Authentication & Conventions
Every request to the EFRIS API is authenticated with your business's API key, sent as a Bearer token. You can generate and rotate the key from your EFRIS Simplified dashboard under Security.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
https://efrissimplified.com/api/efris/{tin}{tin} is the TIN of the business registered on EFRIS Simplified. All endpoints are
POST and accept/return JSON.
A request with a missing or malformed Authorization header returns HTTP 401:
{
"response": "ERROR",
"message": "Missing or malformed Authorization header. Use: Bearer <api_key>",
"data": null
}
Field naming: camelCase only
All fields are camelCase and match the official URA EFRIS field names exactly (e.g.
goodsCode, havePieceUnit, buyerTin). snake_case is not
accepted - goods_code will fail validation. If you have worked with URA's EFRIS specification
before, every field name in this documentation will look familiar; that is intentional.
Numeric values as strings
EFRIS expects numeric values as strings (e.g. "quantity": "100", "taxRate": "0.18").
The API accepts both raw numbers and strings, but strings are recommended for consistency with the URA
specification - and they avoid floating-point surprises in your own serialiser.
Pricing rule: amounts are tax-inclusive
All invoice amounts are gross (tax-inclusive). If an item's net price is 10,000 UGX and VAT is
18%, you send unitPrice: "11800". The VAT portion is then reported per line and per tax category -
see Fiscal Invoices for fully worked examples.
The response envelope
Every endpoint returns the same three-field envelope:
{
"response": "OK", // "OK" or "ERROR"
"message": "Invoice fiscalised successfully",
"data": {} // Decrypted EFRIS response body (structure varies per endpoint)
}
| Field | Meaning |
|---|---|
response |
"OK" on success, "ERROR" on any failure |
message |
Human-readable outcome. For URA rejections this carries the official EFRIS error code and message |
data |
The decrypted EFRIS response body - for example the fiscalised invoice with its FDN and QR code |
Error handling
Two kinds of failure can occur, and they look different:
-
Validation failures return HTTP
400before anything reaches URA, with anerrorsobject keyed per field:
{
"response": "ERROR",
"message": "Validation errors: The goods.0.goodsName field is required.",
"data": null,
"errors": {
"goods.0.goodsName": ["The goods.0.goodsName field is required."]
}
}
-
EFRIS rejections happen after URA processes the request. The URA error code and message are
returned inside
message- for example inventory shortage (1600) or an itemCount mismatch (1304). These codes are referenced throughout this documentation next to the rules that trigger them.
Security recommendations
- Store the API key server-side. Never embed it in mobile apps, browser JavaScript, or public repositories.
- Rotate the key from your dashboard if you suspect it has leaked - the old key stops working immediately.
- Always call the API over HTTPS; plain HTTP requests are not served.