CamInvoice compliance is not really an invoicing problem. Most businesses already produce invoices; what the mandate adds is that each one must be rendered in a prescribed structure, submitted to the General Department of Taxation through an API, and retained with the confirmation the GDT returns. The work is a mapping-and-lifecycle problem between a system a business already runs and an interface it does not control. This scenario sets out how that connector would be scoped, and why the least interesting architectural decision — where it runs — is the one that matters most.
Updated August 2026·8 min read
The situation this scenario addresses
Assume a mid-sized Cambodian business — a distributor, a services firm, a restaurant group — that is VAT-registered and already inside the CamInvoice mandate or approaching its phase of it. It raises a few hundred to a few thousand invoices a month from an accounting package or a POS system it has used for years. The finance team is small. There is no in-house integration capability and no appetite to change the system everyone knows.
The compliance requirement is not negotiable and the enforcement risk is real, so the question is never whether to connect but how, and the honest answer depends almost entirely on what the existing system can already tell you.
That is why the first phase of an engagement like this is not development. It is a survey of the source system: can it emit invoice data at all, and does that data carry every field the submission requires? Businesses are frequently missing something structural — counterparty tax identifiers that were never captured, tax broken out at document level rather than line level, or invoice numbers that are reused across branches. Every one of those is a data problem that no amount of connector engineering will solve, and finding them in week one rather than week nine is most of the value of scoping properly.
What the connector actually has to do
Reduced to essentials, four things.
Extract. Pull invoice data out of the source system by whatever route it supports — an API, a database view, a scheduled export, or a watched folder. This is the part that varies most between clients and the part least worth being clever about.
Map. Transform the business's own representation of an invoice into the structure the GDT expects, including the tax identifiers of both parties, line items with their classifications, the tax computation, and the document identifiers that make the submission traceable back to the source record. Cambodia's e-invoicing model follows the same structured-document lineage as UBL-based systems elsewhere in the region, which means the mapping is mechanical once the source fields exist — and impossible where they do not.
Submit. Authenticate with the client's credentials, transmit the document, and capture whatever the GDT returns: an acceptance with its confirmation reference, or a rejection with the field that caused it.
Retain. Store the submitted document and its response together, in the client's systems, for the statutory retention period. The connector should treat the GDT response as the authoritative record and never as a transient acknowledgement to be discarded after logging.
Connector stages and where each one typically fails
Stage
Function
Most common defect
Extract
Read invoices from the source system
No stable identifier, so re-reads duplicate
Map
Transform to the required document structure
Source lacks a mandatory field entirely
Validate
Check completeness before transmitting
Skipped — rejections discovered downstream
Submit
Authenticated transmission to the GDT
Retry without idempotency, creating duplicates
Retain
Store document plus response together
Response logged but not durably stored
Meeting the business where its systems actually are
The right integration route is set by what the source system supports, and it is worth being blunt that the cheapest route is often the best one.
Where the source system exposes an API or can fire an event as an invoice is raised, the connector is event-driven and submission happens as part of the ordinary flow of business. Nobody has to remember to do anything.
Where it cannot, but can export on a schedule, the connector reads batches. This is unglamorous and entirely adequate: a business filing a few hundred documents a month gains nothing from real-time submission that it does not gain from a nightly cycle, provided the cycle is monitored and failures are visible the next morning rather than at the end of the month.
Where the source system is a spreadsheet or paper, no connector will help. That is a bookkeeping engagement before it is an integration engagement, and saying so early is more useful to the client than building something that automates the transmission of data nobody is reliably capturing.
The distinction matters commercially as well as technically. A client in the third position who is sold an integration will not get compliance out of it, and will reasonably feel misled when they discover why.
Integration route by source-system capability
Source system can…
Route
Submission cadence
What the client must still do
Expose an API or emit events
Event-driven connector
As invoices are raised
Monitor the exception queue
Export on a schedule
Batch connector
Daily or per shift
Review the daily run
Only produce documents by hand
No connector — bookkeeping first
n/a
Establish reliable capture
Idempotency, retries and the duplicate-submission problem
The single most consequential design decision in a connector of this kind is what happens when a submission's outcome is unknown.
A network timeout does not tell you whether the GDT received the document. Naive retry logic resubmits, and if the first attempt did in fact land, the taxpayer now has two records of one sale — a problem that is far more troublesome to unwind than the original failure, because it must be corrected through the tax authority's own process rather than in the client's database.
The defence is to make every submission carry a stable, deterministic identifier derived from the source invoice, so that a retry is recognisable as the same document rather than a new one, and to record locally that an attempt was made before making it. A connector that writes its intent before acting can always reconstruct what it was doing when it stopped. One that writes only on success cannot.
Retries should also back off rather than hammer, and should distinguish between failures that are worth retrying — a timeout, a transient server error — and failures that never will be. A document rejected because a tax identifier is malformed will be rejected identically a thousand times. It belongs in an exception queue in front of a human, immediately, not in a retry loop that hides it until a deadline has passed.
End-of-period surges make all of this sharper. Filing deadlines concentrate load across every taxpayer in the country at once, and an interface that responds comfortably mid-month is not the same interface at the deadline. A connector should be built assuming that the window in which it most matters is the window in which the far end is least responsive.
Where the scope boundary sits
CamFinTech builds the connector: the extraction adapter, the mapping, the validation, the submission client with its retry and idempotency behaviour, the retention wiring into the client's storage, and the operational documentation. It is charged as a fee for that build. No commission, no per-document pricing, no margin on anything a third party invoices.
The client runs it. The connector is deployed in the client's environment, authenticates as the client, and stores the client's records. We do not host or transmit client invoice traffic. This is the design seam described in our positioning, and it is a limit on what we will build rather than a limit on what we will say.
The client remains the taxpayer. Registration, credentials, filings and the underlying tax positions are theirs. Where an engagement also involves accreditation or approval, the client is the applicant of record; CamFinTech does not influence the GDT's decisions and does not claim to. Where a client engages an accredited service provider for part of the chain, we build to that provider's interface — we do not stand in its place.
Advice on tax treatment is reserved work. It goes to the client's licensed tax agent. A connector engineer's opinion about how a transaction should be classified is worth exactly nothing to a client in an audit, and offering it would be a disservice dressed as helpfulness.
Why this shape generalises
CamInvoice is the current instance of a pattern rather than a one-off. A tax authority publishes a mandatory interface; every registered business must speak it; the gap between what businesses run and what the interface expects is the work.
That pattern recurs, and it recurs on a schedule that businesses do not set. The design implication is to treat the connector as a component with a stable internal representation of a document and a replaceable outbound adapter, rather than as a script that reshapes one system's output into one authority's format. The first costs slightly more to build once. The second costs the same amount again every time a requirement changes.
That is an architectural argument, not a prediction about what will be mandated next, and it is the argument worth making to a client who is inclined to buy the cheapest possible route through the immediate deadline.
Fee-only. We build the client-side integration ourselves, or bring in an accredited Service Provider as a disclosed sub-contract. We never hold client funds and never operate a rail.