API: Fulfillment (Auftraggeber)
Schnittstelle zwischen zwei Trade-Bridge-Instanzen: Der Händler schickt Lieferscheine, Artikel, Anlieferungen und Rückläufer an seinen Fulfiller und holt Status, Pakete und Bestand ab.
Zwei Trade-Bridge-Instanzen sprechen direkt miteinander: Der Fulfiller legt den Händler unter Fulfillment → Auftraggeber an und erzeugt dort einen Schlüssel (Recht fulfillment:client). Der Händler trägt Adresse und Schlüssel unter Einstellungen → Connections als „Fulfiller (Trade Bridge)“ ein. Danach läuft alles von selbst: Ausliefern schickt den Lieferschein, Anlieferungen werden angekündigt, Rückgaben gemeldet. Versand, Wareneingang, Retourenprüfung und Bestand meldet der Fulfiller sofort per Webhook zurück; zusätzlich gleicht der Händler einmal je Stunde ab, falls eine Meldung verloren ging.
Wer kein Trade Bridge nutzt, kann dieselben Endpunkte mit einem eigenen System ansprechen. Grundlagen zu Schlüssel und Antworten: API: Überblick und Zugang.
Endpunkte
| Methode | Pfad | Zweck |
|---|---|---|
| POST | /v1/fulfillment/outbounds | Lieferschein anlegen (Auftrag an das Lager) |
| GET | /v1/fulfillment/outbounds | Lieferscheine mit Status und Paketen (updated_since) |
| GET | /v1/fulfillment/outbounds/{id} | Ein Lieferschein, per ID oder eigener Nummer |
| POST | /v1/fulfillment/outbounds/{id}/cancel | Storno, solange nichts versendet ist |
| PUT | /v1/fulfillment/articles | Artikelstammdaten anlegen oder aktualisieren |
| GET | /v1/fulfillment/stock | Bestand je Artikel (updated_since) |
| POST | /v1/fulfillment/inbounds | Anlieferung ankündigen |
| GET | /v1/fulfillment/inbounds | Anlieferungen mit Wareneingang (updated_since) |
| GET | /v1/fulfillment/inbounds/{id} | Eine Anlieferung |
| POST | /v1/fulfillment/returns | Rückläufer ankündigen |
| GET | /v1/fulfillment/returns | Rückläufer mit Prüfergebnis (updated_since) |
| GET | /v1/fulfillment/returns/{id} | Ein Rückläufer |
| PUT | /v1/fulfillment/webhook | Eigene Adresse für sofortige Meldungen registrieren |
| GET / DELETE | /v1/fulfillment/webhook | Registrierte Adresse ansehen oder entfernen |
| POST | /v1/fulfillment/webhook/test | Ein ping-Ereignis an die Adresse schicken |
| GET | /v1/fulfillment/tariff | Preise des Fulfillers für diesen Auftraggeber (Staffeln, Versand, Kartons, Tarif) |
| GET | /v1/fulfillment/request-templates | Vorlagen des Fulfillers für Anfragen (Sonderaufträge) |
| POST | /v1/fulfillment/requests | Anfrage anlegen oder aktualisieren (ID = die eigene) |
| GET | /v1/fulfillment/requests | Anfragen mit Stand und Abrechnung (updated_since) |
| POST | /v1/fulfillment/requests/{id}/messages | Nachricht im Verlauf einer Anfrage |
| POST | /v1/fulfillment/pairing | Kopplung anfragen (ohne Schlüssel, siehe unten) |
| DELETE | /v1/fulfillment/pairing | Verbindung aufheben (nur ohne offene Vorgänge) |
Listen nehmen updated_since (ISO 8601), limit (bis 500) und offset. Mit updated_since kommen die ältesten Änderungen zuerst.
Nummern und IDs
number ist immer die Nummer des Händlers (Lieferschein-, Anlieferungs- oder Rückgabenummer). Sie ist der Schutz vor Doppelungen: dieselbe Nummer noch einmal gesendet legt nichts neu an, die Antwort ist dann 200 statt 201. id ist die Kennung beim Fulfiller.
Beim Fulfiller heißt eine SKU <Kürzel des Auftraggebers>-<sku>; in allen Antworten steht die SKU des Händlers.
Lieferschein anlegen
POST /v1/fulfillment/outbounds
{
"number": "#1234-001",
"orderNumber": "#1234",
"orderExternalId": "cm2k…",
"orderedAt": "2026-10-09T14:12:00Z",
"currency": "EUR",
"shippingAddress": {
"firstName": "Lena", "lastName": "Albrecht",
"address1": "Hafenstraße 12", "zip": "20457", "city": "Hamburg", "countryCode": "DE"
},
"email": "kunde@example.com",
"note": "Bitte als Geschenk verpacken",
"invoice": { "number": "RE-2026-1041", "url": "https://…/RE-2026-1041.pdf" },
"items": [
{ "sku": "SH-KNIT-NAV-M", "quantity": 1, "title": "Strickpullover Navy M", "unitValue": 59.90 }
],
"articles": [
{
"externalId": "variant-id-beim-haendler", "productExternalId": "product-id-beim-haendler",
"sku": "SH-KNIT-NAV-M", "productTitle": "Strickpullover", "variantTitle": "Navy / M",
"barcode": "4006381333931", "weight": 0.42, "weightUnit": "kg", "value": 59.90,
"imageUrl": "https://…/pullover.jpg"
}
]
}Unbekannte SKUs werden aus articles angelegt; fehlen sie dort, antwortet der Fulfiller mit 422. Reicht der Bestand nicht, kommt 409 mit shortages (SKU, angefragt, verfügbar). Der Händler versucht es später noch einmal, wie heute bei JTL-FFN.
Die Antwort enthält id, number, status (PENDING, PICKPROCESS, SHIPPED, PARTIALLY_SHIPPED, CANCELLED …), items, packages (Sendungsnummer, Carrier, Link, Versanddatum, Gewicht, Inhalt), documentUrl (Lieferschein-PDF des Fulfillers), charges (berechnete Leistungen; SERVICE = Summe der Zusatzleistungen), shipmentMode, shippingProduct, fbaShipmentId und bei Spedition freight (Spediteur, Referenz, Paletten mit Gewicht, Maßen und Kartons).
Zusatzleistungen, Spedition und Amazon FBA
Optionale Felder beim Anlegen:
| Feld | Bedeutung |
|---|---|
services | Kürzel bestellter Zusatzleistungen, z. B. ["GESCHENK"]. Welche es gibt, steht in GET /tariff unter services; automatische gelten ohnehin. Unbekannte Kürzel: 422. |
shipmentMode | PARCEL (Standard, Paketlabel) oder FREIGHT (Spedition auf Paletten). |
shippingProduct | Feste Versandart beim Paket: DHL_PAKET, DHL_KLEINPAKET, GLS_PARCEL oder DPD_CLASSIC. Leer = der Fulfiller entscheidet. Unbekannte Werte: 400. |
fba | { "shipmentId": "FBA15…", "labelsUrl": "https://…/kartonetiketten.pdf" } – Einsendung an ein Amazon-Lager. Jedes Stück bekommt am Packtisch ein FNSKU-Etikett, jeder Karton das Amazon-Kartonetikett. |
items[].fnsku | FNSKU je Position (überschreibt die am Artikel). In articles steht sie als fnsku. |
Ohne shippingProduct entscheidet der Fulfiller mit seinen Versandregeln (Land, Sperrgut, Gewicht, Auftraggeber oder günstigster laut Preisliste). Mit shippingProduct geht das Paket fest so raus; am Packtisch wird nicht umentschieden. Geht die Versandart für die Sendung nicht (zu schwer, nicht angeboten), meldet das Lager einen Klärungsfall und der Fulfiller klärt ihn am Lieferschein. In Trade Bridge stellt der Händler die Vorgabe an der Fulfiller-Verbindung ein (Feld „Versandart vorgeben“).
Bestand
GET /v1/fulfillment/stock liefert je Artikel externalId (die Varianten-ID des Händlers aus den Artikeldaten), sku, stockLevel, available, reserved, announced und updatedAt. Der Händler übernimmt die Werte in das Lager des Fulfillers; sein Shop zeigt dann den Bestand beim Fulfiller.
Anlieferung und Rückläufer
Eine Anlieferung (inbounds) nennt number, expectedAt, shipper (Lieferant des Händlers, nur zur Anzeige), trackingNumber, carrier und items mit sku und quantity. Beim Fulfiller entsteht daraus eine Anlieferung im Status „Bestellt“; der Wareneingang läuft in seiner Lager-App, quantityDelivered und status kommen über die Liste zurück.
Das Abweichungsprotokoll steht in derselben Antwort: je Position quantityDamaged (beschädigt angeliefert, nicht eingelagert), eine Mehrmenge als quantityDelivered über quantity, dazu receiptClosedAt (Wareneingang abgeschlossen – was dann fehlt, ist Fehlmenge), receiptNote (Anmerkung des Lagers) und photos (url, sku der Position oder leer, createdAt).
Ein Rückläufer (returns) nennt number, orderNumber (Bestellnummer des Händlers, damit der Fulfiller den Auftrag findet), sender, trackingNumber, carrier und items mit sku, quantity und reason. Nach der Prüfung stehen je Position receivedNew, receivedOpened, receivedBWare und receivedDefective in der Antwort, der Status wechselt auf ARRIVED.
Webhooks (Fulfiller → Händler)
Mit PUT /v1/fulfillment/webhook und { "url": "https://…", "secret": "…" } registriert der Händler, wohin der Fulfiller Ereignisse schickt. Trade Bridge macht das beim Anlegen der Verbindung selbst; ein eigenes System registriert sich einmal.
Jedes Ereignis ist ein POST mit JSON-Body und den Headern x-trade-bridge-event, x-trade-bridge-delivery (eindeutige ID, für Wiederholungen) und x-trade-bridge-signature (sha256=<HMAC-SHA256 des Bodys mit dem Secret, hex>). Antwortet der Empfänger nicht mit 2xx, wiederholt der Fulfiller mit wachsendem Abstand, bis zu acht Mal.
| Ereignis | Wann | data |
|---|---|---|
outbound.shipped | Lieferschein versendet (erstes Paket) | outbound wie in der Liste, dazu stock der betroffenen Artikel |
outbound.updated | Weiteres Paket | outbound, stock |
outbound.cancelled | Fulfiller hat storniert | outbound, stock |
inbound.updated | Wareneingang gebucht | inbound, stock |
return.updated | Rückläufer geprüft | return, stock |
stock.updated | Bestand geändert (Inventur, Umlagerung, unklares Paket) | stock |
tariff.updated | Fulfiller hat den Tarif gespeichert | tariff wie bei GET /tariff |
request.updated | Anfrage angelegt oder weitergeschaltet (Status, Preis, Priorität) | request (siehe unten) |
request.message | Nachricht des Fulfillers im Verlauf einer Anfrage | requestMessage (requestId, messageId, html, author, createdAt, attachments) |
ping | Test über /webhook/test | Name und Kürzel des Auftraggebers |
{
"id": "cmg…",
"event": "outbound.shipped",
"occurredAt": "2026-10-09T15:02:11.000Z",
"attempt": 1,
"data": {
"outbound": { "id": "…", "number": "#1234-001", "status": "SHIPPED", "packages": [ … ] },
"stock": [ { "externalId": "…", "sku": "SH-KNIT-NAV-M", "stockLevel": 41, "available": 39, … } ]
}
}Abrechnung
Der Fulfiller rechnet Leistungen gesammelt ab (Fulfillment → Abrechnung): Pick, Pack, Versand, Kartonage, Pauschale, Wareneingang, Retourenprüfung, Lagergeld, Zusatzleistungen, FNSKU-Etiketten und Paletten je Auftraggeber und Zeitraum (Preise in GET /tariff: services, fnskuLabelPerUnit, palletPerUnit), als Rechnung über seine Buchhaltung mit beigelegtem Leistungsnachweis. Diese Rechnung läuft nicht über die API.
Kopplung per Unternehmens-ID
Zwei Trade-Bridge-Instanzen verbinden sich ohne Schlüssel-Austausch von Hand: Der Händler trägt die Unternehmens-ID des Fulfillers ein, seine Instanz schickt POST /v1/fulfillment/pairing mit { "token", "callbackUrl", "merchant": { "slug", "name", "company", "email", "vatId", "street", "zip", "city", "country" } }. Beim Fulfiller erscheint die Anfrage unter Fulfillment → Auftraggeber. Bestätigt er, ruft seine Instanz die callbackUrl mit dem Einmal-Token und dem neuen API-Schlüssel auf; lehnt er ab, kommt eine Absage. Ein eigenes System kann denselben Weg gehen und den Schlüssel am Rückruf entgegennehmen. DELETE /v1/fulfillment/pairing hebt die Verbindung auf, solange keine Lieferscheine, Anlieferungen oder Rückläufer offen sind.
Anfragen (Sonderaufträge)
Alles, was nicht in Lieferschein, Anlieferung oder Rückläufer passt (Entsorgen, Etikettieren, Umpacken, Verzollung, Fotos), ist eine Anfrage. Der Fulfiller stellt Vorlagen bereit (GET /v1/fulfillment/request-templates: Felder, Ablauf, Abrechnung). Der Händler ist der Anfragende, der Fulfiller der Antwortende.
Feste Status-Bausteine: OPEN, IN_REVIEW, QUOTED (Angebot mit billing FLAT/HOURLY und price/hourlyRate), APPROVED, DECLINED, IN_PROGRESS, DONE (bei HOURLY mit hours), CANCELLED. Welche gelten und wer sie setzen darf, steht im flow der Vorlage. Typischer Ablauf: Händler stellt (OPEN) → Fulfiller bietet an (QUOTED) → Händler gibt frei (APPROVED) → Fulfiller arbeitet (IN_PROGRESS) und meldet DONE. priority ist 0 oder 1.
POST /v1/fulfillment/requests
{
"id": "req_123", "number": 7, "createdBy": "REQUESTER", "status": "OPEN", "priority": 0,
"title": "200 Stück entsorgen", "description": "…",
"templateKey": "entsorgung", "templateName": "Entsorgung",
"fields": [ { "key": "artikel", "label": "Artikel", "type": "article", "value": "SH-KNIT-NAV-M", "display": "Strickpulli navy M" } ],
"billing": "NONE", "price": null, "hourlyRate": null, "hours": null, "billingNote": null,
"dueDate": "2026-10-20", "decidedAt": null, "doneAt": null,
"createdAt": "2026-10-09T15:02:11.000Z", "updatedAt": "2026-10-09T15:02:11.000Z"
}Dieselbe Struktur kommt als data.request im Webhook request.updated zurück, mit der id, unter der der Händler die Anfrage kennt. Nachrichten im Verlauf gehen als POST /v1/fulfillment/requests/{id}/messages mit { "messageId", "html", "author", "createdAt", "attachments" } an den Fulfiller und kommen als request.message zurück; messageId schützt vor Doppelungen. Erledigte Anfragen mit Berechnung stehen in der nächsten Leistungsabrechnung des Fulfillers.