Two endpoints and one webhook URL. Teams typically have a signed sandbox invoice on day one.
POST one JSON invoice. Idempotent on your own invoice number — bad network, double-click, retry storm: it signs once.
Queued, retried and reconciled. A slow KRA never blocks your till.
Signature, internal data, CU invoice number and QR payload, delivered by signed webhook or poll — everything the receipt must carry.
Your customer scans the QR on the receipt and checks the invoice against KRA. Every invoice, device and webhook delivery stays visible in the operator console.
Where each field ends up
Printed as issued — an inspector reads them off the paper.
cu_invoice_number
The control unit invoice number.
signature
The receipt signature, printed exactly as returned.
internal_data
The internal data block that goes with it.
qr_payload
Encoded as the QR. It resolves to verification_url on KRA.
Records the sale and queues it for signing. 202 the first time, 200 on any replay of the same client_reference.
Status poll for systems that would rather not receive webhooks. The fiscal block appears once the invoice is signed.
The two webhook events. Both carry the full invoice, so a signed webhook alone is enough to print the receipt.
Bearer token per tenant · 120 requests per minute · sandbox and production on the same shapes
invoice
client_reference
required
Your own invoice number, and the key we deduplicate on.
type
sale, or credit_note to refund one. Defaults to sale.
original_client_reference
The sale a credit note refunds. Required with one.
device_serial
Which registered device signs it. Only needed once you have more than one.
payment_type_code
KRA's payment type, 01 to 07. Defaults to 01.
customer
customer.pin · name · phone
The buyer. The PIN is what lets them claim the input VAT back.
lines[]
description
required
What was sold.
unit_price
required
VAT-inclusive — the price on the shelf.
quantity
Defaults to 1.
tax_category
A to E. Defaults to B, the 16% standard rate.
discount_amount
Taken off the line before the tax is split out.
item_code
Your own item code.
item_classification_code
KRA's classification code for the item.
A business rejection is permanent, so we do not retry it. The invoice is marked failed with KRA's own result code and message, and invoice.failed fires immediately.
Transport failures get five attempts, backing off 10s, 30s, 1m, 2m, 5m. Your till never waits on it.
Webhooks get six attempts, backing off 30s, 2m, 10m, 30m, 1h. Every attempt is logged with its response code, and the poll endpoint always holds the same answer.
The second POST returns 200 with the first invoice. One client_reference, one signature, one entry in the KRA sequence.
Every delivery is signed with HMAC-SHA256 over the timestamp and the raw body, using the secret issued when you register your URL. Compare in constant time, and reject anything whose timestamp is too old to be yours.
X-Etims-Event
X-Etims-Timestamp
X-Etims-Signature
Send a sale twice, it signs once. Your reference is the key.
Categories A (exempt), B (16%), C (zero-rated), D (non-VAT), E (8%) computed from VAT-inclusive prices; five VAT classes never enter your codebase.
Refunds reference the original signed sale, carry negative amounts, and follow KRA's cancel-once rules automatically.
HMAC-SHA256 over a timestamped body; retried from 30 seconds to an hour; every delivery logged and replayable.
KRA rejections surface immediately with the exact result code; transport failures retry with backoff; nothing signs twice, nothing vanishes.
OSCU for always-online systems, VSCU for offline-capable tills; serials, keys and invoice sequences handled per branch under your KRA PIN.
Every invoice, device and webhook delivery visible; failures retried in one click.
Signature, internal data, CU invoice number, QR payload and verification URL come back per invoice — everything the printed receipt must carry.
A registered device and a working example against the KRA sandbox, within days of writing to us.
Write to us with what your system does. We reply with a token, a device and a working example against the KRA sandbox.