URA rejected your invoice. Here is what it meant.
EFRIS answers a failed submission with a number and a terse sentence, and neither tells you what to change. This is a free reference for the codes that actually come up — what triggers each one, and what the fix is.
Read the error-code reference Quickstart
Stuck on a rejection right now? Start with 1345, 2253, 676 or 1304 — or browse all of them. Free, and staying that way.
Transcribing the spec is the easy part
Turning URA's PDF into seventy endpoint methods is a weekend of tedium, and any competent developer — or a decent coding model — can do it. That is not what this is.
A faithful implementation of the documentation does not work. The specification is wrong in several specific places, and when you get one of them wrong the service does not tell you which: you get a bare number, or a signature error that looks identical whatever caused it.
- The handshake is where most integrations die. The cryptographic choices are not the ones a careful engineer would pick, and the documentation does not state them — so a correct-looking implementation fails every call with the same opaque error, and there is nothing in the response to tell you which of five assumptions was wrong.
- The session key is not in the form the response appears to give you. Implementations routinely end up with a key of the wrong length that looks plausible and fails much later.
- Field names in the live service do not always match the specification, including one that is misspelled. Reading the documented name gives you a runtime error against production.
- Several interfaces are documented with the wrong encryption flag. Following the specification is what breaks them.
- The invoice summary is recomputed by URA and rejected on any disagreement, under rules that pull in opposite directions.
Every one of those took real time to find, against a sandbox that answers with a bare code. All of them are already solved in the source you receive — you get the answers, not the search.
What running it looks like
You onboard a business once — name, TIN, device number and their certificate. The platform issues their credentials:
POST /api/owner/add-client
Authorization: Bearer <your token>
company_name = Acme Wholesalers Ltd
tin = 1000000000
device_no = 1000000000_02
pfx_file = @acme.pfx
→ { "api_key": "efris_...", "api_endpoint": "https://your-host/api/external/efris" }
Their system then just calls your API. No certificate, no handshake, nothing cryptographic in their codebase:
POST /api/external/efris/submit-invoice
X-API-Key: efris_...
{ "invoice_number": "INV-2026-0042",
"customer_name": "Beta Trading Ltd",
"items": [ { "item_name": "Office Chair", "quantity": 2,
"unit_price": 150000, "tax_rate": 18 } ] }
→ fiscal document number, verification code, QR code
The handshake, session-key caching, encryption and response decoding happen underneath. Rejections come back with URA's own numeric code, so callers branch on the number rather than parsing prose.
Multi-tenant from the ground up
Nothing is global. Every business you onboard keeps its own certificate and its own session, so they never share cryptographic state — and the session key is negotiated once and reused, not renegotiated per request. Add as many as you like; there is no per-client fee and nothing is reported back to us.
~70 interfaces
T101–T187. Invoicing, credit notes, goods, stock, reference data, fuel/EDC.
Client management
Onboarding, API key issuance, certificate storage, suspend and reactivate.
Owner portal
Audit and activity logs, per-client rate limits, IP allow-lists, 2FA.
The EFRIS API, as a Postman collection
The full Postman collection — all 72 EFRIS interfaces (T101–T187) in five folders — invoicing, credit notes, goods, stock, reference data and fuel/EDC. This is the API your clients call.
Download the Postman collection
Or import it straight from the URL: in Postman choose Import →
Link and paste
https://efrisapi.com/efris-api-postman-collection.json.
Set base_url, token and api_key as
collection variables; the folders are ordered the way you would actually work
through it — log in, onboard a client, then fiscalise as that client.
Stop fixing these one at a time
Every code documented here is one somebody hit in production and worked out the hard way. If you would rather not repeat that, the implementation that already handles all of them is available as source.
A complete multi-tenant EFRIS platform, sold as source. Onboard businesses, issue each an API key, and let their systems fiscalise through one REST API — without any of them touching URA's certificates or handshake.
- All ~70 EFRIS interfaces (T101–T187)
- Client onboarding & API key issuance
- Certificate and key generation per taxpayer
- Multi-tenant: unlimited businesses on one deployment
- Admin portal, audit logs, rate limits
- Postman collection & deployment documentation
The error codes, the quickstart and the interface coverage on this site are free and stay free, whether or not you ever buy anything. They exist because this information is not written down anywhere else, and every integrator ends up needing it.
URA keeps moving — T186 and T187 arrived in 2024, T127 and T130 changed in 2025 — so the reference is updated as rejections turn up in practice rather than when a specification is republished.
Get in touch
A rejection this reference does not cover, an integration that is already stuck, or a question about the platform:
WhatsApp +256 784 769 332 [email protected] Call +256 784 769 332
Mon–Fri, 9am–6pm EAT (UTC+3). WhatsApp is usually fastest.
Independent software. Not affiliated with, endorsed by, or operated by the Uganda Revenue Authority. "EFRIS" refers to URA's system, which this library integrates with.