PeppolDokumentace pro partnery Swagger UI: sandbox · produkce

Příjem dokumentů

Dokumenty zaslané účastníkům vašich koncových uživatelů přistanou ve schránce (inboxu) daného účastníka. Webhook vám dá vědět, že něco přišlo; dokument pak stáhnete ve formátu, který váš software čte, a potvrdíte jeho převzetí.

Čtení schránky patří do Document API, proto vyžaduje klíč přijímajícího koncového uživatele, ne váš partnerský klíč. Pokud váš software běží centrálně, vyberte podle participantId z webhooku klíč správného koncového uživatele.

Schránka

Každý účastník má schránku s dokumenty, které přijal a vy jste je zatím nepotvrdili, seřazenými od nejstaršího.

curl -s "$DOCUMENT_API/v1/inbox/9929:CZ87654321?limit=100" -H "X-Api-Key: $END_USER_KEY"
  • limit je 1–500, výchozí 50. Zpracované dokumenty potvrďte a zavolejte znovu pro další stránku.
  • Každá položka má stejnou podobu jako stav přenosu: transmissionId, state, counterpartyId (odesílatel), documentTypeId, validationReport, createdAt.
  • Účastník, který nepatří volajícímu koncovému uživateli, vrací 404.

Nevalidní dokumenty

Dokument, který při příjmu neprojde validací Peppol, vám je přesto doručen, se stavem state: "Invalid" a s validationReport. Odesílatel dostal potvrzení o převzetí a vzápětí odmítnutí (Message Level Status RE) s chybami, takže ví, že má poslat opravený dokument. Platný dokument Redque odesílateli potvrdí (AB). Co Redque odesílateli odpověděl, si stáhnete přes GET /v1/inbox/{participantId}/{transmissionId}/message-status/document.

U slovenských koncových uživatelů Redque k přijaté faktuře podá daňové hlášení za příjemce. Jeho stav a dokumenty najdete v GET /v1/inbox/{participantId}/{transmissionId}/tax-reports (viz Daňová hlášení).

Stažení dokumentu

curl -s "$DOCUMENT_API/v1/inbox/9929:CZ87654321/$TRANSMISSION_ID/document?format=Isdoc" \
  -H "X-Api-Key: $END_USER_KEY" -o invoice.isdoc

Parametr format je povinný a rozlišuje velikost písmen. Tentýž dokument můžete stáhnout v libovolném formátu a kolikrát chcete; převádí se při každém požadavku.

formatVrací
IsdocISDOC 6.0.2, application/xml. Obsahuje v rozšíření celou fakturu podle EN 16931, takže se při zpětném převodu nic neztratí.
UblPřesně ty bajty, které přišly přes Peppol, UBL podle Peppol BIS Billing 3.0. Vždy k dispozici.
CanonicalJsonModel EN 16931 od Redque jako JSON, application/json.

Pokud dokument nelze konvertovat do požadovaného formátu, odpověď je 422 s vysvětlením; stáhněte ho jako Ubl. Při archivaci přijatých faktur uchovávejte Ubl jako právní originál.

Potvrzení převzetí

curl -s -X POST "$DOCUMENT_API/v1/inbox/9929:CZ87654321/$TRANSMISSION_ID/ack" -H "X-Api-Key: $END_USER_KEY"

Potvrďte dokument, jakmile je bezpečně uložen ve vašem systému. Zmizí z výpisu schránky, ale stáhnout ho lze dál. Potvrzení je idempotentní a vrací 204.

Webhooky

Odběry webhooků patří vám, partnerovi, a pokrývají všechny vaše koncové uživatele. Vytvoříte je partnerským klíčem:

curl -s -X POST "$PARTNER_API/v1/webhooks" -H "X-Api-Key: $PARTNER_KEY" -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/peppol/webhook" }'
{ "subscriptionId": "a41e…", "url": "https://example.com/peppol/webhook", "active": true, "createdAt": "…", "secret": "q0b9…" }

secret podepisuje každé doručení a vrací se pouze v této odpovědi. URL musí být HTTPS. GET /v1/webhooks vypíše vaše odběry, DELETE /v1/webhooks/{subscriptionId} odběr deaktivuje. Pro změnu secret vytvořte nový odběr a pak smažte starý.

Události

UdálostKdy
document.receivedNěkterému z vašich účastníků dorazil dokument. state je Dispatched, nebo Invalid, pokud neprošel validací.
transmission.statusDokument, který jste odeslali, přešel do stavu Delivered, Failed, Rejected nebo Recorded (jen daňové hlášení, odběratel mimo Peppol). Dokument odmítnutý už v odpovědi API (422) událost nevyvolá.
transmission.message_statusPřístupový bod příjemce odpověděl na dokument, který jste odeslali (Message Level Status). Podrobnosti v messageStatus u přenosu.
tax_report.statusDaňové hlášení k dokumentu (odeslanému i přijatému) změnilo stav: odesláno, potvrzeno nebo odmítnuto úřadem, nebylo potřeba, selhalo. Podrobnosti v GET /v1/documents/{id}/tax-reports.

Každá událost je JSON POST. Dokumenty nikdy nejsou součástí události: stáhněte je přes API.

POST /peppol/webhook HTTP/1.1
Content-Type: application/json
X-Redque-Event: document.received
X-Redque-Delivery: 5c7d2a0e-…
X-Redque-Timestamp: 1791976351
X-Redque-Signature: v1=8f2c…

{
  "eventType": "document.received",
  "transmissionId": "e3a1…",
  "direction": "Inbound",
  "state": "Dispatched",
  "participantId": "9929:cz87654321",
  "counterpartyId": "9929:cz12345678",
  "documentTypeId": "busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##…::2.1",
  "instanceIdentifier": "…",
  "occurredAt": "2026-10-14T09:15:02+00:00",
  "validationSuccess": true
}
  • participantId je účastník vašeho koncového uživatele: u document.received příjemce, u transmission.status odesílatel. counterpartyId je protistrana.
  • lastError je uveden, pokud nějaká chyba nastala, například u Failed.

Doručování a opakování

  • Odpovězte libovolným stavem 2xx, zpracování proveďte až potom.
  • Jakákoli jiná odpověď nebo žádná odpověď vede k opakování v prodlužujících se intervalech — 30 sekund a pak dvojnásobek až do 6 hodin.
  • Doručení může přijít víckrát. X-Redque-Delivery je napříč opakováními jednoho doručení stejné.
  • Události nemusí dorazit ve správném pořadí. Spoléhejte na state, případně si aktuální stav načtěte z API.
  • Webhooky jsou pouze notifikace. Schránka drží každý dokument, dokud ho nepotvrdíte, takže se nic neztratí, ani když je váš endpoint nedostupný.

Ověření podpisu

Každé doručení je podepsáno secretem vašeho odběru: X-Redque-Signature je v1= následované hexadecimálním (malá písmena) HMAC-SHA256 z {X-Redque-Timestamp}.{surové tělo}. Podpis ověřujte na surových bajtech ještě před parsováním JSON, porovnávejte v konstantním čase a odmítejte staré časové značky, abyste zabránili přehrání.

Node.js

import crypto from "node:crypto";

// rawBody: tělo požadavku jako Buffer, před parsováním JSON.
export function verifyRedqueWebhook(secret, headers, rawBody, toleranceSeconds = 300) {
  const timestamp = headers["x-redque-timestamp"];
  const signature = headers["x-redque-signature"] ?? "";
  if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) return false;

  const expected = "v1=" + crypto.createHmac("sha256", secret)
    .update(Buffer.concat([Buffer.from(timestamp + "."), rawBody]))
    .digest("hex");
  return expected.length === signature.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

C#

using System.Security.Cryptography;
using System.Text;

static bool VerifyRedqueWebhook(string secret, string timestamp, string signature, byte[] rawBody, TimeSpan tolerance)
{
    if (!long.TryParse(timestamp, out var unix) ||
        Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - unix) > tolerance.TotalSeconds)
        return false;

    byte[] payload = [.. Encoding.UTF8.GetBytes(timestamp + "."), .. rawBody];
    var expected = "v1=" + Convert.ToHexStringLower(HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), payload));
    return CryptographicOperations.FixedTimeEquals(Encoding.ASCII.GetBytes(expected), Encoding.ASCII.GetBytes(signature));
}

Spolehlivý postup příjmu

  1. Při document.received: ověřte podpis, odpovězte 200 a zařaďte participantId a transmissionId do fronty.
  2. Stáhněte dokument ve svém formátu a jako Ubl pro archiv. Uložte obojí.
  3. Potvrďte převzetí.
  4. Pravidelně procházejte schránky všech účastníků, abyste zaručili doručení i v případě zmeškaného webhooku.