Developer integration guide
For accounting and point-of-sale vendors: how to send invoices to the platform.
1. Registration
The taxpayer registers the system under “My connected systems” and receives a Client ID and a secret shown once. A system can only issue invoices for its own TIN.
2. Request signing
| Header | Value |
|---|---|
| X-Client-Id | Client ID |
| X-Timestamp | Unix seconds (UTC), ±5 min |
| X-Nonce | 16–64 random characters, never reused |
| X-Signature | Base64(HMAC-SHA256(secret, stringToSign)) |
stringToSign = METHOD \n PATH \n QUERY \n TIMESTAMP \n NONCE \n CLIENT_ID \n hex(SHA256(body))
3. Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/invoices | Submit one invoice (201 created, 200 identical resubmission) |
| POST | /api/v1/invoices/batch | Submit up to 100 invoices, per-item results |
| GET | /api/v1/invoices/{uuid} | Read an invoice you sold or bought |
| POST | /api/v1/invoices/{uuid}/cancel | Cancel within 72 h, then credit note |
| GET | /api/v1/taxpayers/{tin} | Check a buyer TIN before issuing |
| GET | /api/v1/catalog/items?q= | Look up standard item codes (GTIN or ETIS internal code) |
{
"invoiceType": "Standard",
"sellerTin": "100200300",
"buyerTin": "100200302",
"sellerInvoiceNumber": "RAF-1001",
"issueDate": "2026-10-01T09:30:00+03:00",
"currency": "IQD",
"totalAmount": 4750000,
"lines": [
{ "description": "Steel rebar 16mm", "itemCode": "IQ-STEEL-REBAR", "quantity": 5, "unitPrice": 850000, "lineTotal": 4250000 },
{ "description": "Transport", "quantity": 1, "unitPrice": 500000, "lineTotal": 500000 }
]
}
Print verificationUrl from the response on the invoice as a QR code.
4. Standard item codes
Put the item's barcode (GTIN) in each line's itemCode when it has one, otherwise the ETIS internal code from the catalogue (/api/v1/catalog/items). Reference prices are built from these codes. The customs HS code is optional and for classification only.
5. Connecting cash registers (POS)
The till works offline: it signs every receipt with its own key and prints a QR code that verifies immediately, then sends the receipts when connected, within 72 hours.
- The device generates an ECDSA P-256 key pair; the private key never leaves the device.
- The device is registered in the taxpayer portal to get an activation code, then calls /api/v1/pos/activate to obtain a signed certificate.
- For each receipt: a gapless sequence number, a link to the previous receipt, a signature, and a QR containing the certificate.
- Receipts are reported via /api/v1/pos/receipts (device signature or the taxpayer's system), and numbers listed by /api/v1/pos/devices/me are resent.
6. POS receipt format
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/v1/pos/activate | — | Activation code + device public key → platform-signed device certificate |
| POST | /api/v1/pos/receipts | Device or HMAC | Report up to 500 signed receipts, any order, within 72 h |
| GET | /api/v1/pos/devices/me | Device | Status and receipt numbers the platform is missing |
payload = ETR1|device|tin|seq|issuedAtUnix|currency|total|tax|prev prev = first 16 hex of SHA-256(previous payload) (0000000000000000 for seq 1) certificate = ETDC1|device|tin|publicKey|expiresUnix|platformKeyId|P|S token = b64url(payload).b64url(deviceSig).b64url(certificate).b64url(platformSig) QR = https://etis.haidar.website/r?t=token signatures = ECDSA P-256 / SHA-256, IEEE P1363 (r||s, 64 bytes) Device request headers: X-Device-Code, X-Timestamp, X-Nonce, X-Signature = Base64(ECDSA(deviceKey, stringToSign)) (same stringToSign as HMAC, device code as client id)
Ready samples in C#, Python and JavaScript with test vectors are in the repository under sdk/pos; the full specification is docs/POS.md.