Automation MCP Server Features Blog Pricing Contact

Error Handling

Every failed request returns a structured JSON error you can act on programmatically. This page covers the response envelope, the error categories, and how to handle them in code.

One envelope for every error. Whichever endpoint you call and whatever goes wrong, a failed request always returns the same JSON shape, an RFC 7807 ProblemDetails object. There is no endpoint-specific error parsing to write: read status for the HTTP outcome, branch on errorCode for the category, and you have handled every error the API can return.

The error envelope

Every error response, on every endpoint, contains the same top-level fields:

Field Type Description
type string RFC 7807 type URI for the error class.
title string Short, human-readable summary of the error class.
status int The HTTP status code, repeated in the body for convenience.
errorCode int The InvoiceXML category code. This is the one value to branch on.
detail string Longer human-readable explanation, safe to show to end users.
errors array An array of finding objects, one per validation error. Present on validation failures, and identical in shape whether the failure is XML validation (4001) or model validation (4002).
warnings array Non-blocking findings, same object shape as a 4001 finding. Advisory only, they never cause a request to fail.

Error codes

The errorCode identifies the category of error. Branch on it to decide how to handle the response. The errors column shows what, if anything, the errors field carries for that code.

errorCode Name Description errors
4000 General Error An unclassified processing error. Check title and detail for information. none
4001 XML Validation The invoice XML violates EN 16931 Schematron business rules (e.g. BR-01, BR-CO-15). Each violation is a finding object. errors[]
4002 Model Validation One or more request fields are missing or malformed before processing could start. errors[]
4003 Missing File A multipart endpoint expected a file upload but none was provided. Include the file in the request. none
4004 Unsupported Content Type The uploaded file's content type or extension is not accepted by that endpoint (for example, a non-PDF where a PDF is required). none
4005 File Too Large The uploaded file exceeds the 20 MB size limit. none
4006 No Embedded XML The PDF does not contain an embedded Factur-X / ZUGFeRD XML attachment. Returned by /v1/extract/*, /v1/validate/*, and /v1/convert/* when no XML is present. To read a PDF without embedded XML, use /v1/parse/json. none
4007 PDF Error The PDF could not be processed. It may be corrupted, password-protected, or not a valid invoice PDF. none
4008 Not an Invoice The uploaded document does not appear to be an invoice. Returned by AI-powered endpoints (e.g. /v1/parse/json, /v1/transform/to/*) when classification rejects the input. none
4009 Multiple Invoices The uploaded PDF contains more than one invoice. Split it and resubmit one invoice per file. none
4010 Unauthorized The Authorization header is missing, malformed, or carries an unknown / revoked API key. Re-check the bearer token and retry. none
4011 Remote Fetch Error A pdfUrl supplied to /v1/create/facturx or /v1/create/zugferd could not be fetched: it was not a valid http/https URL, resolved to a blocked address, or the host was unreachable. Used only by the create endpoints' optional pdfUrl input. none

Example responses

The envelope is identical in all of them. Both validation categories (4001 and 4002) use the very same errors array of finding objects, so you handle them with one code path. Every other error code carries no errors field at all.

XML validation, errorCode 4001

The generated or uploaded XML violates EN 16931 Schematron rules. errors is an array of finding objects, one per violated rule.

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Validation Failed",
  "status": 400,
  "errorCode": 4001,
  "detail": "The invoice contains 2 validation error(s).",
  "errors": [
    {
      "rule": "BR-01",
      "layer": "en16931",
      "line": null,
      "message": "The invoice is missing a specification identifier (BT-24).",
      "btCodes": ["BT-24"],
      "fields": ["specificationId"],
      "raw": "[BR-01] EN16931: An invoice shall have a specification identifier."
    },
    {
      "rule": "PEPPOL-EN16931-R010",
      "layer": "cius",
      "line": null,
      "message": "Peppol BIS requires a buyer electronic address. Add the buyer's electronic address (a buyer VAT identifier is used as a fallback), or use the plain en16931 profile if the invoice is not meant for Peppol.",
      "btCodes": ["BT-49"],
      "fields": ["buyer.electronicAddress"],
      "raw": "[PEPPOL-EN16931-R010] CIUS: Buyer electronic address MUST be provided"
    }
  ],
  "warnings": []
}

Each finding is self-describing. Use message for end-user display and raw for debugging or logs. The btCodes and fields arrays let you map a finding back to a form input.

Field Type Description
rule string The validated rule identifier, e.g. BR-01.
layer string | null Validation layer that produced the finding: xsd (structure), en16931 (European core rules), or cius (the profile overlay: Peppol BIS, XRechnung, NLCIUS, PINT, or the Factur-X/ZUGFeRD profile rules). null on 4002 findings, which have no validation layer.
line int | null 1-based invoice line number, or null for a document-level finding.
message string Plain-language explanation, safe to show end users.
btCodes string[] EN 16931 Business Term codes the rule references.
fields string[] Dotted JSON paths into the invoice the finding maps to. Line-scoped paths use a zero-based index (line 3 maps to lines[2]).
raw string Verbatim validator output, including the rule id, layer and XPath location.

Map findings straight to your form.

Key your invoice-form inputs by the same dotted paths (or keep a lookup from BT code to input). On an error response, match each finding's fields or btCodes to the matching input, mark it invalid, and show the friendly message beside it. The user is taken straight to the field that needs fixing, with no XPath decoding.

Model validation, errorCode 4002

A request field is missing or malformed, so processing never started. errors is the exact same flat array of finding objects as 4001. rule, layer and raw are null (model validation has no Schematron rule or validation layer), while btCodes and fields are resolved from the field path, so the finding maps to the offending input by both BT code and JSON path.

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errorCode": 4002,
  "valid": false,
  "detail": "The request failed validation with 2 error(s).",
  "errors": [
    {
      "rule": null,
      "layer": null,
      "line": null,
      "message": "The seller name is required.",
      "btCodes": ["BT-27"],
      "fields": ["seller.name"],
      "raw": null
    },
    {
      "rule": null,
      "layer": null,
      "line": 1,
      "message": "Quantity must be greater than zero.",
      "btCodes": ["BT-129"],
      "fields": ["lines[0].quantity"],
      "raw": null
    }
  ],
  "warnings": []
}

Other errors, errorCode 4000 and 4003 to 4011

Missing-file, unsupported content type, file-size, no-embedded-XML, PDF-processing and remote-fetch errors carry no errors field. The title and detail tell you what happened.

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Missing File",
  "status": 400,
  "errorCode": 4003,
  "detail": "No file was provided in the request."
}
Warnings never fail a request. The warnings array uses the exact same finding shape as 4001 errors, but it is advisory. A response can be successful and still carry warnings. Only entries in errors make a request fail.

Handling errors in code

Parse the JSON body and branch on errorCode. Because both validation categories share the same errors array, they need just one branch between them; every other code falls through to a generic handler.

const response = await fetch(apiUrl, { method: 'POST', body: formData });

if (!response.ok) {
  const problem = await response.json();

  switch (problem.errorCode) {
    case 4001: // XML validation, Schematron rule violations
    case 4002: // Model validation, malformed request fields
      // Both return the same flat array of finding objects.
      problem.errors.forEach(f => {
        const where = f.line != null ? `line ${f.line}` : 'document';
        console.error(`${where}: ${f.message}`);
        // f.fields and f.btCodes map the finding to a form input
      });
      break;

    default: // 4000, 4003 to 4011: no errors array, use title + detail
      console.error(`${problem.title}: ${problem.detail}`);
  }
}