Automation MCP Server Blog Pricing Contact

Embed and Email ZUGFeRD API Reference

Embed your CII XML into your own PDF as ZUGFeRD and email the result to your customer from your own domain, in one call. The request takes the same pdf and xml parts as POST /v1/embed/zugferd, plus the email.* form fields. The XML is always validated with the full rule set before anything is embedded, and only an invoice that passes is sent, as the ZUGFeRD PDF/A-3 made from your PDF and your XML, from an address on your verified sending domain such as [email protected].

POST /v1/embed/zugferd/email

Set up your sending domain first

Invoices go out from your own domain, so your customers see your address and their replies reach you. Set the domain up once:

  1. Open Verified email domains in your dashboard and add your domain, or a subdomain such as mail.yourcompany.com.
  2. Publish the three CNAME (DKIM) records it shows at your DNS provider. On Cloudflare, set the proxy status of each record to DNS only.
  3. Wait until the status shows Verified. This usually takes a few minutes and can take up to 72 hours. From then on you can send from any address on that domain.

The pricing page lists the plans that include email delivery and how many sending domains each one has.

Code Example

curl -X POST https://api.invoicexml.com/v1/embed/zugferd/email \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "email.fromName=Acme Billing" \
  -F "[email protected]" \
  -F "[email protected]"

The pdf and xml parts are the same as on POST /v1/embed/zugferd; the email.* fields say who sends and who receives the invoice. Subject and message are left out here, so the defaults below are used.

Request

Parameter Type Description
pdf * binary The PDF to embed the XML into, exactly as on POST /v1/embed/zugferd.
xml * binary The CII XML invoice, exactly as on POST /v1/embed/zugferd, including the accepted profiles. Its invoice number (BT-1) and type code (BT-3) name the email and the attachment.
validationLanguage string Optional. Language of the finding messages when the XML is rejected: en (default), de or fr. See localized error messages.
email.* * string The email that carries the invoice, one form field per value. See Email fields below.

Content-Type: multipart/form-data

Full validation always runs on this route: there is no skipValidation field, so only an invoice that passes its rules is embedded and sent.

Email fields

Send each value as its own form field. For a second cc or bcc address, repeat the field.

Field Type Description
email.from * string The sender address, for example [email protected]. Any address on one of your verified sending domains.
email.fromName string Optional display name of the sender, for example Acme Billing. At most 100 characters, no line breaks.
email.to * string The recipient's email address. Exactly one address.
email.cc string, repeatable Optional addresses that receive a visible copy, for example your accounting inbox. cc and bcc hold at most 2 addresses together.
email.bcc string, repeatable Optional addresses that receive a hidden copy. cc and bcc hold at most 2 addresses together.
email.replyTo string Optional address the recipient's replies go to, when it differs from the sender, for example your accounts receivable team. Any domain.
email.subject string Optional subject, at most 200 characters, no line breaks. See Defaults for the subject used when it is left out.
email.message string Optional plain-text message, at most 10,000 characters, sent exactly as you write it, line breaks included, in any language. See Defaults.

A field that breaks one of these rules is answered with a 400 (errorCode 4002) before the invoice is embedded, and nothing is sent or billed.

Defaults

The number in the subject, the message and the attachment name comes from the invoice number (BT-1) and type code (BT-3) of the uploaded XML. Type codes 381 and 261 are credit notes and get the credit note wording.

Part Invoice Credit note
Subject, when left out Invoice 2026-0042 Credit note 2026-0042
Message, when left out Hello,

Please find attached invoice 2026-0042.

Kind regards
Hello,

Please find attached credit note 2026-0042.

Kind regards
Attachment, always invoice-2026-0042.pdf credit-note-2026-0042.pdf

The attachment is the ZUGFeRD PDF/A-3 made from your PDF and your XML. Characters that are not allowed in file names, such as the slash in 2026/0042, become a dash, so that number is attached as invoice-2026-0042.pdf.

The defaults are in English. To write to your customers in German, French or any other language, send your own subject and message. Both are sent exactly as given, so put the invoice number, amount or due date into the text yourself:

  -F "email.subject=Invoice 2026-0042 for October" \
  -F $'email.message=Hello Anna,\n\nyour invoice for October is attached.\n\nBest regards\nAcme Billing'

Headers

Header Value
Authorization * Bearer YOUR_API_KEY
Content-Type multipart/form-data

Response

200 Email accepted

The invoice was embedded, validated and handed over for delivery. accepted does not yet mean that the recipient's mail server has received it. Keep the messageId: it identifies this email when you ask us about a delivery later. The invoice file travels in the email, not in the response.

{
  "status": "accepted",
  "messageId": "0100019a2f4c8e1b-3d7a9c52-6e1f-4b8d-a2c3-5f9e7d1b4a60-000000"
}

400 Email field error

An email field is wrong, here a sender on a domain the account has not added. The finding points at the field; nothing was embedded, sent or billed.

{
  "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 1 error(s).",
  "errors": [
    {
      "rule": null,
      "layer": null,
      "line": null,
      "message": "The sender domain yourcompany.com is not one of this account's sending domains. Add it on the Verified email domains page of your dashboard first.",
      "btCodes": [],
      "fields": ["email.from"],
      "raw": null
    }
  ],
  "warnings": []
}

Error Reference

Every error uses the usual RFC 7807 envelope described on the status codes page, and no error sends an email. Errors of the invoice itself behave exactly as on POST /v1/embed/zugferd.

errorCode Status Meaning
4001 400 The uploaded XML fails its validation rules, exactly as on the plain endpoint. The findings are in errors.
4002 400 A request field is wrong. Invoice fields behave as on the plain endpoint. For the email fields: a sender domain not added to your account, an invalid address, more than 2 cc and bcc addresses together, a subject or display name with a line break, or a value that is too long. The findings point at email.from, email.to and so on.
4020 403 Your plan does not include email delivery. Checked on every call. Compare plans.
4021 403 Email sending is switched off or paused for your account. Contact [email protected].
4022 400 The sender's domain has not finished verification yet. Check its status on Verified email domains and send again once it shows Verified.
4019 429 Too many emails at once, or too many requests in progress. Nothing was sent or billed: wait the number of seconds in the Retry-After header and send the same request again.

The other errors of the plain embed endpoint, for example 4017 for a profile identifier outside the specification, apply unchanged.

Billing

One credit per successful call, like every other endpoint. Not billed: calls refused because your plan does not include email (4020), sending is switched off (4021) or an email field is wrong (4002 on email.*), and sends that fail at delivery because the domain is not verified yet (4022), sending is paused (4021) or too many emails are going out at once (4019). Invoice validation errors are billed exactly as on POST /v1/embed/zugferd.

Need the file in the response instead?

POST /v1/embed/zugferd builds the same PDF and returns it directly, for your own delivery or archive.

Embed XML in ZUGFeRD API

Frequently Asked Questions

Which address can I send from?

Any address on one of your verified sending domains, for example [email protected] or [email protected]. Add the domain (or a subdomain) on the Verified email domains page of your dashboard and publish the three DNS records it shows.

What does "accepted" mean?

The email was handed over for delivery. It does not yet mean that the recipient's mail server has received it. Keep the messageId from the response: it identifies the email when you ask us about a delivery later.

Is the invoice checked before it is sent?

Yes, always. The uploaded XML runs through the full rule set of POST /v1/embed/zugferd before anything is embedded, and the email routes have no skipValidation field. An invoice with errors is answered with a 400 and its findings, and no email is sent.

What is billed?

One credit per successful call, like every other endpoint. A call refused because the plan does not include email (4020), sending is switched off (4021) or an email field is wrong (4002 on email.*) is not billed, and neither is a send that fails at delivery: domain not verified (4022), sending paused (4021) or too many emails at once (4019). Invoice validation errors are billed exactly as on the plain endpoint.

Can I write to my customers in German or French?

Yes. The subject and message are sent exactly as you give them, in any language. Only the defaults used when you leave them out are English, so send your own subject and message to write in another language.

Is the email stored?

InvoiceXML keeps no copy of the attached invoice or of your subject and message. The message id is listed with the call in your API logs. If an email bounces or the recipient marks it as spam, that recipient address is kept so it is not emailed again.