External System Connectivity¶
Applies to: All subscriptions
Purpose¶
Connect the ERP so documents flow in and outcomes flow back — and prove the integration handles failure, not merely success. Integrations that only handle the happy path fail quietly in production.
Audience¶
The integration developer, with the implementation consultant and the customer's ERP team.
Prerequisites¶
- e-Invoice Setup and e-Way Bill Setup gates passed
- ERP developer effort allocated, with a named person
- Raw, unmodified sample payloads per document type
- Sandbox credentials issued for the integration
Steps¶
1. Issue the credential¶
One credential per ERP, scoped to the registrations that ERP sends for. Never shared — a shared credential cannot be revoked for one integration without breaking the others.
Capture the secret into a secret manager at the moment of issue. It is shown once and cannot be retrieved afterwards.
See Machine-to-Machine Authentication.
2. Prove authentication before anything else¶
Call a low-risk endpoint. A response of any kind proves authentication; only an unauthorised response means the credential is wrong.
Doing this first means every subsequent failure is a data or mapping problem, not an ambiguity between the two.
3. Build the mapping from raw ERP output¶
Build the template from unmodified ERP output, including its quirks. A hand-cleaned sample produces a mapping that works in testing and fails on real documents — the single most common integration failure in this stage.
4. Verify the mapped payload, field by field¶
Acceptance proves the document was valid. Only the mapped payload proves it was correct.
| Check | Why |
|---|---|
| Every field carries the intended value | Wrong values are more dangerous than rejections |
| Dates are correct | Test with the fifth of March, where a transposition is visible |
| Coded values translate correctly | And an unrecognised code fails rather than defaulting to a tax invoice |
| Every line is present | Test with a multi-line document |
| Amounts are numeric | Not formatted strings |
5. Test every failure class¶
This is the step that separates an integration that works from one that appears to.
| Response | The ERP must |
|---|---|
| Accepted | Store the identifier |
| Validation rejection | Store the errors, surface them to a person, not retry |
| Duplicate | Reconcile, not retry |
| Forbidden | Alert an administrator — a scope problem |
| Unauthorised | Refresh the credential, retry once |
| Rate limited | Back off and retry |
| Server error | Back off, retry, bounded |
| Timeout | Query status before resending |
Force each one in the sandbox. Reading the table is not the same as having handled it.
6. Close the loop with write-back¶
Enable write-back for the registrations in scope, configure the subscription, and build the consumer.
| Requirement | Why |
|---|---|
| Idempotent on the event identifier | Delivery is at-least-once. It will happen |
| Acknowledge only after committing | Otherwise events are lost on a crash |
| Cursor persisted durably | An in-memory cursor restarts from nothing |
| Unknown event types logged and skipped | New types appear; a fatal reaction breaks on an upgrade |
Remember that enabling write-back does not backfill. Documents processed during earlier stages produce no events.
7. Prove recovery¶
| Test | Expected |
|---|---|
| Stop the ERP mid-batch, restart | Reconciliation identifies what was and was not sent |
| Deliver an event twice | Processed once |
| Crash between applying and acknowledging | The event is redelivered and handled correctly |
| A simulated outage | Both systems agree afterwards |
8. Add monitoring on the ERP side¶
Complifly cannot distinguish a stopped integration from a quiet day. The ERP side must alert on:
| Signal | Alert when |
|---|---|
| Documents sent | Falls to zero during business hours |
| Rejection rate | Rises above baseline |
| Documents awaiting registration | Ageing towards the reporting window |
| Write-back events consumed | Falls to zero |
9. Assign the exception owner¶
Name the person who reviews rejections daily, and the process they follow. Without this, rejections accumulate silently until a filing deadline exposes them — the most common way an otherwise-successful integration fails after go-live.
Validation¶
Gate: this stage is complete when all of these pass.
| Check | Pass condition |
|---|---|
| Authentication proven | A low-risk call accepted |
| Mapping verified field by field | Against raw ERP output |
| Every document type sends | Including edge cases |
| Every failure class handled | Each forced in the sandbox and handled correctly |
| Nothing unretryable is retried | Verified |
| Timeout reconciliation works | Status queried before resend |
| Write-back consumed | Outcomes visible in the ERP |
| Consumer is idempotent | A duplicate event processed once |
| Recovery proven | Systems agree after a simulated outage |
| ERP-side monitoring live | Alerts tested |
| Exception owner named | With a defined daily process |
Rollback¶
| Situation | Action |
|---|---|
| Mapping wrong | Correct it. Documents already ingested keep their mapped values — correct those separately |
| Credential compromised or wrong | Revoke and issue a new one; migrate the caller |
| Write-back enabled prematurely | Disable it. Emitted events remain but stop accumulating |
| The integration sends wrong data | Stop the feed first, then fix |
That last row is the operational instinct worth instilling: stop the feed, then diagnose. A stopped feed is recoverable; a stream of wrong documents reaching the government is not.
Common mistakes¶
| Mistake | Consequence | Avoid by |
|---|---|---|
| Building the mapping from cleaned samples | Works in testing, fails on real documents | Use raw ERP output |
| Testing only the happy path | Silent failures in production | Force every failure class |
| Retrying validation failures or duplicates | Rate limits exhausted; duplicates created | Never retry them |
| Blind resend on timeout | Permanent duplicates | Query status first |
| A consumer that is not idempotent | Double-posted outcomes | Deduplicate on the event identifier |
| Acknowledging before committing | Events silently lost | Reverse the order |
| Sharing one credential across ERPs | Cannot revoke one without breaking others | One per ERP |
| No ERP-side monitoring | A stopped integration nobody notices | Alert on documents sent |
| No exception owner | Rejections accumulate to a deadline | Name one before go-live |
Troubleshooting¶
| Symptom | Cause | Action |
|---|---|---|
| Forbidden on every document | Credential scope excludes the registration | Fix the scope, not the user role |
| A field arrives empty | Mapping path wrong, or absent for this document type | Compare against the raw payload |
| Dates a month out | Format token wrong | Test with an unambiguous date |
| Only the first line arrives | Array notation wrong | Test with a multi-line document |
| No write-back events | Flag off, no subscription, or consumer stopped | Check in that order |
| Events processed twice | Consumer not idempotent | Deduplicate |
| Documents stopped arriving | ERP job, credential, or network | Check in that order |
Related Articles¶
- The Integration Pattern · Custom ERP
- Ingest API · Write-back API
- Validation Testing — the next stage