An event schema contract is the artifact that turns "send us the conversions" into a list of fields, each with a canonical name, a requiredness state, a written meaning, a named owner and a proof level. Agree those questions before development, and record later changes in the same contract. Two cheaper questions come first in this sequence: whether the path can be measured at all, and which system owns which segment of it. A schema agreement is the third one, and it is the only one that a developer can implement literally.
One boundary matters just as much as the content. This document is not a destination's parameter dictionary. Each platform publishes its own field reference, and the cross-network table of those parameters already lives in Cross-Platform Conversion Parameters Matrix. What is agreed here is the interface between your source system and your integrator, written down before either side has an excuse.
What an Event Schema Contract Fixes Before Development
The most expensive dispute in a custom conversion project is the simple one: whether a field is
mandatory. A contract ends that dispute by refusing the binary and recording a state instead. It
also fixes what the field means, because two systems can hold a column called order_id and use it
for a basket, an invoice and a renewal in the same week.
Organize the client agreement around four tasks: field normalization, destination mapping, duplicate handling and delivery checks. For each field, record its source name, canonical name and any destination-specific condition.
For duplicate handling, agree the identifier and its owner for each destination. The event id deduplication mechanism is illustrated in Facebook Pixel and CAPI Event Deduplication; Event Delivery Retries covers repeated delivery. Keep request, response and destination records separate, as explained in Telegram Conversion Proof Levels.
The templates below are proposed client–integrator agreements. They are not a product API schema.
Requiredness Has Four States, Not One Column
| State | How a destination documents it | What the contract records | Answer owed by the data owner |
|---|---|---|---|
| Always required | Meta marks event_name, event_time, user_data and action_source as Required on the server event parameter page | The field is present in every event, with no exception path | Which of your systems can fail to produce it |
| Required in one usage | event_source_url is Optional, yet the same page notes it is required for website events; Google requires user_identifiers for enhanced conversions for leads and cart_data for basket data | The state cell names the usage that triggers the requirement | Which usages this path actually serves |
| Optional but binding once set | Google's order_id: "This field is optional, but strongly recommended… If you set it during the import, you must use it for any adjustments." | A one-way switch: the row states who may start filling it and who cannot stop | Do you already send this value somewhere |
| Recommended with a downstream effect | Google's consent: "If not set, it's possible that your conversions won't be attributable." | The consequence is written beside the field, not in a footnote | Who accepts that risk in writing |
The third state is the one that surprises people, so quote it from the source rather than trusting a summary:
This field is optional, but strongly recommended, because it makes it simpler to reference imported conversions when making adjustments. If you set it during the import, you must use it for any adjustments.
Two Meta-specific examples show why a boolean required/optional column may be insufficient. Meta's customer information parameters require at least one of the listed user_data fields in the correct format. That is a condition on a set of identifiers used as a match key, not a rule that every destination shares. Separately, Meta's Using the API guide gives a general event_time limit of seven days: an older timestamp causes an error for the entire request, with no events processed. The same guide separately says to upload offline and physical-store transactions with action_source: physical_store within 62 days of conversion. Keep that qualification with the applicable event source. In the guide's other documented invalid-event case, the request returns an error but valid events with event_id are still accepted. Record the applicable time and batch rules for each destination; a response alone does not establish attribution.
Nine Columns Every Field Row Carries
Every field row in an event schema contract carries the same nine cells, in the same order, so two reviewers can compare rows without renegotiating the format first.
- Canonical name plus source name, so a renamed CRM field is a change to one column and not to a whole mapping. Event naming itself is treated in Standard Events Mapping: One Conversion, Six Names Across Ad Platforms.
- Type and format, including the timezone rule. Google's
conversion_date_timerequires an explicit offset in the patternyyyy-mm-dd HH:mm:ss+|-HH:mm, while Meta'sevent_timeis a Unix timestamp in seconds that must be sent in GMT. - Requiredness state with its condition, taken from the table above.
- Business meaning in the source system's own words: which object, which state change, and at what moment the event fires.
- Source of truth. One field, one system that may set it; every other system may read it.
- Behavior when the value is absent, because empty string, zero and a missing key are three different payloads and receivers do not treat them alike.
- Transformation and its location, such as the hashing and normalization rules covered in Meta CAPI Hashing: Normalize User Data Before It Costs You Matches.
- Proof level the field contributes to, plus the artifact that shows it.
- Owner and version, so a rename, a new enum value or a dropped column is a signed edit with a date.
# Author's template row, not a Most API format.
field: order_id
source_names: ["crm.deal.external_key", "billing.invoice.number"]
type_format: "string, exactly as the source system stores it (leading zeros and case preserved)"
requiredness: "optional until first sent, then binding for adjustments"
meaning: "identifier of the paid invoice, not of the deal object"
source_of_truth: "billing system; CRM may copy it, never invent it"
when_absent: "omit the key; do not send an empty string"
transformation: "none; never hashed"
proof_level: "accepted: response body of that request; recorded: that destination's conversions report for the named action and window"
owner_version: "v3, agreed 2026-09-10, owner: finance ops"The format cell names no character limit on purpose. Google's own page for order_id documents the
status quoted in the table above and one further constraint, in its troubleshooting table: the
DUPLICATE_ORDER_ID error, "Imported events include multiple conversions with the same Order ID and
were not processed. Make sure Order IDs are unique and try again." That is a rule about repetition,
not about length. Where a receiver does impose a length or character rule, the cell names the limit
and cites that receiver's page; where no published page states one, the cell records the form the
source system stores, and inventing a range there is a defect in the contract rather than in the data.
Questions the Client Must Answer in Writing
An event schema contract review is a list of questions, and each one has to come back as text rather than as a verbal reassurance.
- Which object and which state change count as the event, in your CRM's own vocabulary?
- Is the value present at the moment the trigger fires, or only after a manager edits the record?
- When the same transaction identifier appears twice, is that a retry, a refund or a renewal?
- Does your timestamp mean the click, the submission or the closed deal? Timezone consequences are measurable and documented in Event Time, Time Zones, and Acceptance Windows.
- If two systems both fill one field, which one wins, and who notices when that flips?
- Which destinations does this event actually go to, since requiredness is per destination?
- Who signs a new column, and what happens to historical events when a meaning changes?
The handover of raw materials for an audit is a separate artifact, and this list is not it: those answers feed a working agreement rather than an evidence pack. A minimal document header keeps the agreement versioned instead of implied.
event schema contract
scope = <one event name and its source object>
destinations = <named ad platforms for this path>
version = 3 effective 2026-09-10
field rows = <one row per field, nine cells each>
change rule = <who signs a rename, a new enum value, a dropped column>
out of scope = <attribution, bidding, reporting outcomes>Contract Defects: Symptom, Evidence, Next Test
| Contract symptom | Evidence to ask for | Next test |
|---|---|---|
| One name, two meanings | Five recent samples from each system that fill the column | Check whether one value maps to two different objects |
| A field called required arrives empty | Dispatch log for one day plus the receiver's response for those calls | Replay one logged event with that field left empty through the receiver's own test channel and record the answer: accepted empty means the contract lost its condition cell, rejected means the source breaks a documented rule |
| Amounts arrive without a currency | The outbound request body carrying the amount with no currency code, plus the receiver's error response to that call | Test one event with the currency cell left blank |
| Timestamps differ by a fixed offset | Source timezone convention and the contract's format cell | Test a conversion written with an explicit UTC offset |
| Two teams invented two dedup keys | Both keys as stored before the call, plus one accepted batch | Compare counts per key rather than per day |
| A renamed CRM field broke the mapping silently | The mapping row and the change log entry | Propose one rename in a staging mapping and record whether any change-control step halts the dispatch before events flow; an unchallenged rename is the owner-and-version cell missing |
| Batch accepted, platform shows nothing | Receiver response and the diagnostics report for that window | Separate an acceptance record from a recorded conversion |
Work the rows in order and stop at the first artifact nobody can produce. That gap is the finding, and a hole in the event schema contract is a paperwork defect long before it becomes an engineering one.
What a Signed Schema Does Not Decide
A perfect event schema contract cannot make a platform attribute anything. It defines what you send, what the receiver answers and which record proves each level; matching to a click, counting rules and attribution remain the destination's decisions, and the same holds for bidding. Google states the import side of that limit plainly: conversions uploaded more than 90 days after the associated last click are not imported at all, and the enhanced-conversions-for-leads variant carries its own 63-day window (Guidelines for importing offline conversions). A field agreement that promises an outcome inside an auction is a document to refuse.
Agree implementation scope and delivery obligations separately from the field list. A schema contract does not set a project's schedule or service level.
Need to clarify a field?
Share a sanitized field list and the requirement you need to agree. The first consultation is free.
Do not send tokens or passwords.
Sources
Sources
Way2 services
