Skip to content

How to Validate DCP Messages

Validating a DCP message means two things together: checking it against the JSON Schema for its shape, and checking a rule schema cannot express — that message_type agrees with the body. Skip the second check and a validator will silently accept malformed messages. This guide covers both, plus how to self-certify a validator using the conformance corpus.

By InterIP Networks · Last updated 2026-07-01.

DCP ships 14 JSON Schemas (2020-12), as of 2026-07-03, covering the envelope, the event, and each of the eight entities. Validate any candidate message against dcp-message.schema.json (which in turn references event.schema.json for the body). You have two sources for the schema files:

  • Local — clone the repository and point your validator at schemas/v1/.
  • Published — fetch them from https://schemas.devcopro.org/v1/, served as application/schema+json.
  • Offline bundle — download dcp-schemas-v1-bundle.tar.gz and verify it against SHA256SUMS. The spec recommends bundled/cached schemas over live fetches, and the checksums make the bundle verifiable without trusting the transport.

Any validator that speaks JSON Schema 2020-12 works — AJV (Node), jsonschema (Python), or an equivalent in your language. There is nothing DCP-specific about this step; it is ordinary schema validation. See the envelope reference for the full field table if you need to know what each property means before you validate.

JSON Schema can constrain message_type to the pattern <entity>.<verb>, but it cannot compare two sibling fields for equality — so it cannot on its own catch a message where message_type says one thing and body.entity_type/body.verb say another. Per SPEC §4.1, a validator MUST perform this cross-field check separately, and on conflict the body wins: the message is malformed.

function checkMessageTypeConsistency(message) {
const expected = `${message.body.entity_type}.${message.body.verb}`;
if (message.message_type !== expected) {
throw new Error(`message_type "${message.message_type}" must equal "${expected}"`);
}
}

This is not an edge case to skip — it is one of the two conditions that make a validator conformant at all (§11). Without it, a message claiming message_type: "task.completed" while its body says entity_type: "decision" would pass schema validation and reach downstream code as a lie.

3. Self-certify with the conformance corpus

Section titled “3. Self-certify with the conformance corpus”

The conformance/ directory holds a language-neutral corpus of 25 cases — 7 accept, 18 reject — as of 2026-07-03. Each case is a JSON message plus an expected outcome in conformance/manifest.json: which schema to validate against, whether a conformant validator must accept or reject it, and why. The accept cases exercise forward compatibility (unknown verbs, unknown status values, namespaced extensions, refs-only or delta-only events); the reject cases exercise the single-responsibility guards (a forbidden rel like approved_by, a message_type mismatch, an empty event payload, a non-namespaced extension key, and more).

Per SPEC §11, an implementation is conformant if it:

  1. validates the value against dcp-message.schema.json (2020-12); and
  2. enforces the §4.1 cross-field rule; and
  3. accepts every accept case and rejects every reject case in the manifest.

Run your own validator — in any language — against this corpus instead of trusting a schema-only implementation. The corpus, not any single library, is the practical definition of conformance.

The repository includes reference/validate.mjs, a small AJV-based validator that does exactly the two things above: schema validation plus the cross-field check. Treat it as one reference implementation, not the definition of conformance — your own validator, in whatever language, is what you should certify.

Terminal window
node reference/validate.mjs examples/v1/decision.recorded.json

A pass prints PASS <file>; a failure prints FAIL <file> followed by each schema error and, if applicable, the cross-field mismatch. Browse the worked example messages if you want more fixtures to run it against.

Every schema $ref in DCP resolves against the absolute host https://schemas.devcopro.org/v1/, and that namespace is stable for the lifetime of the v1 major version (see versioning and compatibility). Even so, SPEC §10.1 recommends consumers prefer bundled or cached schemas over live-fetching that host at validation time. Live-fetching on every request adds an external dependency and a latency/availability risk your CI or runtime shouldn’t carry; vendor the schema files (or cache them with a reasonable TTL) and treat the published URLs as identifiers, not a required network call.

If validation fails, work through the error catalog to identify which failure mode you hit and why. This guide intentionally goes deeper than the quickstart — if you just want a first message passing in five minutes, start there instead.