Docs

3 API3.2

3.2

Submit JSON: POST /invoices

Canonical JSON or an ERP export.

  • In the sandbox

In plain words

This call submits an invoice: if it passes every check the service queues it, and if not the answer names the field that failed and nothing is queued.

POST /invoices checks the invoice like a dry run. If it passes, the service queues it and answers 202 with an id. If a check fails, the answer is 422 and nothing is queued. The call needs a key with the submit scope and an Idempotency-Key.

The request

PartMeaning
Idempotency-Key headerRequired, 8 to 100 characters.
invoice_refRequired. The ERP's own document id, up to 100 characters.
routeOptional. One of the five routes. Left out, the service chooses it from the invoice (the seller's and buyer's countries, the profile and the client's stored credentials). If no rule fits, the answer is 422, EI-ROUTE-UNDECIDED or EI-ROUTE-PEPPOL-UNKNOWN.
documentOne invoice in the canonical model. Send this or an export with a connector, not both.
export, connectorAn ERP export as the ERP wrote it, with connector set to business-central or sap-b1. The service maps it with the connector's live mapping version, or the mapping_version you name (see mapping versions). A finding in the mapping answers 422 and names the ERP field. The export is kept with the invoice.
formatsOptional. Name at most one: the document that is built, checked and sent.
environmentOptional. If you send it, it must match the environment of your key, or the answer is 400.
clientOptional. A client's own key may leave it out or name its own client; any other client answers 403. The rail caps are counted per client (see limits).

The body is limited to 5 MB. In production an export is read only when the client's connector settings hold the client's own seller and payment details; without them the answer is 422, connector-settings-missing, naming what is missing. The sandbox reads it with the connector's example details.

An accepted invoice

The sample is submit-de.json. Location holds the invoice URL, and links points at the invoice and its events. The state is queued: nothing has been sent.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2026-0001" \
  --data-binary @submit-de.json
Response202 Accepted
{
  "links": {
    "self": "/invoices/inv_936a93e38de84e7b0a1d7681",
    "events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"
  },
  "id": "inv_936a93e38de84e7b0a1d7681",
  "state": "queued"
}
Recorded on 7 Oct 2026.

An invoice that fails a check

The same call with the seller's name removed, submit-de-missing-seller-name.json. The answer is a problem document with an errors list. Each error is a finding like the ones in a dry-run report. The highlighted lines are the code and the field to fix.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2026-0002" \
  --data-binary @submit-de-missing-seller-name.json
Response422 Unprocessable Content
{
  "type": "https://eurinvoice.com/problems/validation-failed",
  "title": "The invoice did not pass the checks",
  "errors": [
    {
      "code": "EI-SCHEMA",
      "field": "seller.name",
      "related": [
        {
          "code": "Art.226(5)",
          "source": "pre-check"
        }
      ],
      "fix_hint": "Read the JSON path in the error and correct the client mapping.",
      "who_fixes": "us",
      "source": "schema",
      "message": "We could not read this invoice from your export. We are correcting our mapping; if a field is missing in the ERP we will tell you which one."
    },
    {
      "code": "Art.226(5)",
      "field": "seller.name",
      "related": [
        {
          "code": "EI-SCHEMA",
          "source": "schema"
        }
      ],
      "fix_hint": "Complete the party's name and address in the master data.",
      "who_fixes": "erp",
      "source": "pre-check",
      "message": "A company name or street address is missing. Complete the company or customer record in the ERP."
    }
  ],
  "status": 422
}
Recorded on 7 Oct 2026.

Idempotency

  • The same key with the same body returns the first answer again, with the same id.
  • The same key with a different body is 409.
  • A stored answer includes a 422. Send a corrected invoice with a new key.
  • A stored answer is kept for as long as the client's data is kept.
  • A second request with a key whose first request is still running gets 409, request-in-progress. A key whose request never answered, because the server stopped, is freed after 15 minutes.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2026-0001" \
  --data-binary @submit-de.json
Response202 Accepted
{
  "links": {
    "self": "/invoices/inv_936a93e38de84e7b0a1d7681",
    "events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"
  },
  "id": "inv_936a93e38de84e7b0a1d7681",
  "state": "queued"
}
The first call again, same key and same body: the same id. Recorded on 7 Oct 2026.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2026-0001" \
  --data-binary @submit-de-changed.json
Response409 Conflict
{
  "type": "https://eurinvoice.com/problems/idempotency-conflict",
  "title": "This Idempotency-Key was already used with a different body",
  "status": 409
}
Same key, a different body ([submit-de-changed.json](/samples/submit-de-changed.json)). Recorded on 7 Oct 2026.

A document you sent before

A document identical to a live one, for the same client and route, is accepted again under a new key. The answer carries duplicate_of, the id of the first invoice, and nothing new is queued.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2026-0003" \
  --data-binary @submit-de.json
Response202 Accepted
{
  "links": {
    "self": "/invoices/inv_936a93e38de84e7b0a1d7681",
    "events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"
  },
  "id": "inv_936a93e38de84e7b0a1d7681",
  "state": "queued",
  "duplicate_of": "inv_936a93e38de84e7b0a1d7681"
}
The first invoice's document under a new key. Recorded on 7 Oct 2026.

Answers

StatusMeaning
202Accepted and queued, or a duplicate of a live invoice.
400The body is not valid JSON, a field is wrong, or the Idempotency-Key is missing or not 8 to 100 characters.
401No key, or an unknown key.
403The key lacks the submit scope, or names another client (forbidden).
409The key was used with a different body (idempotency-conflict), or its first request is still running (request-in-progress).
413The body is over 5 MB (payload-too-large).
422The invoice failed a check. errors says what and who fixes it.
429Too many requests for the key. Wait for Retry-After seconds.
503Another request for the same document is still being stored (busy). Nothing was written and the key can be used again. Retry after Retry-After seconds.

Warning

After a 202 you never resend. Rail-side errors that can pass are retried on our schedule, and a permanent rejection goes to the care list.

On this page