Skip to main content
Fire does not issue receipts: it numbers them. That distinction explains almost every design decision, so it is worth starting there.

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.
If you already consume order events, you do not have to query anything: the fiscal data arrives through the same path as the rest of the sale. Direct querying is for support and for when you lose the synchronous response.

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:
Carrying the block means numbering was attempted, not that it succeeded. A charged sale left with no fiscal receipt arrives with 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 number that gets printed is documentNumber. Do not compose it yourself.It arrives already composed by the provider, who knows their country’s rule — in Ecuador, article 18 of the Reglamento de Comprobantes de Venta: fifteen digits in three segments. The country block carries the same value under the name the authority uses (numeroComprobante in Ecuador).Assembling it by hand from establecimiento, puntoEmision and secuencial looks equivalent and is not: the Reglamento allows omitting the sequential’s leading zeros, so 001-020-123 can be just as legal as 001-020-000000123. Compose it yourself and you print a number in your convention, not the one the document was issued with.
The three provider fields are not the same thing, which is why they travel apart:
  • providerCode is our adapter identifier (hio). It says which integration numbered.
  • providerIdentity belongs to the provider and has a shape: name, version and reference. That reference is the one you quote back to them when a case needs escalating — it is not your Idempotency-Key.
  • providerMetadata is 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.
Do not branch on providerMetadata keys. Programming against them ties your integration to whichever provider numbers today, and they change without versioning the contract. If a piece of data matters enough to decide with, it will be in the canonical layer or in countryData.
The block also carries the order’s current document, not the first one: if a cancellation happened, the credit note is on top, 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 response carries two states, and they are never merged:
  • requestStatus — did I get numbers to print?
  • documentStatus — did the authority approve it?
At numbering time the second one is always PENDING. That is not a problem: in most countries the receipt is handed over before the authority sees it. If your integration collapses both into one field, at some point you will tell a customer their invoice is authorized when it only has a number.
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.
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 with operation: "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 your reconciliation assumes documentNumber is always the sale’s, it breaks here. The number on top becomes the credit note’s. What the customer walked away with is not lost —it is in history— but you have to go there for it.

If you lose the response

It happens: the network drops right after Fire numbered. The receipt exists and you do not have it.
Returns 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.