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
Base URL: 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 400 before anything reaches URA, with an errors object 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.

Stuck on an integration step? Our engineers reply fast.