Machine translation, not yet reviewed.
CT-e document and event reconciliation
The documents (/inbound/documentos) and events (/inbound/eventos) endpoints operate independently. The client consumes each one in its own loop of…
How-to Guide — This document guides the integrator in building the reconciliation logic between inbound CT-e documents and events consumed via the REST API.
1. Introduction
The documents (/inbound/documentos) and events (/inbound/eventos) endpoints operate independently. The client consumes each one in its own polling loop, with separate tokens and filters. However, documents and events are related: a cancellation event, for example, only makes sense when associated with the CT-e it cancels.
Reconciliation is the client-side logic that connects these two streams. Since the arrival order is unpredictable — an event may arrive before its corresponding document, and vice versa — the client must handle both scenarios resiliently.
2. Prerequisites
- The client already implements the incremental sync loop for the documents endpoint (see Inbound CT-e Document Listing Flow).
- The client already implements the incremental sync loop for the events endpoint (see Inbound CT-e Event Listing Flow).
- The client has a local database where documents and events are persisted as they are consumed.
3. Model overview
The client maintains two independent polling loops, each with its own nextToken and filters. Both loops write the received records to the local database. Reconciliation happens after each write, using the access key as the link.
┌──────────────────────┐ ┌──────────────────────┐
│ Loop de Documentos │ │ Loop de Eventos │
│ /inbound/documentos │ │ /inbound/eventos │
└────────┬─────────────┘ └────────┬─────────────┘
│ │
▼ ▼
Salva documento Salva evento
na base local na base local
│ │
▼ ▼
Busca eventos pendentes Busca documento
pela chave de acesso pela chave de acesso
│ │
▼ ▼
Encontrou? Encontrou?
├─ Não → fim ├─ Não → fim
└─ Sim → reconcilia └─ Sim → reconcilia
Access key
The access key is the identifier that connects a document to its event(s):
| Source | Field |
|---|---|
Document (/inbound/documentos) | metadata.chCte (also exposed at the item root as chCte) |
Event (/inbound/eventos) | metadata.chCTe |
Both fields have exactly the same value and format (44 characters, no prefix) — unlike NFS-e, where the document id carries a prefix ("NFS...") that does not literally match the event's infEvento.id (there, the correct correlation is the document id vs the event's infPedReg.chNFSe, both without prefix).
Multiplicity per company: both the document and the events of the same CT-e may appear more than once — one row per
(companyId, chCte)— when several companies of the tenant are parties to the shipment (service taker, recipient, etc.). Reconcile by(companyId, chCte), not just bychCte, to avoid matching one company's event with another company's document.
The client should index its local database by (companyId, chCte) to allow efficient lookups during reconciliation.
4. When receiving a document
When the documents loop returns a new item:
- Save the document to the local database, regardless of whether associated events already exist.
- Search the local database for all events whose
(companyId, chCTe)matches the(companyId, chCte)of the newly saved document. - If no event is found, end processing of this item. The events may not have arrived yet — they will be reconciled when the events loop consumes them.
- If one or more events are found, associate each event with the document and perform the action corresponding to the event type (
tpEvento). For example, if a cancellation event is found, mark the document as cancelled in the local database.
5. When receiving an event
When the events loop returns a new item:
- Save the event to the local database, regardless of whether the associated document already exists.
- Search the local database for the document whose
(companyId, chCte)matches the(companyId, chCTe)of the newly saved event. - If the document is not found, end processing of this item. The document may not have arrived yet — it will be reconciled when the documents loop consumes it.
- If the document is found, associate the event with the document and perform the action corresponding to the event type. For example, if it is a cancellation event, mark the document as cancelled in the local database.
6. Considerations
Unpredictable arrival order
There is no guarantee that the document will arrive before its events, nor the opposite. The client must handle both scenarios with the same logic: save first, reconcile afterwards.
Idempotency
The reconciliation logic must be idempotent. If the same document-event pair is reconciled more than once (for example, after a client restart), the final result must be the same. This means that marking a document as cancelled twice must not cause unwanted side effects.
Multiple events per document
A CT-e may accumulate several events over time (e.g., a correction letter followed by a cancellation, or a proof of delivery followed by its own cancellation). Use nSeqEvento and tpEvento to order and deduplicate events of the same type, instead of assuming the document receives only one event.
Events without a document
An event may remain without an associated document for an extended period — for example, if the document has not yet been processed by the API or if the client started consuming events with a createdFrom earlier than that used for documents. The client should treat unreconciled events as a normal state, not as an error.
Documents without events
Not every document will have associated events. A CT-e that was never cancelled, corrected or subject to any subsequent action simply will not have events. The absence of events for a document is the default scenario.
CT-e JSON — field reference
Endpoint: GET /api/integration/dfe/cte/inbound/documentos · OpenAPI reference: CT-e Public API.
Incremental sync mechanics
The inbound endpoints return records ordered by creation date (createdAt), using keyset pagination: with each response the API returns a nextToken that…