Error reference
Complete reference of all Beliq API error codes, HTTP statuses, and remediation guidance.
All API errors use the same response shape:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of the error",
"details": {}
}
}| Field | Type | Description |
|---|---|---|
code |
string | Stable, machine-readable error code |
message |
string | Human-readable explanation |
details |
object? | Structured data for the codes that carry it: fields on a schema VALIDATION_ERROR, validationResult on INVALID_INVOICE, allowedProfiles on PROFILE_STANDARD_MISMATCH, creditNoteCapableStandards on DOCUMENT_TYPE_STANDARD_MISMATCH, unmappablePaths on CONVERSION_LOSSY_FAILCLOSED. Absent on every other code |
incidentId |
string? | Support correlation ID, present on 5xx responses only. Quote it together with the x-request-id header when you email hello@beliq.eu |
Error codes
| Code | HTTP Status | Meaning | Endpoints | Remediation |
|---|---|---|---|---|
VALIDATION_ERROR |
400 / 413 / 415 / 422 | Request body is invalid. This code is also the catch-all for client errors that have no more specific code, so read the status to tell them apart: 400 the body failed the schema, 413 it exceeded the size limit and was never read, 415 the content type is not accepted on that route, 422 the engine judged the document unprocessable | All | For 400, check required fields and types in the generate schema. For the others the status is the diagnosis; the message names the specific cause |
INVALID_INVOICE |
422 | Invoice data is structurally valid JSON but fails validation: EN 16931 or CIUS Schematron for UBL/CII, or authority XSD for Italy FatturaPA | /v1/generate |
Inspect details.validationResult.errors (and for FatturaPA, structural XSD findings where applicable) |
PROFILE_STANDARD_MISMATCH |
422 | The chosen profile is not allowed for the chosen standard |
/v1/generate |
Use a compatible combination — the response details includes standard, profile, and allowedProfiles. See the profile compatibility table. |
DOCUMENT_TYPE_STANDARD_MISMATCH |
422 | documentType: "creditnote" with a standard that does not accept CreditNote payloads — today fatturapa and facturae (invoices only). |
/v1/generate |
Inspect details.creditNoteCapableStandards; it lists standards that honour CreditNotes in the deployed engine (facturx, peppol-bis, xrechnung, zugferd, eslog). See the Peppol Credit notes section. |
PARSE_FAILED |
400 | Input file could not be parsed as a valid e-invoice | /v1/parse |
Verify the input is a well-formed UBL 2.1 or CII XML, or a ZUGFeRD / Factur-X hybrid PDF with an embedded CII attachment. FatturaPA and SDI messaggio inputs are not handled by parse — use /v1/validate for those. |
AUTHENTICATION_REQUIRED |
401 | No API key provided or key format is invalid | All /v1/* |
Include Authorization: Bearer <key> or X-API-Key: <key> in the request headers |
INVALID_API_KEY |
403 | API key does not exist or has been revoked | All /v1/* |
Verify the API key in the dashboard. Generate a new key if it was revoked |
QUOTA_EXCEEDED |
429 | Monthly usage quota exhausted | /v1/generate, /v1/validate, /v1/parse |
Upgrade your subscription plan in the dashboard, or wait until the window rolls over (Retry-After is the seconds until then; /v1/me reports the same instant as resetsAt) |
RATE_LIMITED |
429 | Too many requests in the current one-minute burst window | All | Respect Retry-After and retry with backoff. Retry-After here is seconds, not minutes |
ACCOUNT_THROTTLED |
429 | The account is temporarily throttled after sustained pressure on its own limits. Unlike RATE_LIMITED, this blocks every /v1 route until it expires |
All | Respect Retry-After, which can be several minutes — much longer than a burst window. Stop retrying in a tight loop: further requests while throttled extend it. Reaching this state means requests were being sent well beyond the plan’s allowance for a sustained period |
ENGINE_UNAVAILABLE |
503 | Beliq could not process the request: the engine was unavailable, or a burst was larger than could be served inside the request deadline | /v1/generate, /v1/validate, /v1/parse, /v1/convert |
Retry after Retry-After. The document’s quota unit is refunded (see Quota refunds), so a retry does not cost you a second document. Safe to retry automatically. If persistent, check the status page and email hello@beliq.eu with the error.incidentId value |
INTERNAL_ERROR |
500 | Unexpected server error | All | Retry the request. If persistent, email hello@beliq.eu with the error.incidentId value and the x-request-id response header |
NOT_FOUND |
404 | No route exists at the requested path and method | All | Check the path and HTTP method against this reference. A POST route called with GET returns this too |
PDF_TEMPLATE_AUTH_REQUIRED |
400 | pdfTemplateId was sent without an authenticated organization. Stored PDF templates are org-scoped, so they require an API key (the free, unauthenticated generator can use template: "standard" instead). |
/v1/generate |
Send the request with your Authorization: Bearer <key>, or drop pdfTemplateId and use template: "standard" for the built-in layout |
PDF_TEMPLATE_NOT_FOUND |
404 | The referenced pdfTemplateId does not exist in your organization |
/v1/generate |
Check the template’s ref in the dashboard under PDF templates |
PDF_TEMPLATE_INVALID |
422 | The stored template definition could not be parsed | /v1/generate |
Re-save the template in the dashboard designer; if it persists, email hello@beliq.eu with the x-request-id |
CONVERSION_UNSUPPORTED_PAIR |
422 | The source format is outside the EN 16931 family, or the source PDF carries no embedded invoice XML | /v1/convert |
Check the supported pairs. National formats (FatturaPA, Facturae, KSeF, SDI messaggio) have no cross-format converter |
CONVERSION_LOSSY_FAILCLOSED |
422 | The source carries fields the target cannot represent, so the conversion was refused rather than performed silently. No body is returned | /v1/convert |
Read details.unmappablePaths. For a France CTC Flux 2 code on a UBL target, opt in with ?dropFranceCtcOverlay=true; for a synthesised Peppol endpoint pair there is no opt-in, so use POST /v1/generate. See lossy conversions |
CONVERSION_TOOL_UNAVAILABLE |
503 | A converter the engine needs for this pair is not deployed. Operational, and not expected in production | /v1/convert |
Retry after Retry-After. The quota unit is refunded (see Quota refunds). If it persists, email hello@beliq.eu with the error.incidentId |
CONVERSION_TOOL_ERROR |
500 | The converter ran on this document and exited non-zero | /v1/convert |
Retrying the same bytes fails the same way. The quota unit is refunded. Email hello@beliq.eu with the error.incidentId |
Transmission errors (preview)
| Code | HTTP Status | Meaning | Remediation |
|---|---|---|---|
TRANSMISSION_DISABLED |
503 | Transmission is not enabled on this deployment, so every transmission endpoint refuses the request. | Build and validate the file and deliver it through your own channel. Subscribe for the launch date. |
TRANSMISSION_NO_PROVIDER |
503 | Transmission is enabled, but no provider is currently available for the target network in your key’s mode, so the document would queue with no path forward. | Retry after Retry-After. If it persists, check the status page and email hello@beliq.eu with the error.incidentId value. |
IDEMPOTENCY_KEY_REUSED |
409 | An Idempotency-Key was reused with a different request body. |
Use a fresh key for a different document, or resend the identical body to get the existing transmission back. See Idempotency. |
INVALID_IDEMPOTENCY_KEY |
400 | The Idempotency-Key header is longer than 255 characters or contains something other than printable ASCII. |
Shorten the key and keep it to printable ASCII. A UUID is the usual choice. Rejected before any quota is spent. |
SENDER_NOT_REGISTERED |
403 | The sender identifier is not a registered, active participant of your organization, so you may not send as it. |
Register the identifier and complete the ownership check before sending as it. The message says whether there is no registration at all or one that is not active yet. |
CONTENT_ALREADY_SENT |
409 | This exact document was already sent to this recipient and that transmission can still arrive, so nothing was queued. details.transmissionId names it. |
Poll the existing transmission. To make retries unambiguous, send an Idempotency-Key. A resend is accepted once the earlier transmission reaches failed, or rejected on a network where a rejection does not burn the invoice number (see FRANCE_INVOICE_NUMBER_BURNED). |
SENDER_COUNTRY_MISSING |
409 | The participant registration you are sending as records no country. Every Peppol envelope carries the sending entity’s country, so the registration cannot send until it is set. | Email hello@beliq.eu to complete the registration. |
RECIPIENT_NOT_ROUTABLE |
400 | The recipient identifier is not in a form the Peppol Network can address. |
A Peppol identifier is a four-digit scheme code and a value, for example 0088:5790000435975. |
DOCUMENT_PARTY_MISMATCH |
400 | The document’s own electronic address for the sender or the recipient names a different party than the request does. details says which role and gives both identifiers. |
Make the document and the request agree. The EndpointID in the invoice must be the participant you are sending as, and the one you are sending to. |
FRENCH_DOMESTIC_FLOW |
409 | Sender and recipient are both French, so this is a regulated domestic flow under the French B2B reform and must reach the network through a plateforme agréée rather than over Peppol. details gives both canonical identifiers. Not a document defect: the invoice may be perfectly valid. |
Email hello@beliq.eu to enable the French transmission lane. A French sender can still reach a non-French recipient over Peppol. |
FRANCE_CTC_BLOCKING_FINDINGS |
422 | The document trips one or more BR-FR-CTC Flux 2 rules. A plateforme agréée refuses a document carrying any of them whatever severity the rule pack assigns, so Beliq refuses before the send spends the invoice number. details.ruleIds lists them. Note that POST /v1/validate can report valid: true for the same document: the French pack flags most of these rules as warnings, and franceCtcBlockingRuleIds on the validation result is the field that answers for transmission. |
Correct what the listed rules point at and send again. Validate first with POST /v1/validate and check franceCtcBlockingRuleIds is absent. |
FRANCE_CTC_NOT_JUDGED |
422 | The document was not judged against the French CTC rules at all, so Beliq holds no verdict it can stand behind for a plateforme agréée. Almost always this is a missing BT-23 cadre de facturation, which is also what keeps BR-FR-08 — the rule that would have reported it — from running. |
Add BT-23 from the closed cadre list, or declare the EXTENDED-CTC-FR profile in BT-24. See France. |
FRANCE_INVOICE_NUMBER_BURNED |
409 | A plateforme agréée already rejected this exact document. A French invoice number is unique on (number, supplier SIREN, invoice year) and a rejected invoice must be reissued under a new number, so Beliq refuses the resend rather than queue a second document under a spent one. details.transmissionId names the rejected transmission. |
Issue a corrected invoice under a new number and send that. Do not retry the same bytes: the platform’s own uniqueness check does not stop the reuse, which is why this one is on Beliq’s side. |
UNSUPPORTED_SYNTAX |
400 | Only UBL and CII documents can be sent over Peppol. | Convert the document first: see POST /v1/convert. |
MISSING_CUSTOMIZATION_ID |
400 | The document carries no CustomizationID, so its Peppol document type identifier cannot be derived and no receiving Access Point can be looked up. |
Add the CustomizationID for the profile you are sending, for example urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0. |
MISSING_PROCESS_ID |
400 | The document carries no ProfileID (UBL) or business process identifier (CII), so its Peppol process identifier cannot be derived. |
Add it, for example urn:fdc:peppol.eu:2017:poacc:billing:01:1.0. |
MALFORMED_DOCUMENT |
400 | The document is not well-formed XML, or it declares a DOCTYPE. | Fix the XML. A DOCTYPE is refused outright: no valid e-invoice declares one. |
EMPTY_DOCUMENT |
400 | The document body is empty. | Send the invoice XML in the request body. |
INBOX_UNKNOWN_PROVIDER |
404 | An inbound network callback referenced a provider that is not registered. | Provider-side authentication error, not reachable with an API key. |
INBOX_VERIFICATION_FAILED |
401 | An inbound network callback or document failed signature verification. | Provider-side authentication error, not reachable with an API key. |
INBOX_SIGNATURE_EXPIRED |
401 | An inbound network callback carried a valid signature whose timestamp fell outside the accepted freshness window, so it is refused as a replay. | Provider-side authentication error, not reachable with an API key. |
HTTP status code summary
| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request: invalid JSON, missing required fields, or unsupported format combination |
| 401 | Unauthorized: no API key or invalid key format |
| 403 | Forbidden: API key is revoked or does not exist, or you may not send as the sender identifier (transmission, preview) |
| 404 | Not found: a referenced resource (e.g. a pdfTemplateId) does not exist in your organization |
| 409 | Conflict: an Idempotency-Key was reused with a different body, or the same document was already sent to that recipient (transmission, preview) |
| 413 | Payload too large: the request body exceeds the endpoint’s size limit. The body is not read, so no validation runs |
| 415 | Unsupported media type: the Content-Type is not one this route accepts. /v1/validate, /v1/parse and /v1/convert take application/xml, text/xml, application/octet-stream or application/pdf; the free public demo is narrower still and takes XML only |
| 422 | Unprocessable entity: input is syntactically valid but fails business rules or parsing |
| 429 | Too many requests: quota exceeded or rate limited |
| 500 | Internal server error |
| 503 | Service unavailable: engine is temporarily down, or transmission is not enabled |
Request size limits
Each endpoint caps the size of the request body. The cap is enforced before the body is read, so an oversize request is refused without being parsed or validated, and it never spends a quota unit.
| Endpoint | Limit |
|---|---|
POST /v1/validate |
1 MB |
POST /v1/parse |
1 MB |
POST /v1/generate |
1 MB |
POST /v1/convert |
1 MB |
POST /v1/send (preview) |
1 MB |
POST /v1/receive (preview) |
1 MB |
POST /v1/transmissions (preview) |
5 MB |
POST /v1/inbox/:providerId (preview) |
5 MB |
Exceeding the limit returns 413 with code VALIDATION_ERROR:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Request body exceeds the size limit of 1 MB for this endpoint. The body was not read, so this is not a validation failure. Send a smaller document."
}
}The code is the coarse class tag shared by every 4xx that is not one of the
specific codes above; the 413 status is the discriminator. Read the status,
not the code, to tell an oversize body from a schema failure.
Quota refunds on a Beliq-side failure
When a request fails for a reason on our side rather than in your document, the quota unit that request spent goes back. That covers every ENGINE_UNAVAILABLE (503), and the conversion-tool failures on /v1/convert (CONVERSION_TOOL_UNAVAILABLE, CONVERSION_TOOL_ERROR). It does not cover a 4xx that names something in your document: that is an answer you asked for, and it keeps its unit.
Every response that refunds, or should have, says so on the x-beliq-quota-refunded header:
| Header | Meaning |
|---|---|
true |
The unit went back. A retry costs you nothing. |
false |
The unit was not returned. See the cap below. |
| absent | No live unit was at stake (a successful call, a document error, or a test-key request, which meters against the sandbox allowance instead). |
Refunds are unconditional for the failures where nothing was computed: an unreachable engine, a shed request, a missing conversion tool. Where a failure did consume engine compute — a timeout, or a fault raised part-way through processing — refunds are capped at 50 per organization per clock hour. The cap exists so a deliberately expensive document cannot be run repeatedly at no cost; normal traffic through a real incident stays well under it. If you see x-beliq-quota-refunded: false on volume you consider legitimate, email hello@beliq.eu with the error.incidentId and we will reconcile it.
VALIDATION_ERROR details
A VALIDATION_ERROR raised by JSON schema validation carries details.fields, one entry per rejected constraint. This is the 400 on POST /v1/generate; the other statuses that share the code (413, 415, and any other 4xx with no more specific code) reject before or outside the schema and carry no details at all.
| Field | Type | Description |
|---|---|---|
path |
string | Where the constraint failed. A JSON Pointer into the request body (/invoice/lines/0/unitPrice), except for a property missing at the top level, where it is the bare property name (standard) |
message |
string | The constraint in words, relative to path (must have required property 'number', must be number) |
keyword |
string | The JSON Schema keyword that rejected it (required, type, const, anyOf, minimum) |
A missing nested property reports the parent object as path and names the child in message, so { "standard": "xrechnung", "output": "xml", "invoice": { "issueDate": "2026-04-13" } } answers:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "body/invoice must have required property 'number'",
"details": {
"fields": [
{
"path": "/invoice",
"message": "must have required property 'number'",
"keyword": "required"
}
]
}
}
}One bad value can produce several entries. A standard outside the accepted set is checked against each allowed value in turn, so it yields one const entry per candidate plus a closing anyOf entry, all of them on the same path. Read fields as the list of constraints that failed, not as a list of distinct problems, and key your own error reporting on path.
INVALID_INVOICE details
INVALID_INVOICE includes a full validationResult in details, matching the validation result from /v1/validate:
{
"success": false,
"error": {
"code": "INVALID_INVOICE",
"message": "Invoice validation failed with 1 error",
"details": {
"validationResult": {
"valid": false,
"format": "cii",
"schematronVersion": "1.3.16",
"ciusVersion": "XRechnung-2.6.0",
"errors": [
{
"ruleId": "BR-DE-15",
"severity": "error",
"location": "/rsm:CrossIndustryInvoice",
"message": "An XRechnung invoice must contain a buyer reference (BT-10)."
}
],
"warnings": []
}
}
}
}PROFILE_STANDARD_MISMATCH details
PROFILE_STANDARD_MISMATCH includes the rejected combination so you can correct the request:
{
"success": false,
"error": {
"code": "PROFILE_STANDARD_MISMATCH",
"message": "Profile 'extended' is not allowed for standard 'peppol-bis'.",
"details": {
"standard": "peppol-bis",
"profile": "extended",
"allowedProfiles": ["peppol"]
}
}
}DOCUMENT_TYPE_STANDARD_MISMATCH details
DOCUMENT_TYPE_STANDARD_MISMATCH is returned when documentType: "creditnote" is sent for a standard that only supports invoices — notably fatturapa and facturae. The four EN 16931 hybrid/XML routes peppol-bis, facturx, xrechnung, and zugferd accept CreditNotes, as does the national eslog route (document type code 381 on the same e-SLOG message). Inspect creditNoteCapableStandards in error details; it mirrors the deployed engine capability set.
{
"success": false,
"error": {
"code": "DOCUMENT_TYPE_STANDARD_MISMATCH",
"message": "documentType='creditnote' is not supported for standard 'fatturapa'. Accepted for CreditNote payloads: ['eslog', 'facturx', 'peppol-bis', 'xrechnung', 'zugferd'].",
"details": {
"standard": "fatturapa",
"documentType": "creditnote",
"creditNoteCapableStandards": ["eslog", "facturx", "peppol-bis", "xrechnung", "zugferd"]
}
}
}PDF template errors
These are returned only when a pdfTemplateId is referenced on POST /v1/generate. Stored templates are designed in the dashboard and are scoped to your organization, so they require an authenticated request.
| Code | When | Fix |
|---|---|---|
PDF_TEMPLATE_AUTH_REQUIRED |
pdfTemplateId sent on an unauthenticated request |
Use your API key, or switch to template: "standard" |
PDF_TEMPLATE_NOT_FOUND |
The ref is not a template in your organization | Verify the ref in the dashboard |
PDF_TEMPLATE_INVALID |
The stored definition is corrupt and cannot be rendered | Re-save the template in the designer |
{
"success": false,
"error": {
"code": "PDF_TEMPLATE_NOT_FOUND",
"message": "PDF template k3d-9mp was not found."
}
}Request ID and incident ID
Every API response includes an x-request-id header (UUID). Quote it to hello@beliq.eu for faster troubleshooting.
x-request-id: 7f3d2a1b-4e5c-6d7f-8a9b-0c1d2e3f4a5bServer-side failures (HTTP 500 and 503) additionally carry an error.incidentId in the response body. It links the response directly to the captured error event on our side, so quoting it in a support request is the fastest path to a diagnosis:
{
"success": false,
"error": {
"code": "ENGINE_UNAVAILABLE",
"message": "The e-invoice processing service is temporarily unavailable. Please try again shortly.",
"incidentId": "V7mKp2XwQd"
}
}