Cover meaning as well as structure
Document the grain, identifier rules, units, time semantics, source authority, and allowed null values. A numeric amount without a currency and rounding convention is not a complete interface. Distinguish an absent field from an explicit null and from a value that was redacted by policy.
Assign a producer owner and identify important consumers. Specify how breaking changes are proposed, how compatibility is checked, and who responds when the contract is violated. A schema registry can store versions, but it cannot resolve a disagreement about whether invoice status means a source state or a derived assessment.

Validate structure at the boundary
JSON Schema can express types, required fields, allowed values, and numeric constraints. The invoice schema requires an identifier, currency and an amount in integer minor units. Additional properties are permitted, allowing compatible consumers to accept new optional fields.
Choose the schema dialect explicitly and configure the validator consistently. In JSON Schema 2020-12, format handling depends on the vocabulary and implementation configuration; a date format annotation should not be assumed to enforce every business time rule. Structural validation must be complemented by semantic checks and authorization.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "currency", "amountMinor"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"amountMinor": { "type": "integer", "minimum": 0 }
}
}Agree on delivery and invalid records
Specify whether messages can repeat, arrive late, or be delivered out of order. Define event identity, the applicable retention window, and how consumers request replay. A payload can be perfectly valid while still being unusable because it arrives after the decision window or refers to an unknown entity.
Choose a quarantine policy for invalid records. Store enough diagnostic context to repair the problem without copying sensitive payloads into unrestricted logs. Acknowledge only according to the agreed durability boundary, and make rejected records visible to an accountable owner. Silent dropping hides data loss behind an apparently healthy pipeline.
Test compatibility with consumers
Keep representative fixtures for each published contract version, including optional fields, nulls, boundary values, and unknown enumeration values. Run producer validation and consumer compatibility checks during change review. An added field can break consumers that reject unknown properties, and a new enum value can break consumers that exhaustively match existing values.
Include a deprecation window and migration evidence rather than relying on a version number alone. For semantic changes, reconcile old and new outputs on the same input set. The contract should let a team explain what changed, which consumers are affected, and how a rollback or correction would be performed.