{"components":{"parameters":{"Country":{"description":"ISO country code. `ls` (Lesotho) is available; others answer 501 until launched.","in":"path","name":"country","required":true,"schema":{"example":"ls","type":"string"}},"Terminal":{"in":"path","name":"terminal_id","required":true,"schema":{"format":"uuid","type":"string"}}},"responses":{"Error":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Error"}},"schemas":{"Buyer":{"additionalProperties":false,"description":"Omit for a walk-in sale. With a TIN (and name) the document is a tax invoice.","properties":{"address":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string"},"tin":{"type":"string"}},"type":"object"},"Country":{"properties":{"authority":{"type":"string"},"code":{"type":"string"},"currency":{"type":"string"},"name":{"type":"string"},"status":{"enum":["available","planned"],"type":"string"},"system":{"type":"string"}},"type":"object"},"Document":{"properties":{"country":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"currency":{"type":"string"},"error":{"type":["string","null"]},"fiscal":{"properties":{"device_id":{"type":"string"},"fiscal_day_no":{"type":"integer"},"invoice_no":{"description":"The invoice number exactly as filed (the device id is inserted so numbers stay unique across your devices)","type":"string"},"qr_url":{"description":"Print as a QR code","type":["string","null"]},"receipt_counter":{"type":"integer"},"receipt_date":{"type":"string"},"receipt_global_no":{"type":"integer"},"receipt_type":{"description":"FiscalInvoice when the buyer has a TIN; Receipt otherwise","enum":["FiscalInvoice","Receipt","CreditNote","DebitNote"],"type":"string"},"rsl_receipt_id":{"type":["string","null"]},"validation_errors":{"items":{"type":"string"},"type":"array"},"verification_code":{"description":"Print it; customers type it at the authority's portal","type":["string","null"]}},"type":"object"},"id":{"format":"uuid","type":"string"},"invoice_number":{"type":"string"},"metadata":{"type":["object","null"]},"mode":{"enum":["live","test"],"type":"string"},"object":{"enum":["fiscal_document"],"type":"string"},"original_invoice_number":{"type":["string","null"]},"preview":{"description":"Test mode only: the exact receipt that would have been filed","type":"object"},"source":{"enum":["api","portal"],"type":"string"},"status":{"description":"validated: test mode, would have been filed. queued: signed and numbered, awaiting the authority. fiscalized: accepted. flagged: accepted with validation errors. failed: refused after retries.","enum":["validated","queued","fiscalized","flagged","failed"],"type":"string"},"tax_total":{"type":"number"},"taxes":{"items":{"properties":{"amount_with_tax":{"type":"number"},"name":{"type":"string"},"rate":{"type":["number","null"]},"tax_amount":{"type":"number"},"tax_id":{"type":"integer"}},"type":"object"},"type":"array"},"terminal_id":{"format":"uuid","type":"string"},"test":{"type":"boolean"},"total":{"type":"number"},"type":{"enum":["sale","credit_note","debit_note"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"DocumentRequest":{"additionalProperties":false,"properties":{"buyer":{"$ref":"#/components/schemas/Buyer"},"currency":{"default":"LSL","enum":["LSL"],"type":"string"},"expected_total":{"description":"If given, the document is refused (total_mismatch) unless the lines total exactly this","type":"number"},"invoice_number":{"description":"Your document number. Unique across your account; the idempotency key.","maxLength":50,"type":"string"},"issued_at":{"description":"Informational; the fiscal date is the moment of filing","format":"date-time","type":"string"},"lines":{"items":{"$ref":"#/components/schemas/Line"},"maxItems":500,"minItems":1,"type":"array"},"metadata":{"additionalProperties":true,"description":"Stored and returned as-is","type":"object"},"original_invoice_number":{"description":"Notes: the sale being corrected","type":"string"},"payments":{"description":"What was paid. Anything unpaid is filed as Credit (owed). Send the amount applied, not tendered.","items":{"$ref":"#/components/schemas/Payment"},"type":"array"},"prices_include_tax":{"default":true,"description":"false: unit prices are converted to tax-inclusive, rounded to the cent","type":"boolean"},"reason":{"description":"Notes: required","maxLength":250,"type":"string"},"settlement":{"$ref":"#/components/schemas/MoneyType","description":"Notes: how the correction was settled. Default Credit (against the account)."},"terminal_id":{"description":"Optional when the key (or account) has a single terminal","format":"uuid","type":"string"},"type":{"default":"sale","enum":["sale","credit_note","debit_note"],"type":"string"}},"required":["invoice_number","lines"],"type":"object"},"Error":{"properties":{"error":{"properties":{"code":{"example":"validation_failed","type":"string"},"details":{"items":{"properties":{"field":{"example":"lines[0].tax_id","type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"document_id":{"description":"On idempotency_conflict: the document already filed","type":"string"},"message":{"type":"string"},"rule":{"description":"The authority's rule the document would break, e.g. RCPT035","type":"string"}},"required":["code","message"],"type":"object"},"request_id":{"type":"string"}},"required":["error"],"type":"object"},"FiscalDay":{"properties":{"closed_at":{"format":"date-time","type":["string","null"]},"closes_by":{"format":"date-time","type":"string"},"error":{"type":["string","null"]},"failed_receipts":{"type":"integer"},"files":{"description":"Offline devices only","items":{"type":"object"},"type":"array"},"fiscal_day_no":{"type":"integer"},"opened_at":{"format":"date-time","type":"string"},"pending_receipts":{"type":"integer"},"receipts":{"type":"integer"},"status":{"enum":["open","closing","closed","close_failed"],"type":"string"}},"type":["object","null"]},"Line":{"additionalProperties":false,"properties":{"description":{"maxLength":200,"type":"string"},"discount":{"description":"Line discount, in money. Must divide evenly by quantity.","minimum":0,"type":"number"},"hs_code":{"pattern":"^[0-9]{4,8}$","type":"string"},"is_service":{"description":"Chooses between the goods and services variants of a rate","type":"boolean"},"original_line":{"description":"Notes: the original's line (1-based); its description and tax are inherited","minimum":1,"type":"integer"},"quantity":{"description":"Up to four decimals","exclusiveMinimum":0,"type":"number"},"sku":{"type":"string"},"tax_category":{"enum":["standard","zero_rated","exempt"],"type":"string"},"tax_code":{"type":"string"},"tax_id":{"description":"Preferred: an id from the terminal's tax-codes","type":"integer"},"tax_rate":{"description":"With or instead of tax_category, e.g. 15","type":"number"},"unit_price":{"exclusiveMinimum":0,"type":"number"}},"required":["quantity","unit_price"],"type":"object"},"MoneyType":{"enum":["Cash","Card","MobileWallet","BankTransfer","Coupon","Credit","Other"],"type":"string"},"Payment":{"additionalProperties":false,"properties":{"amount":{"exclusiveMinimum":0,"type":"number"},"method":{"$ref":"#/components/schemas/MoneyType"},"reference":{"type":"string"}},"required":["method","amount"],"type":"object"},"TaxCode":{"properties":{"category":{"type":"string"},"kind":{"enum":["tax","levy"],"type":"string"},"name":{"type":"string"},"rate":{"type":["number","null"]},"tax_id":{"type":"integer"},"type":{"type":"string"},"valid":{"type":"boolean"}},"type":"object"},"Terminal":{"properties":{"api_terminal":{"type":"boolean"},"auto_day":{"type":"boolean"},"device_id":{"type":["string","null"]},"enrolled":{"type":"boolean"},"fiscal_day":{"$ref":"#/components/schemas/FiscalDay"},"id":{"format":"uuid","type":"string"},"location":{"type":"string"},"name":{"type":"string"},"operating_mode":{"enum":["Online","Offline"],"type":"string"},"taxpayer":{"properties":{"name":{"type":["string","null"]},"tin":{"type":["string","null"]},"vat_number":{"type":["string","null"]}},"type":"object"}},"type":"object"},"Usage":{"properties":{"currency":{"type":"string"},"documents":{"type":"integer"},"hard_limit":{"type":"boolean"},"included":{"type":["integer","null"]},"metered":{"type":"boolean"},"overage":{"type":"integer"},"overage_amount":{"type":"number"},"overage_price":{"type":["number","null"]},"period_end":{"type":"string"},"period_start":{"type":"string"},"test_documents":{"type":"integer"}},"type":"object"},"WebhookEvent":{"description":"POSTed to your endpoint. Events: document.fiscalized, document.flagged, document.failed, document.validated (test mode), fiscal_day.closed, fiscal_day.close_failed, offline_file.processed, ping.","properties":{"created_at":{"type":"string"},"data":{"type":"object"},"id":{"type":"string"},"mode":{"type":"string"},"type":{"type":"string"}},"type":"object"}},"securitySchemes":{"ApiKey":{"in":"header","name":"X-Api-Key","type":"apiKey"},"Bearer":{"scheme":"bearer","type":"http"}}},"info":{"description":"Send an invoice; Marshal validates it against the taxpayer's own tax table, numbers and signs it on your fiscal device, files it with the tax authority and returns the fiscal details (receipt numbers, verification code, QR link).\n\n**Keys.** `mk_test_…` keys are a full sandbox: documents go through the real validation, numbering and signing, then are rolled back — nothing reaches the tax authority and they are never billed. `mk_live_…` keys file for real.\n\n**Idempotency.** Your `invoice_number` is the idempotency key, per terminal and mode. Re-sending the same number with the same content returns the original document (HTTP 200, header `Idempotent-Replay: true`); the same number with different content is refused with 409 `idempotency_conflict`. It is always safe to retry after a timeout.\n\n**Corrections.** An issued invoice can never be changed. Correct it with a `credit_note` or `debit_note` that names it in `original_invoice_number`.\n\n**Errors** always have the shape `{\"error\": {\"code\", \"message\", \"details\"?}, \"request_id\"}`.\n\n**Webhooks** are signed: `Marshal-Signature: t=\u003cunix\u003e,v1=\u003chex HMAC-SHA256(secret, \"\u003ct\u003e.\u003craw body\u003e\")\u003e`.","summary":"Fiscalise invoices with the tax authority from any system.","title":"Marshal Fiscal API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/v1/countries":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Country"},"type":"array"}},"type":"object"}}},"description":"Countries and whether each is available"}},"security":[],"summary":"List countries","tags":["Account"]}},"/v1/me":{"get":{"responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Error"}},"summary":"The key and account you are calling as","tags":["Account"]}},"/v1/usage":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}},"description":"OK"}},"summary":"This month's billable documents and allowance","tags":["Account"]}},"/v1/{country}/invoices":{"get":{"parameters":[{"description":"Comma-separated: validated, queued, fiscalized, flagged, failed","in":"query","name":"status","schema":{"type":"string"}},{"description":"Comma-separated: sale, credit_note, debit_note","in":"query","name":"type","schema":{"type":"string"}},{"in":"query","name":"terminal_id","schema":{"format":"uuid","type":"string"}},{"in":"query","name":"invoice_number","schema":{"type":"string"}},{"description":"Date (2026-09-01) or RFC 3339 time, inclusive","in":"query","name":"from","schema":{"type":"string"}},{"description":"Date or time, exclusive","in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}},{"in":"query","name":"offset","schema":{"default":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Document"},"type":"array"},"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}},"type":"object"}}},"description":"OK"}},"summary":"List documents (of the key's mode)","tags":["Invoices"]},"parameters":[{"$ref":"#/components/parameters/Country"}],"post":{"requestBody":{"content":{"application/json":{"examples":{"b2b":{"summary":"Tax invoice on credit to a registered buyer","value":{"buyer":{"name":"Acme (Pty) Ltd","tin":"200012345-6"},"invoice_number":"INV-1002","lines":[{"description":"Consulting, September","is_service":true,"quantity":1,"tax_category":"standard","unit_price":5750}]}},"credit_note":{"summary":"Credit one unit back","value":{"invoice_number":"CN-0001","lines":[{"original_line":1,"quantity":1,"unit_price":115}],"original_invoice_number":"INV-1001","reason":"Damaged bag returned","settlement":"Cash","type":"credit_note"}},"sale":{"summary":"Cash sale, two lines","value":{"invoice_number":"INV-1001","lines":[{"description":"Maize meal 12.5kg","quantity":2,"tax_id":7,"unit_price":115},{"description":"Delivery","is_service":true,"quantity":1,"tax_id":1,"unit_price":50}],"payments":[{"amount":280,"method":"Cash"}]}}},"schema":{"$ref":"#/components/schemas/DocumentRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}},"description":"Idempotent replay of a document already filed with this number and content","headers":{"Idempotent-Replay":{"schema":{"enum":["true"],"type":"string"}}}},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}},"description":"Filed (live) or validated (test)"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Account suspended, subscription lapsed, or allowance exhausted"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"idempotency_conflict, invoice_number_in_use, fiscal_day_* or terminal_not_ready"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"validation_failed, overpaid, total_mismatch, original_invalid, rejected_by_rulebook (with `rule`, e.g. RCPT035)"},"429":{"$ref":"#/components/responses/Error"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Country not yet available"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"fiscalisation_unavailable — nothing was filed; retry later"}},"summary":"File a sale, credit note or debit note","tags":["Invoices"]}},"/v1/{country}/invoices/stats":{"get":{"responses":{"200":{"description":"OK"}},"summary":"Counts and totals by status and type (same filters as the list)","tags":["Invoices"]},"parameters":[{"$ref":"#/components/parameters/Country"}]},"/v1/{country}/invoices/{id}":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}},"description":"OK"},"404":{"$ref":"#/components/responses/Error"}},"summary":"Get a document","tags":["Invoices"]},"parameters":[{"$ref":"#/components/parameters/Country"},{"description":"The document id, or your invoice_number (add ?terminal_id= if two terminals share a number)","in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/{country}/invoices/{id}/pdf":{"get":{"responses":{"200":{"content":{"application/pdf":{}},"description":"PDF"}},"summary":"Printable fiscal document (80 mm)","tags":["Invoices"]},"parameters":[{"$ref":"#/components/parameters/Country"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/{country}/terminals":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Terminal"},"type":"array"}},"type":"object"}}},"description":"OK"}},"summary":"List terminals","tags":["Terminals"]},"parameters":[{"$ref":"#/components/parameters/Country"}],"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"activation_key":{"type":"string"},"auto_day":{"default":true,"description":"Let the API open fiscal days on the first document and close them before the authority's limit","type":"boolean"},"device_id":{"description":"Issued by the tax authority","type":"string"},"key_type":{"default":"ecc","enum":["ecc","rsa"],"type":"string"},"location":{"type":"string"},"name":{"type":"string"},"serial_no":{"type":"string"}},"required":["name","device_id","activation_key","serial_no"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Terminal"}}},"description":"Enrolled"},"502":{"description":"authority_rejected"}},"summary":"Enrol a new fiscal device (live keys only)","tags":["Terminals"]}},"/v1/{country}/terminals/{terminal_id}":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Terminal"}}},"description":"OK"}},"summary":"Get a terminal","tags":["Terminals"]},"parameters":[{"$ref":"#/components/parameters/Country"},{"$ref":"#/components/parameters/Terminal"}]},"/v1/{country}/terminals/{terminal_id}/fiscal-day":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiscalDay"}}},"description":"OK"}},"summary":"The current (or last) fiscal day","tags":["Terminals"]},"parameters":[{"$ref":"#/components/parameters/Country"},{"$ref":"#/components/parameters/Terminal"}]},"/v1/{country}/terminals/{terminal_id}/fiscal-day/close":{"parameters":[{"$ref":"#/components/parameters/Country"},{"$ref":"#/components/parameters/Terminal"}],"post":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiscalDay"}}},"description":"Closed"},"409":{"description":"fiscal_day_close_failed"}},"summary":"Close the fiscal day (Z report). On an Offline device this builds and sends the day file.","tags":["Terminals"]}},"/v1/{country}/terminals/{terminal_id}/fiscal-day/open":{"parameters":[{"$ref":"#/components/parameters/Country"},{"$ref":"#/components/parameters/Terminal"}],"post":{"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiscalDay"}}},"description":"Opened"},"409":{"description":"fiscal_day_open"}},"summary":"Open a fiscal day (live keys; auto-day terminals do this themselves)","tags":["Terminals"]}},"/v1/{country}/terminals/{terminal_id}/fiscal-days/{day_no}/files":{"get":{"responses":{"200":{"description":"OK"}},"summary":"Offline mode: the day files and how the authority processed them","tags":["Terminals"]},"parameters":[{"$ref":"#/components/parameters/Country"},{"$ref":"#/components/parameters/Terminal"},{"in":"path","name":"day_no","required":true,"schema":{"type":"integer"}}]},"/v1/{country}/terminals/{terminal_id}/tax-codes":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/TaxCode"},"type":"array"},"sandbox":{"type":"boolean"}},"type":"object"}}},"description":"OK"}},"summary":"The taxpayer's tax table — the tax_id values a line may use","tags":["Terminals"]},"parameters":[{"$ref":"#/components/parameters/Country"},{"$ref":"#/components/parameters/Terminal"}]}},"security":[{"ApiKey":[]},{"Bearer":[]}],"servers":[{"description":"This environment","url":"https://dev-pos-backoffice.marshal.co.ls"}],"tags":[{"description":"Sales, credit notes and debit notes.","name":"Invoices"},{"description":"Fiscal devices and their fiscal days.","name":"Terminals"},{"description":"Who you are, what you have used.","name":"Account"}]}
