BusinessDocument — Peppol UBL invoice

Send a cross-border PEPPOL invoice (or credit note) via the standard-agnostic BusinessDocument endpoint, in five languages.

The POST /api/v1/documents/business-documents endpoint accepts a standard-agnostic invoice or credit note. Bizzlink’s routing layer then decides the output wire format — PEPPOL BIS UBL, FatturaPA-to-SDI for Italy, XRechnung for German B2G, Factur-X PDF/A-3 — based on the receiver’s PEPPOL participant ID and document type capability lookup. You always send the same JSON; the cloud handles the wire format.

Use this endpoint when you want a single integration that works for any EU recipient. The narrower /documents/invoices endpoint is simpler but limited to UBL-only.

What’s different from /documents/invoices

/documents/invoices/documents/business-documents
Output formatsUBL 2.1 onlyUBL 2.1, FatturaPA, XRechnung, Factur-X (auto-routed)
Document typesInvoice onlyInvoice or CreditNote (polymorphic)
Field modelFlatRich — supports allowances, charges, tax breakdown, country-specific extensions
Use caseQuick start, LU/EU B2BProduction, multi-country, regulated B2G

Request body — Peppol UBL invoice

A minimal-but-PEPPOL-valid invoice from a Luxembourg seller to a Belgian buyer.

How to read this: the @type discriminator inside attributes tells the server which shape this is:

  • "@type": "InvoiceDocument" → server validates as an invoice
  • "@type": "CreditNoteDocument" → server validates as a credit note, requires originalInvoiceNumber + originalInvoiceDate

typeCode carries the semantic subtype (COMMERCIAL_INVOICE, CREDIT_NOTE, CORRECTED_INVOICE, PREPAYMENT_INVOICE, SELF_BILLED_INVOICE, …). It must be consistent with @type — e.g. a CreditNoteDocument with typeCode: COMMERCIAL_INVOICE is rejected.

{
  "data": {
    "type": "business-documents",
    "attributes": {
      "@type": "InvoiceDocument",
      "documentId": "INV-2026-00042",
      "issueDate": "2026-05-05",
      "typeCode": "COMMERCIAL_INVOICE",
      "currency": "EUR",
      "dueDate": "2026-06-04",
      "buyerReference": "PO-7788",
      "paymentTermsText": "Net 30 days",
      "seller": {
        "name": "Vigasoft S.à r.l.-S.",
        "legalRegistrationId": "LU-RCS-B306709",
        "vatId": "LU12345678",
        "electronicAddress": "LU12345678",
        "electronicAddressSchemeId": "9938",
        "address": {
          "street1": "9, rue Marcel Schintgen",
          "city": "Lamadelaine",
          "postCode": "L-4889",
          "countryCode": "LU"
        }
      },
      "buyer": {
        "name": "ACME Belgium SA",
        "vatId": "BE0123456789",
        "electronicAddress": "BE0123456789",
        "electronicAddressSchemeId": "9925",
        "address": {
          "street1": "Avenue Louise 100",
          "city": "Bruxelles",
          "postCode": "1050",
          "countryCode": "BE"
        }
      },
      "delivery": {
        "deliveryDate": "2026-05-04",
        "locationIdentifier": "4025673",
        "locationIdentifierSchemeId": "0088",
        "partyName": "ACME Belgium SA — Warehouse",
        "address": {
          "street1": "Avenue Louise 100",
          "city": "Bruxelles",
          "postCode": "1050",
          "countryCode": "BE"
        }
      },
      "payment": {
        "paymentMeansCode": "SEPA_CREDIT_TRANSFER",
        "remittanceInformation": "INV-2026-00042",
        "accounts": [
          { "iban": "LU000000000000000000", "bic": "BCEELULL", "accountName": "Vigasoft" }
        ]
      },
      "taxBreakdown": [
        {
          "categoryCode": "S",
          "rate": 21.00,
          "taxableAmount": { "amount": 1000.00, "currency": "EUR" }
        }
      ],
      "lines": [
        {
          "id": "1",
          "quantity": 10,
          "unitCode": "C62",
          "netUnitPrice": { "amount": 100.00, "currency": "EUR" },
          "vatCategoryCode": "S",
          "vatRate": 21.00,
          "itemName": "Widget"
        }
      ]
    }
  }
}

Key field reference

FieldPEPPOL BTNotes
@typePolymorphic discriminator. InvoiceDocument or CreditNoteDocument. Must match typeCode.
documentIdBT-1Your document identifier — must be unique per seller
issueDateBT-2Issue date, ISO 8601 (YYYY-MM-DD)
typeCodeBT-3Enum: COMMERCIAL_INVOICE, CREDIT_NOTE, DEBIT_NOTE, CORRECTED_INVOICE, PREPAYMENT_INVOICE, SELF_BILLED_INVOICE (+ construction variants)
currencyBT-5ISO 4217 (EUR, USD, …)
dueDateBT-9Payment due date (invoice only — not applicable to credit notes)
seller.electronicAddressSchemeIdBT-34Peppol EAS code (recommended, e.g. 9938) or the symbolic name. Codes: 9938/LU_VAT, 9930/DE_VAT, 9925/BE_VAT, 0009/FR_SIRET, 0211/IT_IVA, 0210/IT_CFI, 0201/IT_CUUO, 0135/IT_SIA, 0142/IT_SECETI, 0106/NL_KVK, 9920/ES_VAT, 0088/GLN, 0060/DUNS
seller.addressBG-5Fields: street1, street2, additionalStreet, city, postCode, countrySubdivision, countryCode
payment.paymentMeansCodeBT-81Enum: SEPA_CREDIT_TRANSFER, CREDIT_TRANSFER, DEBIT_TRANSFER, BANK_CARD, STANDING_AGREEMENT, etc.
payment.accounts[]BG-17One or more BankAccount (iban, bic, accountName)
lines[].vatCategoryCodeBT-151VatCategoryCode enum: S (standard), Z (zero), E (exempt), AE (reverse charge), K (intra-EU), G (export), O (out-of-scope), L (Canary Islands), M (Ceuta/Melilla)
lines[].vatRateBT-152Tax percentage as a number (e.g. 21.00, not "21")
lines[].unitCodeBT-130UN/ECE Recommendation 20 (C62=piece, HUR=hour, DAY=day, KGM=kg, MTR=meter, LTR=litre, …)
taxBreakdownBG-23One entry per (categoryCode, rate) pair — mandatory for PEPPOL validation. Sum of taxableAmount across breakdown lines must equal sum of line net amounts per (code, rate).

Attaching a PDF

You can embed a binary attachment — e.g. a human-readable PDF rendering of the invoice — alongside the structured data. Each attachment is carried into the wire format as a UBL cac:AdditionalDocumentReference with an EmbeddedDocumentBinaryObject. v1.0 supports PDF only.

Add an attachments array inside attributes (same level as lines):

"attachments": [
  {
    "filename": "invoice-INV-2026-00042.pdf",
    "contentType": "application/pdf",
    "content": "JVBERi0xLjcKJeLjz9MK...<base64-encoded PDF bytes>...",
    "description": "Human-readable invoice"
  }
]
FieldRequiredPEPPOL BTNotes
filenameyesFile name, e.g. invoice-INV-2026-00042.pdf
contentTypeyesMIME type — must be application/pdf in v1.0
contentyesBT-125The file bytes, Base64-encoded
descriptionnoBT-123Optional human-readable text → UBL cbc:DocumentDescription
The same attachments array works identically on a credit note, and across all SDKs — the Java SDK exposes it as .addAttachmentsItem(new Attachment()...).

Code

: "${BIZZLINK_API_TOKEN:?BIZZLINK_API_TOKEN not set}"
: "${BIZZLINK_HMAC_SECRET:?BIZZLINK_HMAC_SECRET not set}"

TIMESTAMP=$(date +%s)
PATH_AND_QUERY="/bizzlink/api/v1/documents/business-documents"
BODY=$(cat <<'EOF'
{
  "data": {
    "type": "business-documents",
    "attributes": {
      "@type": "InvoiceDocument",
      "documentId": "INV-2026-00042",
      "issueDate": "2026-05-05",
      "typeCode": "COMMERCIAL_INVOICE",
      "currency": "EUR",
      "dueDate": "2026-06-04",
      "buyerReference": "PO-7788",
      "paymentTermsText": "Net 30 days",
      "seller": {
        "name": "Vigasoft S.à r.l.-S.",
        "vatId": "LU12345678",
        "electronicAddress": "LU12345678",
        "electronicAddressSchemeId": "9938",
        "address": {
          "street1": "9, rue Marcel Schintgen",
          "city": "Lamadelaine",
          "postCode": "L-4889",
          "countryCode": "LU"
        }
      },
      "buyer": {
        "name": "ACME Belgium SA",
        "vatId": "BE0123456789",
        "electronicAddress": "BE0123456789",
        "electronicAddressSchemeId": "9925",
        "address": {
          "street1": "Avenue Louise 100",
          "city": "Bruxelles",
          "postCode": "1050",
          "countryCode": "BE"
        }
      },
      "payment": {
        "paymentMeansCode": "SEPA_CREDIT_TRANSFER",
        "remittanceInformation": "INV-2026-00042",
        "accounts": [
          { "iban": "LU000000000000000000", "bic": "BCEELULL", "accountName": "Vigasoft" }
        ]
      },
      "taxBreakdown": [
        { "categoryCode": "S", "rate": 21.00,
          "taxableAmount": { "amount": 1000.00, "currency": "EUR" } }
      ],
      "lines": [
        { "id": "1", "quantity": 10, "unitCode": "C62",
          "netUnitPrice": { "amount": 100.00, "currency": "EUR" },
          "vatCategoryCode": "S", "vatRate": 21.00,
          "itemName": "Widget" }
      ]
    }
  }
}
EOF
)

BODY_HASH=$(printf '%s' "${BODY}" | openssl dgst -sha256 -hex | sed 's/^.* //')
SIGNATURE=$(printf '%s' "${TIMESTAMP}.POST.${PATH_AND_QUERY}.${BODY_HASH}" | \
  openssl dgst -sha256 -hmac "${BIZZLINK_HMAC_SECRET}" | sed 's/^.* //')

curl -X POST "https://gateway.vigasoft.lu${PATH_AND_QUERY}" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${BIZZLINK_API_TOKEN}" \
  -H "X-Bizzlink-Signature: t=${TIMESTAMP},v1=${SIGNATURE}" \
  -d "${BODY}"
// Maven: lu.vigasoft:bizzlink-sdk-java:0.3.1
// The SDK adds the JSON:API envelope and the "@type" discriminator for you.
import lu.vigasoft.bizzlink.sdk.BizzlinkClient;
import lu.vigasoft.bizzlink.sdk.requests.CreateAndSendBusinessDocumentRequest;
import lu.vigasoft.bizzlink.api.DocumentApi;
import lu.vigasoft.bizzlink.model.*;
import java.time.LocalDate;
import java.math.BigDecimal;

try (BizzlinkClient client = BizzlinkClient.builder()
        .apiToken(System.getenv("BIZZLINK_API_TOKEN"))
        .hmacSecret(System.getenv("BIZZLINK_HMAC_SECRET"))
        .build()) {

    var response = client.api(DocumentApi::new).createAndSendBusinessDocument(
        CreateAndSendBusinessDocumentRequest.forInvoice(inv -> inv
            .documentId("INV-2026-00042")
            .issueDate(LocalDate.of(2026, 5, 5))
            .typeCode(InvoiceDocument.TypeCodeEnum.COMMERCIAL_INVOICE)
            .currency(CurrencyCode.EUR)
            .dueDate(LocalDate.of(2026, 6, 4))
            .buyerReference("PO-7788")
            .paymentTermsText("Net 30 days")
            .seller(new Party()
                .name("Vigasoft S.à r.l.-S.")
                .vatId("LU12345678")
                .electronicAddress("LU12345678")
                .electronicAddressSchemeId(EndpointSchemeId.LU_VAT)
                .address(new Address()
                    .street1("9, rue Marcel Schintgen")
                    .city("Lamadelaine")
                    .postCode("L-4889")
                    .countryCode(CountryCode.LU)))
            .buyer(new Party()
                .name("ACME Belgium SA")
                .vatId("BE0123456789")
                .electronicAddress("BE0123456789")
                .electronicAddressSchemeId(EndpointSchemeId.BE_VAT)
                .address(new Address()
                    .street1("Avenue Louise 100").city("Bruxelles")
                    .postCode("1050")
                    .countryCode(CountryCode.BE)))
            .payment(new PaymentInfo()
                .paymentMeansCode(PaymentMeansCode.SEPA_CREDIT_TRANSFER)
                .remittanceInformation("INV-2026-00042")
                .addAccountsItem(new BankAccount()
                    .iban("LU000000000000000000")
                    .bic("BCEELULL")
                    .accountName("Vigasoft")))
            .addTaxBreakdownItem(new TaxBreakdown()
                .categoryCode(VatCategoryCode.S)
                .rate(new BigDecimal("21.00"))
                .taxableAmount(new Money().amount(new BigDecimal("1000.00")).currency(CurrencyCode.EUR)))
            .addLinesItem(new LineItem()
                .id("1")
                .quantity(new BigDecimal("10"))
                .unitCode(UnitCode.C62)
                .netUnitPrice(new Money().amount(new BigDecimal("100.00")).currency(CurrencyCode.EUR))
                .vatCategoryCode(VatCategoryCode.S)
                .vatRate(new BigDecimal("21.00"))
                .itemName("Widget"))));

    System.out.println("Document ID: " + response.getData().getId());
}
import hashlib
import hmac
import json
import os
import time
import requests

API_BASE       = "https://gateway.vigasoft.lu"
PATH_AND_QUERY = "/bizzlink/api/v1/documents/business-documents"
API_TOKEN      = os.environ["BIZZLINK_API_TOKEN"]
HMAC_SECRET    = os.environ["BIZZLINK_HMAC_SECRET"]

invoice = {
    "data": {
        "type": "business-documents",
        "attributes": {
            "@type": "InvoiceDocument",
            "documentId": "INV-2026-00042",
            "issueDate":  "2026-05-05",
            "typeCode":   "COMMERCIAL_INVOICE",
            "currency":   "EUR",
            "dueDate":    "2026-06-04",
            "buyerReference":    "PO-7788",
            "paymentTermsText":  "Net 30 days",
            "seller": {
                "name":  "Vigasoft S.à r.l.-S.",
                "vatId": "LU12345678",
                "electronicAddress":         "LU12345678",
                "electronicAddressSchemeId": "9938",
                "address": {
                    "street1": "9, rue Marcel Schintgen",
                    "city":    "Lamadelaine",
                    "postCode":    "L-4889",
                    "countryCode": "LU",
                },
            },
            "buyer": {
                "name":  "ACME Belgium SA",
                "vatId": "BE0123456789",
                "electronicAddress":         "BE0123456789",
                "electronicAddressSchemeId": "9925",
                "address": {
                    "street1": "Avenue Louise 100",
                    "city":    "Bruxelles",
                    "postCode": "1050",
                    "countryCode": "BE",
                },
            },
            "payment": {
                "paymentMeansCode":      "SEPA_CREDIT_TRANSFER",
                "remittanceInformation": "INV-2026-00042",
                "accounts": [
                    {"iban": "LU000000000000000000", "bic": "BCEELULL", "accountName": "Vigasoft"},
                ],
            },
            "taxBreakdown": [{
                "categoryCode": "S",
                "rate":         21.00,
                "taxableAmount": {"amount": 1000.00, "currency": "EUR"},
            }],
            "lines": [{
                "id":       "1",
                "quantity": 10,
                "unitCode": "C62",
                "netUnitPrice":    {"amount": 100.00, "currency": "EUR"},
                "vatCategoryCode": "S",
                "vatRate":         21.00,
                "itemName":        "Widget",
            }],
        },
    },
}

# Serialize once — same bytes are hashed and sent
body = json.dumps(invoice, separators=(",", ":")).encode()

timestamp = int(time.time())
body_hash = hashlib.sha256(body).hexdigest()
payload   = f"{timestamp}.POST.{PATH_AND_QUERY}.{body_hash}".encode()
signature = hmac.new(HMAC_SECRET.encode(), payload, hashlib.sha256).hexdigest()

response = requests.post(
    f"{API_BASE}{PATH_AND_QUERY}",
    headers={
        "Content-Type":         "application/json",
        "Authorization":        f"Bearer {API_TOKEN}",
        "X-Bizzlink-Signature": f"t={timestamp},v1={signature}",
    },
    data=body,
)
print(response.json())
// Node.js 18+ (built-in fetch + crypto)
import crypto from 'node:crypto';

const API_BASE       = 'https://gateway.vigasoft.lu';
const PATH_AND_QUERY = '/bizzlink/api/v1/documents/business-documents';
const API_TOKEN      = process.env.BIZZLINK_API_TOKEN;
const HMAC_SECRET    = process.env.BIZZLINK_HMAC_SECRET;

const invoice = {
  data: {
    type: 'business-documents',
    attributes: {
      '@type': 'InvoiceDocument',
      documentId: 'INV-2026-00042',
      issueDate:  '2026-05-05',
      typeCode:   'COMMERCIAL_INVOICE',
      currency:   'EUR',
      dueDate:    '2026-06-04',
      buyerReference:   'PO-7788',
      paymentTermsText: 'Net 30 days',
      seller: {
        name:  'Vigasoft S.à r.l.-S.',
        vatId: 'LU12345678',
        electronicAddress:         'LU12345678',
        electronicAddressSchemeId: '9938',
        address: {
          street1: '9, rue Marcel Schintgen',
          city: 'Lamadelaine',
          postCode: 'L-4889',
          countryCode: 'LU',
        },
      },
      buyer: {
        name:  'ACME Belgium SA',
        vatId: 'BE0123456789',
        electronicAddress:         'BE0123456789',
        electronicAddressSchemeId: '9925',
        address: {
          street1: 'Avenue Louise 100', city: 'Bruxelles',
          postCode: '1050',
          countryCode: 'BE',
        },
      },
      payment: {
        paymentMeansCode: 'SEPA_CREDIT_TRANSFER',
        remittanceInformation: 'INV-2026-00042',
        accounts: [
          { iban: 'LU000000000000000000', bic: 'BCEELULL', accountName: 'Vigasoft' },
        ],
      },
      taxBreakdown: [{
        categoryCode: 'S',
        rate: 21.00,
        taxableAmount: { amount: 1000.00, currency: 'EUR' },
      }],
      lines: [{
        id: '1',
        quantity: 10,
        unitCode: 'C62',
        netUnitPrice: { amount: 100.00, currency: 'EUR' },
        vatCategoryCode: 'S',
        vatRate: 21.00,
        itemName: 'Widget',
      }],
    },
  },
};

// Serialize once — same bytes are hashed and sent
const body = JSON.stringify(invoice);

const timestamp = Math.floor(Date.now() / 1000);
const bodyHash  = crypto.createHash('sha256').update(body).digest('hex');
const payload   = `${timestamp}.POST.${PATH_AND_QUERY}.${bodyHash}`;
const signature = crypto.createHmac('sha256', HMAC_SECRET)
  .update(payload).digest('hex');

const response = await fetch(`${API_BASE}${PATH_AND_QUERY}`, {
  method: 'POST',
  headers: {
    'Content-Type':         'application/json',
    'Authorization':        `Bearer ${API_TOKEN}`,
    'X-Bizzlink-Signature': `t=${timestamp},v1=${signature}`,
  },
  body,
});
console.log(await response.json());
<?php
// composer require guzzlehttp/guzzle
use GuzzleHttp\Client;

$apiBase      = 'https://gateway.vigasoft.lu';
$pathAndQuery = '/bizzlink/api/v1/documents/business-documents';
$apiToken     = getenv('BIZZLINK_API_TOKEN');
$hmacSecret   = getenv('BIZZLINK_HMAC_SECRET');

$invoice = [
    'data' => [
        'type' => 'business-documents',
        'attributes' => [
            '@type'       => 'InvoiceDocument',
            'documentId'  => 'INV-2026-00042',
            'issueDate'   => '2026-05-05',
            'typeCode'    => 'COMMERCIAL_INVOICE',
            'currency'    => 'EUR',
            'dueDate'     => '2026-06-04',
            'buyerReference'   => 'PO-7788',
            'paymentTermsText' => 'Net 30 days',
            'seller' => [
                'name'  => 'Vigasoft S.à r.l.-S.',
                'vatId' => 'LU12345678',
                'electronicAddress'         => 'LU12345678',
                'electronicAddressSchemeId' => '9938',
                'address' => [
                    'street1' => '9, rue Marcel Schintgen',
                    'city'    => 'Lamadelaine',
                    'postCode'    => 'L-4889',
                    'countryCode' => 'LU',
                ],
            ],
            'buyer' => [
                'name'  => 'ACME Belgium SA',
                'vatId' => 'BE0123456789',
                'electronicAddress'         => 'BE0123456789',
                'electronicAddressSchemeId' => '9925',
                'address' => [
                    'street1' => 'Avenue Louise 100', 'city' => 'Bruxelles',
                    'postCode' => '1050',
                    'countryCode' => 'BE',
                ],
            ],
            'payment' => [
                'paymentMeansCode'      => 'SEPA_CREDIT_TRANSFER',
                'remittanceInformation' => 'INV-2026-00042',
                'accounts' => [
                    ['iban' => 'LU000000000000000000', 'bic' => 'BCEELULL', 'accountName' => 'Vigasoft'],
                ],
            ],
            'taxBreakdown' => [[
                'categoryCode'  => 'S',
                'rate'          => 21.00,
                'taxableAmount' => ['amount' => 1000.00, 'currency' => 'EUR'],
            ]],
            'lines' => [[
                'id'       => '1',
                'quantity' => 10,
                'unitCode' => 'C62',
                'netUnitPrice'    => ['amount' => 100.00, 'currency' => 'EUR'],
                'vatCategoryCode' => 'S',
                'vatRate'         => 21.00,
                'itemName'        => 'Widget',
            ]],
        ],
    ],
];

// Serialize once — same bytes are hashed and sent
$body = json_encode($invoice, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

$timestamp = time();
$bodyHash  = hash('sha256', $body);
$payload   = "{$timestamp}.POST.{$pathAndQuery}.{$bodyHash}";
$signature = hash_hmac('sha256', $payload, $hmacSecret);

$client   = new Client();
$response = $client->post($apiBase . $pathAndQuery, [
    'headers' => [
        'Content-Type'         => 'application/json',
        'Authorization'        => "Bearer {$apiToken}",
        'X-Bizzlink-Signature' => "t={$timestamp},v1={$signature}",
    ],
    'body' => $body,
]);
echo $response->getBody();

Invoice vs. credit note — what’s the difference?

Both go through the same endpoint and use the same envelope — only a few fields and the typeCode change. Conceptually:

InvoiceCredit Note
PurposeBills the buyer for goods or services delivered → buyer owes moneyReverses (fully or partially) a previously issued invoice → seller owes money back, or buyer’s debt is reduced
Use caseNormal billingRefund, return, post-delivery discount, correction of a wrong invoice, cancellation of services already invoiced
@type discriminator"InvoiceDocument""CreditNoteDocument"
typeCode enum (UN/CEFACT 1001 backed)COMMERCIAL_INVOICE (380), CORRECTED_INVOICE (384), PREPAYMENT_INVOICE (386), SELF_BILLED_INVOICE (389), DEBIT_NOTE (383)CREDIT_NOTE (381)
Money flow directionSeller → Buyer (receivable)Buyer → Seller (payable from seller’s side)
Amounts in JSONPositive numbers — “this is owed”Still positive numbers — the typeCode signals it’s a reduction. Don’t send negative amounts.
Mandatory link to invoiceoriginalInvoiceNumber (BT-25) + originalInvoiceDate (BT-26) — PEPPOL Schematron rejects credit notes without these
UBL wire format<Invoice> (urn:oasis:names:specification:ubl:schema:xsd:Invoice-2)<CreditNote> (urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2) — different XSD
Java SDK builderCreateAndSendBusinessDocumentRequest.forInvoice(...)CreateAndSendBusinessDocumentRequest.forCreditNote(...)

Rule of thumb: if money is flowing toward the seller, it’s an invoice. If money is flowing back to the buyer (or the buyer’s debt is being reduced), it’s a credit note. Never use a “negative invoice” to model a refund — PEPPOL doesn’t accept that and most buyers’ ERP systems will reject it.

Correction vs. credit note: if the original invoice was wrong but never paid, two valid approaches exist — either issue a corrected invoice (typeCode: CORRECTED_INVOICE, often replacing the original) or issue a credit note (typeCode: CREDIT_NOTE) that fully zeros out the original + a fresh invoice for the right amount. The credit-note approach is more common because it leaves an audit trail.

Sending a credit note

Same endpoint and envelope — flip the @type discriminator to CreditNoteDocument, set typeCode to CREDIT_NOTE, and add the two reference fields PEPPOL requires (BT-25 / BT-26):

{
  "data": {
    "type": "business-documents",
    "attributes": {
      "@type": "CreditNoteDocument",
      "documentId": "CN-2026-00007",
      "issueDate": "2026-05-15",
      "typeCode": "CREDIT_NOTE",
      "currency": "EUR",
      "originalInvoiceNumber": "INV-2026-00042",
      "originalInvoiceDate":   "2026-05-05",
      "seller": { "...same as above" },
      "buyer":  { "...same as above" },
      "taxBreakdown": [ "..." ],
      "lines":  [ "..." ]
    }
  }
}

Credit notes don’t have a dueDate (no payment is due — money goes back). In the Java SDK, use CreateAndSendBusinessDocumentRequest.forCreditNote(cn -> cn. ...) instead of .forInvoice(...).

Response

A 200 OK returns a JSON:API collectiondata is an array with one entry per generated rendition. For most cross-border invoices that’s a single UBL/Peppol entry; for some jurisdictions (e.g. an IT seller invoicing a foreign EU buyer) the cloud produces both a FatturaPA via SDI rendition and a UBL via Peppol rendition from the same input, both sharing one processId:

{
  "data": [
    {
      "type": "invoices",
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "attributes": {
        "processId": "8e3a1f2c-1234-4abc-9def-012345678abc",
        "format":   "UBL_PEPPOL_BIS_3",
        "target":   "PEPPOL",
        "status":   "QUEUED_FOR_VALIDATION",
        "xml":      "<?xml version=\"1.0\"...\"/>"
      }
    }
  ]
}

For an IT seller the array would carry a second entry with "format": "FATTURA_PA_1_2" and "target": "SDI_IT", same processId.

FieldMeaning
data[].typeJSON:API resource type — invoices for an InvoiceDocument input, credit-notes for a CreditNoteDocument input. All siblings of the same business document share the same type.
data[].idPer-rendition document id. Poll GET /documents/{id}/status for the lifecycle of that rendition (validation, send, delivery).
attributes.processIdCorrelation id shared by every rendition produced by this create call. Look up siblings with GET /documents?processId={uuid}.
attributes.formatWire format actually generated (UBL_PEPPOL_BIS_3, FATTURA_PA_1_2, FACTUR_X_1_07, XRECHNUNG_3_0, KSEF_FA_3).
attributes.targetNetwork/platform this rendition is delivered to (PEPPOL, SDI_IT, PPF_FR, XRECHNUNG_DE, KSEF_PL).
attributes.statusSymbolic status — ACCEPTED, QUEUED_FOR_VALIDATION, VALID, INVALID, QUEUED_FOR_SENDING, SUBMITTED, DELIVERED, FAILED.
attributes.xmlThe generated XML in the indicated format — useful for archival or debugging.