---
title: "Send an invoice over Peppol"
description: "Send an invoice over Peppol with one REST call: register the sender, verify the recipient, POST /v1/documents/send with an idempotency key, then watch the delivery webhooks."
canonical: "https://docs.get-flowie.com/guides/send-invoice"
source: "https://docs.get-flowie.com/guides/send-invoice.html"
---

# Send an invoice over Peppol

Guides

# Send an invoice over Peppol

One REST call delivers a compliant e-invoice to any Peppol participant. This is the happy path in four steps, from a cold start to a `document.delivered` webhook.

## 1 · Register the sender

One-time per company. Creates the company, enriches it from the VAT number, and publishes it to the Peppol SMP so it can both send and receive.
[code] 
    curl -X POST …/v1/companies \
      -H "Authorization: Bearer $FLOWIE_KEY" \
      -d '{"vatNumber":"BE0123456789"}'
[/code]

If the company already exists on another platform, use [`POST /v1/companies/import`](<../reference/index.html#import-company>) instead, then [`POST /v1/companies/{id}/register`](<../reference/index.html#register-company>) to activate it on Peppol.

## 2 · Verify the recipient

Always verify before sending. A recipient that is not registered for your document type will bounce, and the bounce arrives asynchronously — minutes after you thought the invoice was gone.
[code] 
    curl -X POST …/v1/directory/verify \
      -H "Authorization: Bearer $FLOWIE_KEY" \
      -d '{"peppolId":"0208:9876543210","documentType":"INVOICE"}'
[/code]

Check `canReceive` in the response before continuing.

## 3 · Send the invoice

Describe the invoice as JSON and we render, sign and route the UBL for you. Pass a persistent `Idempotency-Key` — generate it before the first attempt, from your own database row id, so a crash between generation and the HTTP call is still recoverable.
[code] 
    curl -X POST …/v1/documents/send \
      -H "Authorization: Bearer $FLOWIE_KEY" \
      -H "Idempotency-Key: inv-2026-001" \
      -d '{
        "type": "invoice",
        "from": "comp_abc123",
        "to":   "0208:9876543210",
        "document": {
          "number":    "INV-2026-001",
          "issueDate": "2026-04-25",
          "dueDate":   "2026-05-25",
          "currency":  "EUR",
          "lines": [{
            "description": "Consulting, April 2026",
            "quantity": 10, "unit": "hours",
            "unitPrice": 150.00, "vatRate": 21
          }]
        }
      }'
[/code]

Already have UBL XML or a Factur-X PDF? Send it as-is with the `xml` or `file` field instead of `document` — see [the endpoint reference](<../reference/index.html#send-document>) for the payload matrix.

## 4 · Watch the delivery

The response returns immediately with `status: "sent"`; delivery is asynchronous. A [subscribed webhook](<receive-invoices.html>) receives `document.delivered` once the recipient's access point confirms, or `document.failed` with an error code if it does not.

Pre-flight checks before switching a customer live

Run the payload through [`POST /v1/documents/validate`](<../reference/index.html#validate-document>) in CI. It catches BIS rule violations (BR-*), unreachable recipients and currency mismatches without touching Peppol. 

## Next

  * [Receive invoices](<receive-invoices.html>) — the other half of the exchange.
  * [ERP webhooks → send](<index.html#ingest>) — wire D365, SAP or NetSuite as the inbound source.
  * [Go-live checklist](<index.html#go-live>) — prove you are production-ready.
  * [Compliance](<../compliance/index.html>) — what changes per country.
