eliDocs
API Reference

POST /v1/send

POST/v1/send

Managed delivery (preview). One call generates, validates, and delivers an e-invoice over the right national network, tracked with a conservative status contract and billed per delivered invoice. In development, not generally available.

When managed delivery ships, POST /v1/send will take your invoice data, generate and validate the compliant document, and durably queue it for delivery over the network you name. It is the composite entry point: one call for build, check, and deliver.

Delivery is asynchronous. The call returns 202 Accepted once the document is safely queued; the document then moves through the network on its own, and you follow its progress by webhook or by polling the transmission.

Two ways to send

Two ways to send

Endpoint Use when
POST /v1/send You have invoice data. Beliq will generate the compliant XML, validate it, and deliver it in one call.
POST /v1/transmissions You already have a validated XML document and only need delivery.

Both accept the same delivery fields and return the same transmission resource.

Networks

Networks

Name the network the document travels on:

network Channel
peppol The Peppol network, via a certified Access Point
ksef Poland KSeF — Beliq’s Poland delivery lane targets the current FA(3) schema (mandatory since 2026-02-01). Timeline subject to the FA(3) implementation milestone.
sdi Italy SDI (Sistema di Interscambio)
ppf_pdp France, a certified Plateforme Agréée (PA)
choruspro France Chorus Pro (public procurement)
Headers

Headers

Header Required Description
Authorization required Bearer <api-key> or use X-API-Key. A test key never reaches a real network.
Content-Type required application/json
Idempotency-Key optional A key you choose to make the send safe to retry. See Idempotency.
Request body

Request body

The invoice payload is the same as POST /v1/generate, plus the delivery envelope: network, sender, and recipient.

Field Type Required Description
standard string required Target format, for example peppol-bis, facturx, xrechnung.
invoice object required The EN 16931 invoice data, as in generate.
network string required One of the networks above.
sender object required { scheme, id } identifying you on the network.
recipient object required { scheme, id } identifying the buyer on the network.
documentTypeId string optional The network document-type identifier, where the network needs one.
deadlineAt string optional ISO 8601 instant by which delivery must succeed. Drives at-risk escalation.
send.sh
curl -X POST https://api.beliq.eu/v1/send \
  -H "Authorization: Bearer blq_live_abc123..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3c-2026-04-13-invoice-123" \
  -d '{
    "standard": "peppol-bis",
    "network": "peppol",
    "sender":    { "scheme": "0208", "id": "0123456789" },
    "recipient": { "scheme": "0208", "id": "9876543210" },
    "invoice": {
      "number": "INV-2026-0123",
      "issueDate": "2026-04-13",
      "currencyCode": "EUR",
      "seller": {
        "name": "Acme AG",
        "vatId": "BE0123456789",
        "address": { "street": "Grote Markt 1", "city": "Brussel", "postalCode": "1000", "countryCode": "BE" }
      },
      "buyer": {
        "name": "Client BV",
        "vatId": "BE9876543210",
        "address": { "street": "Meir 2", "city": "Antwerpen", "postalCode": "2000", "countryCode": "BE" }
      },
      "lines": [ { "description": "Consulting", "quantity": 1, "unitCode": "DAY", "unitPrice": 800.00, "lineTotal": 800.00, "vatRate": 21, "vatCategoryCode": "S" } ],
      "taxSummary": [ { "vatCategoryCode": "S", "vatRate": 21, "taxableAmount": 800.00, "taxAmount": 168.00 } ],
      "totalNetAmount": 800.00, "totalTaxAmount": 168.00, "totalGrossAmount": 968.00
    }
  }'
Response
{
  "success": true,
  "data": {
    "id": "txn_9f3c2a1b8e",
    "status": "queued",
    "direction": "outbound",
    "network": "peppol",
    "deduplicated": false,
    "verdict": { "valid": true, "format": "ubl", "profileDetected": "peppol", "errors": [], "warnings": [] }
  }
}

If the invoice fails validation, nothing is queued: the call returns 422 INVALID_INVOICE with the full verdict in details, exactly as generate does. You fix the data and send again.

POST /v1/transmissions

POST /v1/transmissions

When you already hold a validated document, deliver it directly. The payload carries the document instead of invoice data:

Field Type Required Description
network string required One of the networks.
sender object required { scheme, id }.
recipient object required { scheme, id }.
format string required ubl or cii.
xml string required The UTF-8 XML document.
documentTypeId string optional Network document-type identifier.
deadlineAt string optional Delivery deadline.

The response is the same transmission resource as POST /v1/send.

Idempotency

Idempotency

Delivery must never fire twice for one invoice, so sends are safe to retry. Set an Idempotency-Key header with a value you derive from the invoice (its number is a good seed):

  • Same key, same body returns the existing transmission with deduplicated: true and 200 OK. No second delivery is queued.
  • Same key, different body returns 409 IDEMPOTENCY_KEY_REUSED. Beliq refuses to guess which one you meant rather than risk sending the wrong document.

Retrying a send after a timeout is therefore safe: either the first attempt registered and you get it back, or it did not and the retry queues it.

Without a key there is still a backstop, but it answers differently. Sending a document you have already sent to that recipient returns 409 CONTENT_ALREADY_SENT with the existing transmission’s id in details, because nothing was queued and a 200 would read as a second delivery that never happened. Two things are deliberately not duplicates: the same document to a different recipient, and a resend of a document whose transmission reached failed or rejected. Both queue normally.

Sender identity

Sender identity

sender is the identifier your invoice goes out as, and you may only use one your organization has registered and Beliq has confirmed you own. An unregistered or not-yet-active identifier returns 403 SENDER_NOT_REGISTERED and nothing is queued or billed.

This is checked on Beliq’s side rather than the access point’s. Every Beliq customer’s participants sit under one account at the access point, so its own “may this identifier send” check cannot tell one customer from another. Ours can, and it is the check that stops one customer sending as another.

The same check runs against the document. If the invoice’s own EndpointID for the seller or the buyer names a different party than the request does, the send is refused with 400 DOCUMENT_PARTY_MISMATCH rather than going out addressed one way and reading another. Different spellings of one identifier agree: 0088:5790000435975 and iso6523-actorid-upis::0088:5790000435975 are the same participant.

Peppol routing

Peppol routing

A document travels the Peppol Network inside an envelope, and the receiving access point routes on the envelope rather than on the invoice. Beliq builds it, from values it derives from your document at send time:

Value Where it comes from
Document type identifier The document’s root element and its CustomizationID. This is the key the recipient’s capabilities are looked up with.
Process identifier cbc:ProfileID (UBL) or the business process parameter (CII).
Sender and recipient The registered participant you send as, and the recipient on the request. Never read from the invoice.
Country of the sender The country recorded on your participant registration. Mandatory in every Peppol envelope.

You do not supply any of these. What you do have to make sure of is that the document carries a CustomizationID and a ProfileID: without them there is no envelope to build and no access point to look up, so the send is refused with 400 MISSING_CUSTOMIZATION_ID or 400 MISSING_PROCESS_ID. Nothing is queued or billed. Beliq never falls back to sending a bare document, because a document with no envelope has nowhere to go.

Delivery status

Delivery status

A transmission moves forward through a conservative set of statuses. The contract is deliberate: a provider returning HTTP 200 is not the same as the document reaching the network, which is not the same as it being delivered. Beliq only reports the stronger status once it has the proof.

Status Meaning Terminal
queued Validated and durably held. Beliq owns delivery from here. Not yet on any network.
submitting An attempt is in flight to a provider. No network confirmation yet.
submitted A provider acknowledged the submission. In the provider’s pipeline, not yet network-confirmed.
cleared The network confirmed technical acceptance (Peppol transport receipt, KSeF UPO, SDI ricevuta). Legal proof captured. KSeF only
delivered Confirmed delivery to the recipient (Peppol MLR, SDI delivery receipt, PA approval). yes
rejected The network or recipient refused on validation or business grounds. Fix and send again as a new transmission. yes
failed Permanent transport failure after the deadline and grace window, or an unroutable recipient. Escalated, never silently retried forever. yes

cleared is terminal only for KSeF, where the UPO is the final proof. On Peppol, SDI, and the French PA channel the network emits a further delivery signal, so cleared is a step on the way to delivered.

At risk. When a deadlineAt is set and the deadline is threatened or breached, the transmission carries atRisk: true alongside its current status and fires a transmission.at_risk webhook. It is a flag, not a status: the transmission keeps progressing.

Never abandoned. A transport or provider outage does not drop a document. Beliq holds it in a durable outbox, retries with backoff, and escalates for human attention rather than giving up. It never blindly re-sends when the first attempt’s outcome is unknown; it reconciles the real status first, so a document is never delivered twice.

If the recipient cannot be found

Before a document goes out, Beliq asks the network whether the recipient is actually there. Three answers are possible and they are kept apart, because they are different problems with different fixes:

Answer What it means Who fixes it
Reachable The recipient is registered and its access point serves it. The document goes out. nobody
Not in the directory Nothing is registered for that identifier. Usually a wrong identifier, or a recipient who is not on the network yet. you, or your recipient
Registered but not served The directory lists the recipient, but the access point it points at does not know them. A stale registration on their side. your recipient’s provider

A recipient who is reachable but does not publish the document type you are sending is a fourth case, and it is refused rather than worked around: your document declares which profile it conforms to, and Beliq will not relabel it as a profile nobody validated it against.

None of these are terminal. The transmission stays open and is escalated for human attention rather than being rejected outright, because a recipient who is not registered today may be registered tomorrow. It reaches failed only if the deadline passes.

If the lookup itself does not answer, Beliq sends anyway. A directory outage is not evidence about your recipient, and the receiving access point validates the recipient again on its own side.

How a retry avoids sending twice

Every Peppol envelope carries an identifier that Beliq mints and the access point stores as its own reference for the transmission. The identifier has to be new on each attempt, because the standard requires it to be unique per envelope, so it cannot on its own stop a retry from becoming a second invoice.

What stops it is that Beliq writes the identifier down before the send rather than after. If an attempt ends without an answer, whether the network dropped it, the connection died, or the process was killed mid-request, the identifier survives. The next attempt asks the access point about it first and sends only if the answer is that no such transmission exists. An access point that cannot be reached to answer is not an answer: the document waits rather than going out on a guess.

This is why an unknown outcome shows as submitting for longer than a failure would. Beliq is establishing what actually happened before it acts, and it would rather be slow than send your customer the same invoice twice.

Billing

Billing

Delivery is billed per delivered invoice, and only on success: a transmission that reaches delivered (or a terminal cleared, for KSeF) is billed once. A rejected or failed transmission is never billed. Compute (the generate and validate folded into POST /v1/send) uses your plan quota as usual. See pricing.

Track a transmission

Track a transmission

Poll a transmission, or list your recent ones. These reads are available to any authenticated caller in your organisation.

GET /v1/transmissions

List transmissions, most recent first, with optional filters.

Query parameter Description
direction outbound or inbound
status Any status value from the table above (or the inbound statuses)
network One of the networks
limit Page size, 1 to 100
cursor The nextCursor from the previous page
Response
{
  "success": true,
  "data": {
    "items": [ { "id": "txn_9f3c2a1b8e", "direction": "outbound", "network": "peppol", "status": "delivered", "atRisk": false } ],
    "nextCursor": null
  }
}

GET /v1/transmissions/:id

The full transmission resource: its status, the counterparty, the deadline and at-risk flag, and timestamps.

Response
{
  "success": true,
  "data": {
    "id": "txn_9f3c2a1b8e",
    "direction": "outbound",
    "network": "peppol",
    "status": "delivered",
    "counterparty": { "scheme": "0208", "id": "9876543210" },
    "deadlineAt": "2026-04-20T00:00:00.000Z",
    "atRisk": false,
    "livemode": true,
    "createdAt": "2026-04-13T09:00:00.000Z",
    "updatedAt": "2026-04-13T09:04:12.000Z"
  }
}

The audit sub-resources

Path Returns
GET /v1/transmissions/:id/attempts Every delivery attempt: the provider, the outcome, and the retry history.
GET /v1/transmissions/:id/events A hash-chained audit trail of every status change, with a chainOk flag so you can confirm the log has not been tampered with.
GET /v1/transmissions/:id/receipts The legal proofs captured from the network (Peppol AS4 receipt and MLR, KSeF UPO, SDI ricevuta, PA lifecycle), each with its SHA-256 hash.
GET /v1/transmissions/:id/document The stored document bytes. Returns 410 Gone once the payload is purged under the retention policy; the hash and proofs are kept.
Webhooks

Webhooks

Rather than poll, subscribe to the transmission events and react as the status advances: transmission.queued, transmission.submitted, transmission.cleared, transmission.delivered, transmission.rejected, transmission.failed, and transmission.at_risk. See Webhooks.

Related