Who does what
Your channel
Charges, requests the numbering, prints and injects the order. It knows no country’s
fiscal rules.
Fire
Resolves the store, the issuer and the provider. Stores the request, asks for the
numbers, and tells you what can be printed.
The fiscal provider
Translates to the authority’s codes, numbers with its country vocabulary, and submits
the document.
The tax authority
Approves or rejects. Its verdict arrives after the customer has left with the
receipt.
One contract, every country. Fire resolves internally which provider matches each
country. Your integration is the same in Ecuador, Brazil or Venezuela: what changes is
which fields come filled in the response, not how you ask for it.
The timeline
Steps 1 to 5 happen with the customer waiting at the register: seconds. From 6 onwards your channel is no longer involved.Where the fiscal data shows up
The numbering does not stay locked inside this endpoint. It travels through the order lifecycle at two distinct moments, and they should not be conflated.1. What we compensate at injection
When you inject the order, Fire enriches it with the numbering you already obtained. That data travels in the normal lifecycle events:
At this point there is still no verdict from the authority: there are printed numbers and
a registered sale.
2. What the fiscal callback compensates
Minutes later, the provider tells Fire what the authority decided. That callback is what triggers the two outcome events:That is the separation to keep clear end to end: you request the numbering and it
compensates the order; the authorization arrives on its own and compensates the outcome.
A numbered document may never reach
order.invoiced if the authority rejects it.The field to read: data.fiscalRepresentation
The numbering arrives in that block, on every order event — all five in the two tables
above.
The key always travels. It arrives as null when numbering was not attempted —
aggregators, countries without fiscal representation, or merchants with numbering turned off
— and carries the block when it was. Branch on the value, never on the key’s presence:
null identifiers and the reason in failure —
handle that case, because it used to be invisible.
And carrying the block does not mean the document is authorized either: that is what
lastKnown.fiscal.status says, and it is the only one of the two that gets updated.
What the block carries
Three layers, and it pays not to mix them:
The three provider fields are not the same thing, which is why they travel apart:
providerCodeis our adapter identifier (hio). It says which integration numbered.providerIdentitybelongs to the provider and has a shape:name,versionandreference. Thatreferenceis the one you quote back to them when a case needs escalating — it is not yourIdempotency-Key.providerMetadatais an opaque bag: no guaranteed shape, the provider owns the keys and may change them without notice. It is for pasting into a support ticket.
compensates points at the invoice it voids, and the
whole invoice sits in history. Every history entry has exactly the same keys as the
block above, so they read the same.
The full field-by-field reference lives in
order.opened.
The three rules to understand
The sale is never blocked
The sale is never blocked
If the provider does not answer in time, Fire does not return an error: it returns
202 with printing.mode: "PROVISIONAL_RECEIPT". You print a non-fiscal ticket, inject
the order anyway, and Fire completes the numbering on its own.Do not retry in a loop and do not hold the sale. The money is already charged; the
receipt gets resolved afterwards.Fire decides what gets printed, not you
Fire decides what gets printed, not you
The
printing block is not a deduction from whether there is a document: it is a
legal rule of the country. In Ecuador under contingency the receipt exists and is
printed even though the authority has not seen it yet; in a country that forbids printing
before approval, printable would come as false with the document present.If each channel derived that rule on its own, one of them would get it wrong — and that
mistake only surfaces in an audit.Idempotency: three layers
A sale charged twice is a money problem; a sale numbered twice is a fiscal problem, and it cannot be fixed with a deploy. Hence three barriers:1
Your Idempotency-Key
You generate it, one per sale, and reuse it on every retry of that same sale. It is what
keeps a network failure from consuming a second sequential.If you reuse it with a different body, Fire answers
409: those are two different
operations.2
The natural key
country + orderCode + operation. It protects you even if your channel regenerates the
Idempotency-Key on every attempt — the most common implementation mistake.It is also why the orderCode must be unique per account and country: if two stores
use the same one, Fire stops before issuing.3
The provider's
The same triple, on the other side. Both keys being identical is what makes a collision
surface on both ends at once, instead of showing up months later as two receipts for one
sale.
Cancelling
Requested withoperation: "CANCEL" and the original sale’s orderCode. Nothing else.
Your point of sale does not need to store any identifier of ours: Fire finds the original
document through the natural key. That is deliberate — a kiosk that gets reinstalled or a
register that gets replaced would lose that data, and the sale could never be voided. The
orderCode, on the other hand, is printed on the ticket.
Which instrument materializes the cancellation is decided by the country: in Ecuador it is a
credit note with its own sequential; in Brazil, a cancellation event that produces no new
document.
From then on the order carries the credit note on top. The following events bring
documentType: "CREDIT_NOTE" in fiscalRepresentation, with compensates pointing at the
voided invoice and the whole invoice in history.
If you lose the response
It happens: the network drops right after Fire numbered. The receipt exists and you do not have it.items[] with every document of that order — possibly two, the invoice and its
cancellation. This is why the orderCode must be the same string in the numbering and in the
injection: it is the only thing left in your hand.
Before going to production
Your
orderCode is unique per account and country, and identical in numbering and injection.You store the
Idempotency-Key with the order and reuse it on retries.Each device declares its own
device.externalId — two registers in a store do not share one.You branch on
printing.mode, not on the HTTP status code.You print
documentNumber exactly as it arrives, without recomposing it from establecimiento, puntoEmision and secuencial.You iterate
countryData instead of indexing fixed keys: the numbering country sets them, and in Venezuela there is no claveAcceso.You iterate over the keys of
graphic instead of looking for fixed fields.You do not branch on
providerMetadata keys: it is the provider’s opaque bag and it changes without notice.Your reconciliation accounts for the credit note being the top document after a cancellation, with the invoice in
history.On
202 you print provisional and inject anyway, without retrying in a loop.Endpoint reference
Fields, responses and per-country examples.

