Buy the EFRIS integration instead of building it.
Commercial Python source code for Uganda Revenue Authority's EFRIS — all ~70 interfaces, invoicing through stock. You receive the full source under licence, modify it freely, and run it yourself. Not a subscription, not a hosted API.
See licence pricing Read the error-code reference
Stuck on a URA rejection right now? The error-code reference is free and always will be — 1345, 2253, 676, 1304 and the rest, with what each one actually means.
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 using it looks like
from efris import EfrisClient, EfrisConfig
client = EfrisClient(EfrisConfig(
tin="1000000000",
cert_path="/secure/certs/1000000000.pfx",
cert_password=os.environ["EFRIS_CERT_PASSWORD"],
test_mode=True,
))
client.get_server_time() # proves connectivity before crypto
result = client.upload_invoice(document) # T109 — fiscalised
The T104 handshake, session-key caching, encryption and response decoding happen underneath. Failures raise with URA's own code, so you branch on the number instead of parsing prose:
try:
client.upload_invoice(document)
except EfrisError as exc:
if exc.code == "2253": # duplicate seller reference
...
Built for multi-tenant use
Nothing is global. A client is bound to one configuration and holds its own session key, so an ERP serving many taxpayers keeps one client per tenant and they never share cryptographic state. Credentials come from wherever you keep them — a database row, a secrets manager, per-tenant files.
registry.for_tenant("acme").upload_invoice(document)
~70 interfaces
T101–T187. Invoicing, credit notes, goods, stock, reference data, fuel/EDC.
Two dependencies
requests and cryptography. No
framework lock-in.
REST service included
Optional FastAPI wrapper for callers that aren't Python.
Pricing
Most Ugandan businesses pay around 1,000,000 UGX per year for EFRIS API access, regardless of provider. This is the buy-instead-of-rent option: you get the source, and you stop renewing.
$1,000 one-time
3,700,000 UGX · roughly 3.5 years of a subscription.
- Full source, modify freely
- Use for your own TINs, unlimited
- Multi-tenancy included
Updates & new error fixes: $220/year (800,000 UGX), optional.
from $3,500 one-time
13,000,000 UGX · for ERP vendors shipping to their own customers.
- Everything in Internal
- Embed and redistribute in your product
- Unlimited end-user deployments
Updates & new error fixes: $800/year (3,000,000 UGX), optional.
Payable in USD or UGX. UGX figures are indicative and settled at the rate on the invoice date. Integration support and done-for-you setup are quoted separately.
Why the annual renewal is the part that matters. URA keeps moving — T186 and T187 arrived in 2024, T127 and T130 changed in 2025. A library bought today is stale within a year without updates. The subscription is also where new rejection fixes land, so it compounds: every URA error solved makes it further ahead of a fresh reimplementation.
Get in touch
Licensing questions, a walkthrough of what you receive, or help with an integration that is already stuck:
WhatsApp +256 784 769 332 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.