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.
1. Validate against the schemas
Section titled “1. Validate against the schemas”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 asapplication/schema+json. - Offline bundle — download
dcp-schemas-v1-bundle.tar.gzand verify it againstSHA256SUMS. 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.
2. Add the check schema alone cannot do
Section titled “2. Add the check schema alone cannot do”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:
- validates the value against
dcp-message.schema.json(2020-12); and - enforces the §4.1 cross-field rule; and
- accepts every
acceptcase and rejects everyrejectcase 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.
4. Try the Node reference validator
Section titled “4. Try the Node reference validator”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.
node reference/validate.mjs examples/v1/decision.recorded.jsonA 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.
5. Prefer bundled schemas in production
Section titled “5. Prefer bundled schemas in production”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.
Next steps
Section titled “Next steps”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.