Home/Developers
OpenAPI 3.1 · sandbox parity · HMAC-signed webhooks

One API contract. Every country profile.

Idempotent submissions, field-level validation errors with rule IDs, and webhook lifecycle events — identical in every market we serve. The jurisdiction is a parameter, not a project.

01 Core concepts

Three nouns. That's the whole model.

NOUN — 01

Connectors

A connector binds one client ERP to the platform — created per client from a reusable pattern (API, database, file, agent, email). Identified as cnx_*.

NOUN — 02

Profiles

The output format per jurisdiction — PINT-AE, PINT-MY, BIS-3.0 — set per submission or as a connector default.

NOUN — 03

Lifecycle events · Success API

received → validating → validated → submitted → cleared / delivered → acknowledged. Every transition fires a signed webhook — and the Success API writes the final delivered / cleared confirmation straight back into the ERP.

02 Show, don't tell

The same call, three markets.

# UAE — the rule-pack validates ~51 mandatory PINT AE fields pre-submission curl -X POST https://api.peppolbridge.jinacode.systems/v1/invoices \ -H "Authorization: Bearer $PB_API_KEY" \ -H "Idempotency-Key: inv-2027-000142" \ -d '{ "connector_id": "cnx_sap_dubai01", "profile": "PINT-AE", "source_ref": "SAP-DOC-90001234" }' # → 202 Accepted { "id": "inv_9f2c", "status": "validating", "checks": { "schema": "pending", "business_rules": "pending" } }
# Malaysia — same endpoint; the MY rule-pack additionally handles # MyInvois clearance and embeds the LHDN UIN in the Peppol payload curl -X POST https://api.peppolbridge.jinacode.systems/v1/invoices \ -H "Authorization: Bearer $PB_API_KEY" \ -H "Idempotency-Key: inv-2026-04412" \ -d '{ "connector_id": "cnx_sqlacct_kl02", "profile": "PINT-MY", "source_ref": "INV-2026-04412" }' # → 202 Accepted { "id": "inv_b71a", "status": "validating", "checks": { "schema": "pending", "business_rules": "pending", "myinvois_clearance": "pending" } }
# Lifecycle webhook — verify the HMAC signature before trusting it { "event": "invoice.cleared", "id": "inv_b71a", "profile": "PINT-MY", "uin": "LHDN-UIN-9X2K4M…", "timestamp": "2026-06-10T08:14:22Z", "signature": "sha256=4f1c0e…" } # Events: invoice.received · invoice.validated · invoice.rejected # invoice.submitted · invoice.cleared · invoice.delivered
03 Request anatomy

One request, the whole flow.

Follow a single submission end to end: the request you send, the canonical invoice model (CIM) the pipeline normalizes it into, and the signed lifecycle events you get back. Country rule-packs read the CIM — never your ERP's format.

# One call. The connector pulls the source document by reference — # you never serialize XML. The Idempotency-Key makes retries safe. curl -X POST https://api.peppolbridge.jinacode.systems/v1/invoices \ -H "Authorization: Bearer $PB_API_KEY" \ -H "Idempotency-Key: inv-2027-000817" \ -d '{ "connector_id": "cnx_sap_dubai01", "profile": "PINT-AE", "source_ref": "SAP-DOC-90001288" }' # → 202 Accepted — everything after this is asynchronous { "id": "inv_c4d8", "status": "received", "links": { "events": "/v1/invoices/inv_c4d8/events" } }
# The canonical invoice model — every source document normalizes into this. # Country rule-packs read THIS: the same CIM emits PINT AE, PINT MY # or BIS 3.0 depending only on "profile". { "invoice": { "number": "SAP-DOC-90001288", "issue_date": "2026-07-02", "currency": "AED", "seller": { "name": "Seller Co FZ-LLC", "trn": "1002345678…" }, "buyer": { "name": "Buyer Co LLC", "trn": "1008765432…" }, "lines": [ { "sku": "SVC-CONSULT", "qty": 12, "unit_price": 450.00, "tax": { "category": "S", "rate": 5.0 } } ], "totals": { "net": 5400.00, "tax": 270.00, "gross": 5670.00 } } }
# Every transition fires a webhook — HMAC-signed, timestamped, replay-safe. { "event": "invoice.received", "id": "inv_c4d8", "ts": "…T08:14:02Z", "signature": "sha256=9b0d…" } { "event": "invoice.validating", "id": "inv_c4d8", "ts": "…T08:14:03Z", "signature": "sha256=2e7a…" } { "event": "invoice.validated", "id": "inv_c4d8", "ts": "…T08:14:05Z", "signature": "sha256=c51f…" } { "event": "invoice.submitted", "id": "inv_c4d8", "ts": "…T08:14:06Z", "signature": "sha256=77d2…" } { "event": "invoice.delivered", "id": "inv_c4d8", "ts": "…T08:14:22Z", "signature": "sha256=4f1c…" } # delivered + reported on exchange markets (AE, BE) · cleared on clearance markets (MY) # verify the signature with your per-endpoint secret before trusting any event
04 Validation

Errors that name the field, not just "invalid."

Every rejection carries the XPath-level field, the authority rule ID, a human-readable message and a severity — so your support team fixes data instead of opening tickets with us.

Schema validation — XSD per profile; structure fails fast, before business rules run.
Business rules — authority rule sets per jurisdiction (PINT AE, PINT MY, EN 16931), executed pre-submission.
Sandbox parity — the identical engine runs in sandbox and production. What passes in test passes live.
422 Unprocessable Entity
{ "id": "inv_9f2c", "status": "rejected", "errors": [ { "field": "cac:TaxTotal/cbc:TaxAmount", "rule": "PINT-AE-BR-CO-15", "message": "Tax total must equal the sum of line tax amounts", "severity": "fatal" }, { "field": "cbc:BuyerReference", "rule": "PINT-AE-R-007", "message": "Buyer reference is required for tax invoices", "severity": "fatal" } ] }
05 Error codes

Every status code, one honest sentence.

CodeWhat it meansRetry?
202 AcceptedSubmission accepted; validation and submission continue asynchronously — watch the lifecycle webhooks.Nothing to retry.
400 Bad RequestMalformed JSON or a missing required parameter; nothing was created.After fixing the request.
401 UnauthorizedMissing, revoked or wrong-environment key — a sk_test_* key against production, or the reverse.With the right key.
404 Not FoundThe connector_id doesn't exist in your tenant — connectors are tenant-scoped by design.With a valid cnx_* id.
409 ConflictSame Idempotency-Key, different payload — we refuse rather than guess which one you meant.New key, or the original payload.
422 Validation failedThe body lists each failing field with the authority rule ID — e.g. PINT-AE-BR-CO-15 — and its severity.After fixing the data.
429 Rate limitedYour agreement's rate limit is exceeded; Retry-After says when to come back.After Retry-After.
5xx Server errorOur fault. Retry with the same Idempotency-Key — duplicates are impossible by design.Same key, always safe.

The full status reference ships with the OpenAPI 3.1 spec in the sample bundle — request it with your sandbox keys.

06 Integration path

From API key to production.

The full path, end to end. Most partners clear steps one to four inside a sprint; step five is a key swap, not a rewrite.

Get API keys

Request access via contact and we provision a sandbox tenant with a sk_test_* key. Separate keys per environment; IP allowlisting optional.

Create the connector

POST /v1/connectors with the pattern agreed at discovery — API, database, file, agent or email. Returns the cnx_* id every later call references.

Map to the CIM

Pull real samples from the ERP and review the field-by-field mapping to the canonical invoice model at GET /v1/connectors/{id}/mapping — then approve in bulk.

Validate in sandbox

POST /v1/invoices against the same engine production runs. Fix what the rule-ID diagnostics surface; sign off your webhook endpoint's HMAC handling.

Move to production

Swap sk_test_* for sk_live_*, clear the go-live checklist, send the first live invoice. Everything else stays identical.

08 Developer FAQ

Asked on every technical call.

Yes — request access via contact. The sandbox runs the identical validation engine as production and points at the authority test environments (e.g., the FTA and MyInvois sandboxes), so behaviour carries over exactly.

Bearer API keys, separate per environment, with optional IP allowlisting. Webhooks are HMAC-signed with per-endpoint secrets and timestamped for replay protection — verify before trusting.

Rate limits follow your agreement; bursts beyond them receive 429 with Retry-After. Because submissions are idempotency-keyed, retrying is always safe.

The local bridge agent runs inside client networks for air-gapped, bidirectional AP + AR sync; the platform itself is SaaS. In-region deployment and data-residency options are available on Enterprise agreements — talk to us.

09 Start building

Ship your integration this sprint.

Sandbox keys, the sample bundle and a Slack channel with our engineers — most partners submit their first validated invoice within a day.