POST https://api.fire.rest/api/v1/fire/external/printing/orders/8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62/documents/invoice
x-api-key: <your_api_key>
Content-Type: application/json
{
"printer": { "width": 42 },
"copies": 1
}
{
"success": true,
"data": {
"contract": "print.v1",
"jobId": "ba880df8-651b-4971-90d3-be3ae1a49223",
"document": "invoice",
"subject": {
"kind": "order",
"countryCode": "BR",
"orderId": "8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62",
"orderCode": "FUEL-495A3063-0CD"
},
"template": {
"source": "account",
"templateId": "649f10d4-e781-4460-9dc9-a41fd0888b41",
"version": 3,
"contentHash": "9b1c7e0a4d2f8b6c1e5a0d3f7b2c9e4a"
},
"paper": {
"width": 42,
"charset": "utf-8",
"copies": 1,
"lines": [
{ "t": "band", "lines": [{ "text": "Maria", "big": false }, { "text": "46K", "big": true }] },
{ "t": "rule", "ch": "-", "s": "------------------------------------------" },
{ "t": "text", "s": " Dev company " },
{ "t": "text", "s": " CNPJ 50080000000600 " },
{ "t": "blank" },
{ "t": "text", "s": "QTD. DESCRIÇÃO UNITÁRIO TOTAL" },
{ "t": "text", "s": "1 Batata Grande R$211,90 R$211,90" },
{ "t": "rule", "ch": "=", "s": "==========================================" },
{ "t": "text", "s": "TOTAL R$211,90", "bold": true },
{ "t": "code", "content": "https://www.nfce.fazenda.sp.gov.br/qrcode?p=3525...", "symbology": "qr", "key": "qr", "ecLevel": "m" },
{ "t": "cut" }
],
"plainText": "Maria\n46K\n---..."
},
"freshness": {
"fiscal": "authorized",
"isCancelled": false,
"asOf": "2026-09-14T17:17:04.000Z",
"fingerprint": "10d4a90ded6e2f7b8c3a1e5d0f4b9c62"
},
"warnings": []
}
}
{
"success": false,
"error": "FORBIDDEN",
"message": "API key does not have required scope: printing:read. Available: orders:read, orders:write, store:read"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "Order not found with ID 8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62"
}
{
"success": false,
"error": "PRINT_DOCUMENT_NOT_APPLICABLE",
"message": "This order is not cancelled: there is nothing to compensate"
}
Printing
Print an order document
Get a receipt already laid out for a POS printer — invoice, credit note or kitchen ticket. Fire resolves the template, the country’s fiscal rules, the currency and the column widths; your register only draws the lines it receives.
POST
/
api
/
v1
/
fire
/
external
/
printing
/
orders
/
{orderRef}
/
documents
/
{document}
POST https://api.fire.rest/api/v1/fire/external/printing/orders/8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62/documents/invoice
x-api-key: <your_api_key>
Content-Type: application/json
{
"printer": { "width": 42 },
"copies": 1
}
{
"success": true,
"data": {
"contract": "print.v1",
"jobId": "ba880df8-651b-4971-90d3-be3ae1a49223",
"document": "invoice",
"subject": {
"kind": "order",
"countryCode": "BR",
"orderId": "8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62",
"orderCode": "FUEL-495A3063-0CD"
},
"template": {
"source": "account",
"templateId": "649f10d4-e781-4460-9dc9-a41fd0888b41",
"version": 3,
"contentHash": "9b1c7e0a4d2f8b6c1e5a0d3f7b2c9e4a"
},
"paper": {
"width": 42,
"charset": "utf-8",
"copies": 1,
"lines": [
{ "t": "band", "lines": [{ "text": "Maria", "big": false }, { "text": "46K", "big": true }] },
{ "t": "rule", "ch": "-", "s": "------------------------------------------" },
{ "t": "text", "s": " Dev company " },
{ "t": "text", "s": " CNPJ 50080000000600 " },
{ "t": "blank" },
{ "t": "text", "s": "QTD. DESCRIÇÃO UNITÁRIO TOTAL" },
{ "t": "text", "s": "1 Batata Grande R$211,90 R$211,90" },
{ "t": "rule", "ch": "=", "s": "==========================================" },
{ "t": "text", "s": "TOTAL R$211,90", "bold": true },
{ "t": "code", "content": "https://www.nfce.fazenda.sp.gov.br/qrcode?p=3525...", "symbology": "qr", "key": "qr", "ecLevel": "m" },
{ "t": "cut" }
],
"plainText": "Maria\n46K\n---..."
},
"freshness": {
"fiscal": "authorized",
"isCancelled": false,
"asOf": "2026-09-14T17:17:04.000Z",
"fingerprint": "10d4a90ded6e2f7b8c3a1e5d0f4b9c62"
},
"warnings": []
}
}
{
"success": false,
"error": "FORBIDDEN",
"message": "API key does not have required scope: printing:read. Available: orders:read, orders:write, store:read"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "Order not found with ID 8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62"
}
{
"success": false,
"error": "PRINT_DOCUMENT_NOT_APPLICABLE",
"message": "This order is not cancelled: there is nothing to compensate"
}
Returns a receipt that is already laid out: every line comes padded to the paper width, with the labels, the currency format, the dates in the store’s timezone and whatever the country’s tax authority requires, all resolved on Fire’s side.
Your register does not interpret business rules. It receives a list of line types — text, separator, inverted band, code, cut — and draws them. That is deliberate: there are many different registers in the field, and a rule that lives in each of them is a rule that drifts.
The day-end report has its own endpoint, because its subject is a business day and not a sale: see Print the day close.
POST /api/v1/fire/external/printing/orders/{orderRef}/documents/invoice
POST /api/v1/fire/external/printing/orders/{orderRef}/documents/credit_note
POST /api/v1/fire/external/printing/orders/{orderRef}/documents/kitchen
If there is an order, there is paper
The endpoint will not leave a cashier without a receipt for something Fire can resolve on its own:- No template configured? It falls back to the account’s template, and then to Fire’s generic one. You get
template.source: "seed"and aTEMPLATE_FELL_BACK_TO_SEEDwarning, not an error. - Template unreadable? Same fallback, plus
TEMPLATE_UNREADABLE. - Tax authority has not answered yet? The paper prints without the fiscal number, and
freshness.fiscaltells you it is stillpending.
Authentication
string
required
Your Fire API key with the
printing:read scope. The key must be vendor-scoped — system-only keys are rejected with 403.printing:read is separate from orders:read on purpose: a key that injects orders has no reason to pull receipts, and the two need to be revocable independently.printing:read is a new scope. Existing keys do not have it — grant it in the Fire dashboard before your first call, or every request comes back 403 with the list of scopes the key does carry.Path parameters
string
required
The order’s UUID or its order code. The order is looked up within your key’s vendor, so an order from another vendor simply does not exist for you.
string
required
invoice, credit_note or kitchen.day_close is rejected here with PRINT_WRONG_SUBJECT: a day close does not come from a sale.Body
object
required
The paper the register has in front of it.
Show printer
Show printer
number
required
Columns of the paper:
32, 42 or 48. This is what the layout is computed against, so it is not cosmetic — a receipt built for 42 columns printed on 32 will wrap and misalign.number
Width of the label column in label/value rows, between
6 and 24. Omit it and the engine picks one from the content.number
How many identical copies to print,
1 to 5. Default 1. Fire does not repeat the lines — it tells you how many times to send them.number
Reprint with the template version the receipt originally came out with, instead of the one published today.
string
Which template that version belongs to. Send it together with
templateVersion.“Version 3” does not identify a receipt on its own: the store’s template assignment may have changed since it was printed, and version 3 of a different template is a receipt that never existed. Take it from template.templateId in the original response. If you send templateVersion without it, the paper still comes out, with a TEMPLATE_VERSION_AMBIGUOUS warning.POST https://api.fire.rest/api/v1/fire/external/printing/orders/8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62/documents/invoice
x-api-key: <your_api_key>
Content-Type: application/json
{
"printer": { "width": 42 },
"copies": 1
}
Response
string
Always
print.v1. It only changes if something breaks registers already in the field — new line types and new fields are additive and do not move it.string
Identifies this delivery. Nothing is required of you today: it exists because asking for a receipt and printing it are not the same event — a spooled printer answers “done” before any ink is on the paper — and on the day printing has to be confirmed, there is no way to correlate anything without an identifier that came from the origin.
string
invoice, credit_note or kitchen, echoing what you asked for.object
object
Which template produced this paper. Keep it: it is what lets you reprint the same receipt later, and what lets support answer “why did this one come out different”.
object
The receipt itself.
Show paper
Show paper
number
The columns you asked for, echoed.
string
Always
utf-8, accents included — Ação, Teléfono. Stripping them is a decision of the printer profile, never of the document: the same receipt goes to printers with different code pages, and degrading the text at the source would be irreversible. Map to your printer’s code page when you translate to ESC/POS.number
How many times to send the lines.
object[]
The receipt as a list of typed lines — see below.
string
The same receipt as plain text, for your logs and for support. Do not print this one: it has no cut, no drawer and no codes.
object
Whether this paper is final, and whether it changed since you last asked.
Show freshness
Show freshness
string
What the tax authority has said, which is not the same as the order’s status:
authorized— confirmed. The paper is final.pending— no answer yet. The receipt prints without a fiscal number; ask again later.rejected— the authority turned it down. Terminal: do not retry.cancelled— the sale was voided.none— does not apply. A kitchen ticket never goes to the authority.
boolean
Whether the sale is voided.
string | null
When what this paper says became known — the authorization, the cancellation, or the order’s creation.
string
If it changes, the paper changed. Store it next to the receipt. When you ask again, compare: same fingerprint means the customer already has this exact paper, a different one means something moved — the authority answered, the sale was voided, the company published a new template.
string[]
Things worth logging that did not stop the receipt from printing. Ignore any code you do not recognise — the list grows.
| Code | What happened |
|---|---|
TEMPLATE_FELL_BACK_TO_SEED | No template configured; Fire’s generic one was used. |
TEMPLATE_UNREADABLE | The configured template could not be read; the generic one was used. |
TEMPLATE_VERSION_AMBIGUOUS | templateVersion without templateId. |
FISCAL_PENDING | The authority has not answered yet. |
FISCAL_REJECTED | The authority turned the document down. |
The line vocabulary
paper.lines is the whole receipt. Each entry has a t and draws one thing. Ignore a t you do not know — that is what lets Fire add line types without breaking registers already deployed.
{ "t": "text", "s": string, "bold"?: true }
A line of text, already padded to the paper width. Print
s as it is; do not trim, align or re-pad it.{ "t": "rule", "ch": string, "s": string }
A separator.
s is already expanded to the full width — there is nothing to compute. ch is the character it was built from, if you need it.{ "t": "band", "lines": [{ "text": string, "big": boolean }], "plain"?: true }
The block that is read from across the counter — the pickup number. Print it white-on-black (
GS B 1) and double-size the entries with "big": true (GS ! 0x11), unless plain is true, in which case print it without inverting. That flag comes from the template: the styling is the document’s decision, not the register’s.{ "t": "code", "content": string, "symbology": string, "key": string, "ecLevel"?: "l" | "m" | "q" | "h" }
A code to print — the QR of an NFC-e, the access key of an Ecuadorian invoice. Fire sends the content and the symbology, not an image: the size depends on the device, so the printer draws it.
ecLevel is the QR error-correction level the template chose.{ "t": "blank" }
An empty line.
{ "t": "cut", "partial"?: boolean }
Cut the paper (
GS V). It comes from the document, not from your register: where a receipt ends is part of the receipt.{ "t": "drawer" }
Open the cash drawer (
ESC p). Same reasoning.{
"success": true,
"data": {
"contract": "print.v1",
"jobId": "ba880df8-651b-4971-90d3-be3ae1a49223",
"document": "invoice",
"subject": {
"kind": "order",
"countryCode": "BR",
"orderId": "8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62",
"orderCode": "FUEL-495A3063-0CD"
},
"template": {
"source": "account",
"templateId": "649f10d4-e781-4460-9dc9-a41fd0888b41",
"version": 3,
"contentHash": "9b1c7e0a4d2f8b6c1e5a0d3f7b2c9e4a"
},
"paper": {
"width": 42,
"charset": "utf-8",
"copies": 1,
"lines": [
{ "t": "band", "lines": [{ "text": "Maria", "big": false }, { "text": "46K", "big": true }] },
{ "t": "rule", "ch": "-", "s": "------------------------------------------" },
{ "t": "text", "s": " Dev company " },
{ "t": "text", "s": " CNPJ 50080000000600 " },
{ "t": "blank" },
{ "t": "text", "s": "QTD. DESCRIÇÃO UNITÁRIO TOTAL" },
{ "t": "text", "s": "1 Batata Grande R$211,90 R$211,90" },
{ "t": "rule", "ch": "=", "s": "==========================================" },
{ "t": "text", "s": "TOTAL R$211,90", "bold": true },
{ "t": "code", "content": "https://www.nfce.fazenda.sp.gov.br/qrcode?p=3525...", "symbology": "qr", "key": "qr", "ecLevel": "m" },
{ "t": "cut" }
],
"plainText": "Maria\n46K\n---..."
},
"freshness": {
"fiscal": "authorized",
"isCancelled": false,
"asOf": "2026-09-14T17:17:04.000Z",
"fingerprint": "10d4a90ded6e2f7b8c3a1e5d0f4b9c62"
},
"warnings": []
}
}
{
"success": false,
"error": "FORBIDDEN",
"message": "API key does not have required scope: printing:read. Available: orders:read, orders:write, store:read"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "Order not found with ID 8f3b21c4-90ab-4d1e-b7c2-1f5a9e0d4a62"
}
{
"success": false,
"error": "PRINT_DOCUMENT_NOT_APPLICABLE",
"message": "This order is not cancelled: there is nothing to compensate"
}
Errors
| Status | Code | When |
|---|---|---|
400 | VALIDATION_ERROR | Unknown document, or a printer.width that is not 32/42/48. |
401 | UNAUTHORIZED | Missing or invalid API key. |
403 | FORBIDDEN | The key lacks printing:read, or is not vendor-scoped. |
404 | NOT_FOUND | The order does not exist within your vendor. |
409 | PRINT_DOCUMENT_NOT_APPLICABLE | A credit note was asked for on a sale that is not voided. |
409 | PRINT_WRONG_SUBJECT | day_close asked for on this endpoint. |
Notes
Why
POST for something read-only? The request carries the printer’s paper, and the receipt depends on the fiscal state. A GET would be cached by URL somewhere along the way, and a cached receipt is a receipt that may be lying about whether the authority has authorized it. Nothing is persisted by this call.The printer model is not part of the request. Fire needs the width, because the layout is computed in columns. Everything else about the device — code page, whether it can draw a QR natively, whether accents have to be transliterated — is your register’s profile and stays on your side. That is why
charset always comes back utf-8.Reprinting honestly. Store
freshness.fingerprint and template.templateId / template.version alongside each printed receipt. To reprint exactly what the customer got, send both templateId and templateVersion. To find out whether there is something new to print, ask again and compare fingerprints.
