Your first invoice
A working request that creates an invoice, with every required field explained.
The request
curl -X POST https://staging-e-invoice.harmonizedx.com/api/v1/invoices \
-H "X-API-Key: sk_test_a1b2c3d4e5f67890abcdef1234567890" \
-H "Content-Type: application/json" \
-H "idempotency-key: 9f8c1e40-3b7a-4a2f-8c1d-7e2b5a904f11" \
-d '{
"businessId": "clxyz123abc456def789",
"buyer": {
"type": "B2B",
"tin": "12345678-0001",
"name": "Acme Nigeria Limited",
"email": "accounts@acme.example"
},
"dueDate": "2026-10-01T23:59:59.000Z",
"lines": [
{
"description": "Professional consulting services — September 2026",
"quantity": 10,
"unitPrice": 15000.00,
"taxRate": 7.5,
"hsnCode": "8471.30"
}
]
}'The invoice is created as a draft. It is not with FIRS yet — see Filing with FIRS for the next three calls.
What is required
| Field | Notes |
|---|---|
businessId | The business the invoice belongs to. A BUSINESS key may only use its own. |
buyer.type | B2B, B2C or B2G. The only required field inside buyer. |
dueDate | ISO 8601. |
lines | At least one. An invoice with no lines is rejected. |
Every line requires five things:
| Line field | Notes |
|---|---|
description | |
quantity | |
unitPrice | |
taxRate | A percentage — 7.5, not 0.075. Required on every line; there is no invoice-level tax field. |
hsnCode or isicCode | A classification code. One of the two is required — see below. |
sku, discountRate, inventoryItemId, productCategory and serviceCategory are
genuinely optional.
idempotency-key is required, not optional, on invoice creation. Leaving it out is
a 400. See Idempotency for how to choose one.
Fields worth getting right
buyer.tin is optional to us and effectively mandatory in practice. FIRS accepts a
placeholder without complaint, so a wrong or missing TIN produces a filing that looks
successful and names the wrong party. Send the real one.
Classifying a line
Every line needs a classification code, and there are two kinds. Send whichever fits the line — the correct FIRS fields are populated for you.
| Line is | Send | Format | Get valid codes from |
|---|---|---|---|
| A physical good | hsnCode | NNNN.NN — e.g. 8471.30 | GET /firs/hs-codes |
| A service | isicCode | four digits — e.g. 6190 | GET /firs/service-codes |
A four-digit code is read as an ISIC service-activity code and checked against the 419 published classes. It is not a truncated HS code, and it is not rejected.
Never pad a four-digit code to NNNN.00. 8471 is not an ISIC class; padding it to
8471.00 names an unrelated and usually nonexistent product, and FIRS accepts it
without complaint. If the line is a good and you only have four digits, look up the real
HS code — for 8471 it is probably 8471.30.
Placeholders are rejected. Neither 0000.00 nor 0000 is accepted. Omitting both
fields is a 400: "has an invalid or missing classification code".
Sending both hsnCode and isicCode with different values is also a 400 — the invoice
line stores one code, so we ask rather than guess which you meant.
productCategory and serviceCategory are optional labels, but if you send one it must
be descriptive — a very short value is rejected. Omit them to use the default.
Totals are yours to get right
We calculate the invoice totals from the lines you send, and FIRS does not check the arithmetic at all — a total that contradicts its own lines is accepted. Nothing downstream will catch a mistake here, so reconcile on your side.