Invoices

The invoice, its validation report and a signed manifest, as one ZIP

An evidence bundle: what to keep with an invoice and hand to a tax adviser. The response is application/zip holding the invoice XML; the Factur-X / ZUGFeRD PDF (EN 16931 profile) when one was generated (?format=pdf) or sent; validation-report.json (every finding — uncapped — with the engine version, the rule set's provenance and the time); validation-report.html (the same report, readable offline: it loads nothing from the network); manifest.json (every other file's name, size and SHA-256, the engine version, the time and the signing key id); manifest.sig (an Ed25519 signature over the exact bytes of manifest.json, checkable against GET /.well-known/attestwire-signing-keys.json); and README.txt (what the bundle is for and how to check it). The entries are stored, not compressed, so any unzip reads them.

TWO KINDS OF BODY, chosen by content-type exactly as on /v1/validate. application/json is the invoice as for /v1/generate — alone, or in the {"invoice": …, "pdf": {…}} wrapper — and is validated and generated; with ?format=pdf and profile facturx-en16931 the bundle also holds the PDF, drawn with the same options and watermarked on the free plan exactly as /v1/generate draws it. application/xml, text/xml, application/pdf or application/octet-stream is an invoice document you already have, read by the same reader as /v1/validate: the XML goes into the bundle byte for byte as sent, and a Factur-X or ZUGFeRD PDF goes in as sent with its attached XML beside it.

ONLY A CLEAN INVOICE IS BUNDLED. An invoice or document with a fatal finding is a 422 carrying the ValidationResult the other endpoints give, and costs nothing. One document is charged when the bundle comes back.

UNSIGNED WHEN NO KEY IS CONFIGURED. A deployment without a signing key still makes the bundle, with no manifest.sig, "signature": null in the manifest, a README that says so, and Attestwire-Signature: none.

The report records an automated check: it is not a certification of compliance, not a guarantee of acceptance, and not legal or tax advice, and it says so in its statement.

post/v1/bundle

Request

  • Base URL: https://api.attestwire.com
  • URL: https://api.attestwire.com/v1/bundle
  • Auth: HTTP bearer

Query parameters

format'xml' | 'pdf'

xml (the default): the bundle holds the XML. pdf: it also holds the Factur-X / ZUGFeRD PDF — JSON bodies with profile facturx-en16931 only, as on /v1/generate. A document is bundled as it was sent, so pdf with a document body is a 400.

language'en' | 'de' | 'fr'

The language of the page: its labels, and the way it formats numbers and dates. Default: the seller country's — DE and AT German, FR French, anything else English. The invoice's own text (names, descriptions, notes) and the embedded XML are the same in every language. Query parameter: language.

?format=pdf only: the language PDF option, as on /v1/generate. The language of the page: its labels, and the way it formats numbers and dates. Default: the seller country's — DE and AT German, FR French, anything else English. The invoice's own text (names, descriptions, notes) and the embedded XML are the same in every language. Query parameter: language.

payment_qrboolean

The EPC payment QR code ("GiroCode"), printed beside the payment details so a banking app can fill in the transfer: payee, IBAN, amount due and reference. Default: printed whenever the invoice can carry one — currency EUR, payment means 30, 42 or 58 (credit transfer), a valid IBAN, an amount due from 0.01 EUR, and not a credit note — and left out otherwise. false leaves it out; true requires it, and an invoice that cannot carry it is then a 400 that says why. The reference in the code is the payment reference (BT-83), or else the invoice number. Query parameter: payment_qr=true|false.

?format=pdf only: the paymentQr PDF option, as on /v1/generate. The EPC payment QR code ("GiroCode"), printed beside the payment details so a banking app can fill in the transfer: payee, IBAN, amount due and reference. Default: printed whenever the invoice can carry one — currency EUR, payment means 30, 42 or 58 (credit transfer), a valid IBAN, an amount due from 0.01 EUR, and not a credit note — and left out otherwise. false leaves it out; true requires it, and an invoice that cannot carry it is then a 400 that says why. The reference in the code is the payment reference (BT-83), or else the invoice number. Query parameter: payment_qr=true|false.

payment_linkstring uri

An https:// address where the invoice can be paid online, such as a payment page from your payment provider. It is printed under the payment details and is clickable in the PDF (a link annotation, which PDF/A permits; no script). At most 500 characters, no user name or password. It is on the page only: EN 16931 has no field for it, so the embedded XML does not carry it. Query parameter: payment_link (URL-encoded).

?format=pdf only: the paymentLink PDF option, as on /v1/generate. An https:// address where the invoice can be paid online, such as a payment page from your payment provider. It is printed under the payment details and is clickable in the PDF (a link annotation, which PDF/A permits; no script). At most 500 characters, no user name or password. It is on the page only: EN 16931 has no field for it, so the embedded XML does not carry it. Query parameter: payment_link (URL-encoded).

max_charactersinteger

Raise the XML reader's character cap for this one request, up to 16,000,000. The default is the engine's 8,000,000 and is unchanged for any request that does not ask.

THE CASE THIS EXISTS FOR is a document carrying a base64-embedded attachment (BG-24, EmbeddedDocumentBinaryObject): base64 spends four characters per three bytes, so a 300 kB PDF inside an otherwise ordinary invoice clears the default on the attachment alone.

Asking for it also raises the body ceiling of an application/xml or text/xml request from 1 MB to 32 MB — a raise the bytes cannot get through is not a raise. The two ceilings are independent and whichever you meet first refuses the request. For a PDF it raises the cap on the XML attached to it, as far as the 4 MB the reader takes out of one PDF, and leaves the PDF's own 10 MB ceiling where it is.

The depth, element and attribute caps do NOT move, and that is what makes this safe: the element cap bounds the parsed tree whatever the character count. A value above the ceiling, or one that is not a positive whole number, is a 400 — the number you ask for is never quietly clamped. Ignored on an application/json request, which has no document reader to configure.

Request body

OR

Example request

{
  "currency": "EUR",
  "invoiceTypeCode": "380",
  "seller": {
    "vatId": "DE123456789",
    "address": {
      "countryCode": "DE"
    },
    "electronicAddress": {
      "schemeId": "9930"
    }
  },
  "buyer": {
    "vatId": "DE123456789",
    "address": {
      "countryCode": "DE"
    },
    "electronicAddress": {
      "schemeId": "9930"
    }
  },
  "taxRepresentative": {
    "address": {
      "countryCode": "DE"
    }
  },
  "lines": [
    {
      "unitCode": "C62",
      "itemClassifications": [
        {
          "schemeId": "TST"
        }
      ]
    }
  ],
  "payment": {
    "meansCode": "58"
  },
  "declaredTotals": {
    "defects": [
      {
        "field": "BT-115"
      }
    ],
    "overPrecise": [
      {
        "field": "BT-131"
      }
    ]
  }
}

Response

The bundle. Content-Disposition names it <invoice number>-evidence.zip.

Changes

No recorded changes to this operation across all 1 revision of this API.