eTIMS Integration: What Kenyan Businesses Need to Know
What eTIMS integration actually involves for Kenyan businesses — why re-keying invoices into a portal does not scale, what to build, and the failure modes that catch engineering teams.
eTIMS Integration: What Kenyan Businesses Need to Know
There are two ways for a Kenyan business to meet its electronic tax invoicing obligations. One is that somebody in finance retypes each invoice into a portal. The other is that your system transmits invoices as they are raised, and nobody retypes anything.
The first is not an integration. It is a person, and that person is a bottleneck, a source of transcription errors, and a single point of failure who occasionally takes leave. At low volume it is survivable. It stops being survivable at exactly the moment your business grows, which is the worst possible moment to discover it.
This is a guide to what the second option actually involves.
What eTIMS is, briefly
eTIMS is the Kenya Revenue Authority's electronic Tax Invoice Management System. Invoices are transmitted to KRA and validated, rather than being compiled and submitted separately after the fact. The intent is that the tax authority sees invoices close to when they are raised.
For a business, the practical consequence is that invoicing stops being purely an internal act. Raising an invoice now involves a third party that can accept it, reject it, or be unavailable — and your software has to cope with all three.
That is the entire engineering problem, and it is where teams get it wrong.
The happy path is not the work
Any competent developer can call an API and receive a success response. If your integration works when everything works, you have written perhaps thirty percent of it.
Here is what the remaining seventy percent has to handle.
Rejection. KRA validates what you send. An invoice may be rejected for reasons that are entirely your data's fault — a malformed tax identifier, an item without a valid classification, a total that does not reconcile to its line items. What does your system do? If the answer is "shows an error to whoever happened to be at the screen," that invoice is now in an undefined state: raised in your system, unknown to KRA, and nobody owns the discrepancy.
Unavailability. The service will at some point be unreachable. Your business cannot stop invoicing because a remote endpoint is down. So invoices must queue durably, retry with backoff, and reconcile when the service returns — and your finance team needs to be able to see, at any moment, which invoices are transmitted, which are queued, and which were rejected.
Duplication. If your request times out, did KRA receive it? You do not know. Retry naively and you may transmit the same invoice twice. Do not retry, and you may have an invoice that was never transmitted at all. The answer is idempotency: every transmission carries a key that lets the same logical invoice be retried safely without being recorded twice. This is the single most common defect we find in integrations built by teams meeting the requirement for the first time.
Credit notes and amendments. Invoices get corrected. Sales get reversed. Your integration must handle the full lifecycle, not just creation, and the accounting treatment must remain consistent between your ledger and what KRA holds.
Reconciliation. At any point you must be able to answer: does what KRA believes we invoiced match what our ledger says we invoiced? If you cannot answer that automatically, you will answer it manually, under time pressure, during an audit.
Where it fits with everything else
For most Kenyan businesses the two integrations that matter are eTIMS and M-Pesa, and they are related in an unobvious way.
M-Pesa via the Daraja API brings money in. eTIMS records the invoice that money settles. A system where both are integrated but neither is reconciled against the other creates a specific and painful failure: payments arrive that cannot be matched to invoices, and invoices exist for which no payment can be found. Finance then reconciles by hand, which is precisely the labour the integrations were meant to remove.
Build them as one flow. An invoice is raised, transmitted to eTIMS, and carries an identifier. A payment arrives via Daraja and is matched to that invoice automatically. The ledger, the tax record and the bank all agree without a human comparing three screens.
This is the difference between integrating systems and connecting them.
What to ask a developer
If you are commissioning this work, the questions that separate a real integration from a demo are specific.
How is idempotency handled — what happens when a transmission times out and is retried? What happens to an invoice that KRA rejects; who is notified, and what state is it in? Where do invoices queue when the service is unavailable, and how do they drain? How does finance see the status of every invoice without asking an engineer? How do you reconcile our ledger against KRA's record, and how often?
A developer who has done this before will have immediate answers, because these are the problems the work consists of. One who has not will talk about the API.
And ask how it was tested. A sandbox environment behaves differently from production, and the transition between them is where integrations that "worked in testing" fail publicly.
A closing note on scope
eTIMS obligations, the applicable invoicing requirements, and the available integration methods are set by KRA and change. Anything specific in this article should be verified against current KRA documentation before you build against it, and your tax adviser — not your software vendor — should confirm what your business is obliged to do.
What does not change is the engineering. Idempotency, durable queuing, rejection handling and reconciliation are the work, whichever endpoint you are transmitting to.
Frequently asked questions
Can we just use the eTIMS portal instead of integrating?
You can, and for very low invoice volumes it may be reasonable. The difficulty is that it does not scale and it introduces a human transcription step between your ledger and the tax authority, which means the two can silently diverge. It also creates a single point of failure in whoever performs the task. Most businesses that begin with the portal integrate eventually, and do so under time pressure once volume has already made the manual process painful.
What is the hardest part of an eTIMS integration?
Not calling the API. The difficulty is everything around the happy path: what happens when an invoice is rejected, when the service is unreachable, or when a request times out and you cannot tell whether it was received. That last case requires idempotency — a key ensuring the same logical invoice cannot be recorded twice on retry — and it is the most common defect we find in integrations built by teams doing this for the first time.
Should eTIMS and M-Pesa be integrated together?
They should at least be reconciled together. M-Pesa brings the money in; eTIMS records the invoice that money settles. If the two are integrated independently but never matched, your finance team ends up manually pairing payments to invoices — exactly the labour the integrations were supposed to eliminate. Building them as one flow, where a Daraja payment automatically matches an invoice carrying its eTIMS identifier, is what makes the ledger, the tax record and the bank agree without human intervention.
How do we know our system stays in sync with what KRA holds?
By reconciling automatically and regularly, and by making invoice status visible to finance without an engineer's help. At any moment somebody should be able to see which invoices are transmitted, which are queued, and which were rejected and why. If that information can only be obtained by reading logs, you will discover the discrepancies during an audit rather than before one.
Can you integrate eTIMS with our existing ERP or accounting system?
Usually, yes — it depends on whether the system exposes an extension point or an API. We integrate eTIMS into ERPs we build, into off-the-shelf platforms that permit it, and into custom accounting systems, including ones whose original developer is long gone. Where a platform is genuinely closed, the honest answer is sometimes that a middleware layer is required, and we will say so rather than pretend a clean integration exists.