Invoices

E-mail one validated invoice to one recipient

Attestwire sends invoices by e-mail on request; it does not operate Peppol or French-platform transmission. This generates an invoice — or takes one you already have — checks it, and e-mails it to one address through Resend (resend.com): one invoice per message, attached under its invoice number, with a subject and a short note in the invoice's language ("Rechnung {nr} von {seller}", "Facture {nr} de {seller}", "Invoice {nr} from {seller}").

WHAT IS SENT. invoice with format: "xml" sends the XML of its profile (XRechnung UBL for xrechnung-ubl); format: "pdf" sends the Factur-X / ZUGFeRD PDF (EN 16931 profile), profile facturx-en16931 only, drawn with the pdf options exactly as /v1/generate draws it. document is a file you already have, as base64 — XML, or a Factur-X or ZUGFeRD PDF — read by the reader /v1/validate uses and attached byte for byte as sent. Nothing with a fatal finding is sent: that is a 422 with the ValidationResult.

WHO IT IS FROM. From is this deployment's sender address, displayed as "{seller} via Attestwire". Reply-To is the seller's contact e-mail (BT-43), so the invoice must carry one (400 seller_email_required). The language is language if named, else the PDF page's, else the seller country's: DE and AT German, FR French, anything else English.

THE FREE PLAN IS A TEST MODE: it sends only to the address the key was registered with (403 recipient_not_allowed otherwise), every message is marked "[TEST]" and says it is not a request for payment, and a PDF is the watermarked preview. The paid plans (Solo, Starter, Scale) send to anyone.

LIMITS. 10 messages per key per UTC day on the free plan and 500 on a paid plan (429 send_limit_exceeded); a ceiling on the deployment's sends per UTC day across all keys, 50 unless it sets another, because the mail account is shared (429 send_capacity_exceeded, which says when it resets); both with Retry-After until 00:00 UTC. Then the per-second pace limit, and an attachment of at most 7 MB, so the message stays under the 10 MB many receiving mail servers accept.

CHARGED once the mail service has accepted the message: one document. Every refusal costs nothing, and nothing is retried on your behalf. The answer is 202 Accepted, because acceptance is all Attestwire learns: Accepted by the mail service, which delivers it and retries on its own. Attestwire is not told whether it was delivered, bounced or marked as spam, and does not store the message: keep attachment.sha256 and message_id as your record of what was sent, and ask the recipient to confirm receipt if you need to know. A retry after a timeout can send the invoice twice. Nothing about the message is stored by Attestwire; Resend processes it to deliver it and keeps its own delivery logs. Each message carries the header X-Attestwire-Account with the sending key's 8-character fingerprint, so an abuse report can be traced to the key.

A deployment without e-mail configured answers 503 email_not_enabled, before authentication.

post/v1/send

Request

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

Request body

tostring email required

One plain address, no display name. On the free plan it must be the address the key was registered with.

format'xml' | 'pdf'

Required with invoice: xml sends the XML of its profile, pdf the Factur-X / ZUGFeRD PDF (profile facturx-en16931 only). Refused with document, which is sent as what it is.

documentstring byte

An invoice document you already have — XML, or a Factur-X or ZUGFeRD PDF — as base64. At most 7 MB once decoded. Read and judged as /v1/validate reads a document, and attached byte for byte. Not with invoice.

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

The language of the subject and the note. Default: the language of the attached PDF's page, when a PDF is attached, else the seller country's (DE and AT German, FR French, anything else English).

Example request

{
  "invoice": {
    "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 mail service accepted the message. Not a delivery receipt: see delivery.

status'accepted' required
message_idstring required

The mail service's id for the message.

tostring email required
reply_tostring email required

The seller's contact e-mail (BT-43).

subjectstring required
language'en' | 'de' | 'fr' required
test_modeboolean required

A free key's message: sent to its own address and marked as a test.

source'generated' | 'document' required

generated from invoice, or a document sent as it came.

format'xml' | 'pdf' required
profilestring nullable required

The profile the invoice was judged under.

deliverystring required

Accepted by the mail service, which delivers it and retries on its own. Attestwire is not told whether it was delivered, bounced or marked as spam, and does not store the message: keep attachment.sha256 and message_id as your record of what was sent, and ask the recipient to confirm receipt if you need to know.

Example response

{
  "warnings": [
    {
      "rule": "BR-DE-15",
      "field": "BT-10",
      "location": {
        "attachment": "factur-x.xml"
      }
    }
  ],
  "information": [
    {
      "rule": "BR-DE-15",
      "field": "BT-10",
      "location": {
        "attachment": "factur-x.xml"
      }
    }
  ],
  "findings_truncated": {
    "total": 20012,
    "returned": 500,
    "cap": 500
  },
  "provenance": {
    "engine": "@attestwire/en16931",
    "engine_version": "0.14.1",
    "ruleset": "en16931@0.14.1",
    "profile": "xrechnung-ubl",
    "kosit_conformance": {
      "recorded": "2026-09-24",
      "validator": "1.6.3",
      "configuration": "3.0.2",
      "configuration_published": "2026-08-31"
    }
  }
}

Changes

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