API Referenz
Basis-URL: https://api.msv3gateway.example.com
Alle Anfragen und Antworten verwenden Content-Type: application/json, sofern nicht anders angegeben.
Authentifizierung
Jeder geschuetzte Endpunkt erfordert zwei Authentifizierungsebenen als HTTP-Header.
| Header | Erforderlich bei | Beschreibung |
|---|---|---|
X-API-Key | Alle Endpunkte ausser GET /v1/health | Ihr Gateway-API-Schluessel. Identifiziert Ihr Konto und setzt Rate-Limits durch. |
X-MSV3-Username | Grosshaendler-Endpunkte | MSV3-Benutzername vom Grosshaendler. |
X-MSV3-Password | Grosshaendler-Endpunkte | MSV3-Passwort vom Grosshaendler. |
Zugangsdaten werden nur fuer die Dauer des SOAP-Aufrufs im Speicher gehalten und danach geloescht. Sie werden niemals persistiert.
Sandbox-Modus
API-Schluessel mit dem Praefix pk_test_ leiten Anfragen an die Sandbox-Umgebung weiter.
Anfragen an noweda_test erreichen den echten NOWEDA-Testserver. Alle anderen Grosshaendler werden auf einen integrierten Mock geleitet.
Idempotency Keys
Alle aendernden Endpunkte akzeptieren einen optionalen Idempotency-Key-Header.
Idempotency-Key: my-order-2026-04-27-001 Das Gateway speichert den Schluessel-Hash und die zugehoerige Antwort fuer 24 Stunden. Wiederholte Anfragen mit dem gleichen Schluessel liefern die gespeicherte Antwort zurueck, ohne den SOAP-Aufruf erneut auszufuehren.
Fehlerformat
Alle 4xx- und 5xx-Antworten verwenden diese Struktur:
{
"error": "invalid_request",
"message": "PZN must be 1-8 digits, got: 'abc123'",
"wholesaler": "noweda",
"error_code": "3002"
} Vollstaendige Fehler-Referenz: Fehlercodes und Loesungen
Rate Limiting
Anfragen werden pro API-Schluessel limitiert. Bei Ueberschreitung antwortet das Gateway mit 429 und einem Retry-After-Header.
HTTP/1.1 429 Too Many Requests
Retry-After: 30 Endpunkte
GET /v1/health
Liveness-Probe. Keine Authentifizierung erforderlich.
// Antwort 200
{
"status": "ok",
"version": "1.0.0"
} GET /v1/wholesalers
Gibt alle registrierten Grosshaendler zurueck. Erfordert: X-API-Key
// Antwort 200
{
"wholesalers": [
{
"id": "noweda",
"name": "NOWEDA eG",
"verified": true,
"capabilities": ["order", "availability", "contracts"]
}
]
} POST /v1/wholesalers/custom
Registriert einen eigenen MSV3-Grosshaendler-Endpunkt. Erfordert: X-API-Key
// Anfrage
{
"name": "My Wholesaler GmbH",
"endpoint": "https://msv3.my-wholesaler.de/msv3"
}
// Antwort 200
{
"wholesaler": {
"id": "my-wholesaler-gmbh",
"name": "My Wholesaler GmbH",
"endpoint": "https://msv3.my-wholesaler.de/msv3",
"verified": false,
"capabilities": []
}
} POST /v1/connection/test
Prueft MSV3-Zugangsdaten gegen einen Grosshaendler. Gibt Round-Trip-Latenz zurueck.
Erfordert: X-API-Key, X-MSV3-Username, X-MSV3-Password
// Anfrage
{ "wholesaler": "noweda" }
// Antwort 200
{
"connected": true,
"wholesaler": "noweda",
"latency_ms": 142
} Fehler: 400, 401, 404, 502
POST /v1/availability
Echtzeit-Verfuegbarkeit fuer bis zu 50 Artikel abfragen, inklusive Lieferanteile, geschaetzter Lieferzeiten und Substitutionen.
Erfordert: X-API-Key, X-MSV3-Username, X-MSV3-Password
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
wholesaler | string | Ja | Grosshaendler-ID |
items | array | Ja | 1-50 Artikel |
items[].pzn | string | Ja | PZN, 1-8 Ziffern |
items[].quantity | integer | Ja | Angefragte Menge |
items[].demand_type | enum | Nein | direct (Standard), one_of_many, unspecified |
// Antwort 200
{
"wholesaler": "noweda",
"response_type": "standard",
"items": [
{
"pzn": "761271",
"quantity_requested": 5,
"available": true,
"deliveries": [
{
"type": "normal",
"quantity": 5,
"tour": "00345H",
"estimated_at": "2026-04-28T10:00:00"
}
],
"substitution": null
}
]
} Fehler: 400, 401, 404, 502
POST /v1/availability/bulk
Schlanke Pruefung, welche PZNs aus einer Liste aktuell auf Lager sind. Keine Mengen oder Bedarfsarten noetig. Nuetzlich zum Vorfiltern grosser Kataloge.
// Anfrage
{
"wholesaler": "noweda",
"pzns": ["761271", "4211896", "10203595"]
}
// Antwort 200
{
"wholesaler": "noweda",
"available_pzns": ["761271", "4211896"]
} GET /v1/contracts?wholesaler=noweda
Vertragsdaten zwischen Ihrer Apotheke und dem Grosshaendler abrufen - Faehigkeiten, unterstuetzte Bestelltypen und alle woechentlichen Bestellfenster.
// Antwort 200
{
"wholesaler": "noweda",
"customer_id": "Now00079800",
"capabilities": {
"bulk_availability": true,
"return_offers": true,
"substitution": false,
"order_types": {
"normal": true,
"batch": true,
"special": false,
"shipping": false
}
},
"delivery_windows": [
{ "day": "monday", "closes_at": "10:29" },
{ "day": "monday", "closes_at": "14:30" }
]
} POST /v1/orders
Arzneimittelbestellung an den Grosshaendler ueber MSV3 uebermitteln. Mit ?dry_run=true validieren, ohne die Bestellung aufzugeben.
Erfordert: X-API-Key, X-MSV3-Username, X-MSV3-Password
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
wholesaler | string | Ja | Grosshaendler-ID |
items | array | Ja | Mindestens 1 Artikel |
items[].pzn | string | Ja | PZN, 1-8 Ziffern |
items[].quantity | integer | Ja | Bestellmenge |
items[].delivery_preference | enum | Nein | normal, backorder, grouped, disposition |
// Antwort 200
{
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "confirmed",
"wholesaler": "noweda",
"dry_run": false,
"items": [
{
"pzn": "761271",
"quantity_ordered": 3,
"quantity_confirmed": 3,
"delivery_preference": "backorder",
"deliveries": [
{
"type": "normal",
"quantity": 3,
"tour": "00345H",
"tour_id": "00345H2704261403",
"estimated_at": "2026-04-28T10:00:00"
}
]
}
]
} status-Werte: confirmed, dry_run, queued_night_mode
Fehler: 400, 401, 404, 422 (Bestellung abgelehnt), 502
GET /v1/orders/{order_id}/status?wholesaler=noweda
Aktuellen Status einer zuvor aufgegebenen Bestellung abrufen.
// Antwort 200
{
"order_id": "GW-ABCDEF12",
"status": "available",
"items": [
{
"pzn": "761271",
"quantity_ordered": 3,
"delivery_preference": "backorder"
}
]
} status-Werte: available, expired, unknown
GET /v1/deliveries?wholesaler=noweda
Unbestaetigte Lieferavise vom Grosshaendler abrufen. Nach Verarbeitung mit POST /v1/deliveries/confirm bestaetigen.
// Antwort 200
{
"wholesaler": "noweda",
"deliveries": [
{
"tracking_number": "LS-123",
"barcode": "1*123",
"order_type": "normal",
"date": "2026-04-27",
"has_shortages": false,
"items": [
{
"pzn": "761271",
"quantity_delivered": 3,
"shortages": 0
}
]
}
]
} POST /v1/deliveries/confirm
Lieferungen anhand ihrer Trackingnummern bestaetigen.
// Anfrage
{
"wholesaler": "noweda",
"tracking_numbers": ["LS-123", "LS-124"]
}
// Antwort 200
{
"wholesaler": "noweda",
"confirmed": ["LS-123", "LS-124"],
"status": "confirmed"
} GET /v1/deliveries/history?wholesaler=noweda
Historische Lieferavise abrufen. Filtern nach Trackingnummer oder Barcode.
POST /v1/returns
Retourenantrag einreichen. Jeder Artikel muss die Original-Lieferscheinnummer und einen Retourengrund angeben.
| Wert | Beschreibung |
|---|---|
order_error | Artikel versehentlich bestellt |
not_delivered | Berechnet, aber nicht erhalten |
damaged | Beschaedigt eingetroffen |
expiry_too_short | Verfallsdatum zu nah |
over_delivered | Mehr Stueck als bestellt geliefert |
POST /v1/returns/announce
Bevorstehende Retoure ankuendigen. Der Grosshaendler kann die Retoure in mehrere Anteile aufteilen.
POST /v1/returns/offers
Preis-/Gutschrift-Informationen vom Grosshaendler fuer eine potenzielle Retoure anfordern. Erfordert die return_offers-Faehigkeit im Vertrag.
GET /v1/documents/{id}?wholesaler=noweda
PDF-Dokument (Lieferschein, Retourenlabel) anhand seiner ID herunterladen. Antwort: application/pdf binaer.
POST /v1/webhooks
Webhook-Abonnement erstellen. Erfordert nur X-API-Key -- keine MSV3-Zugangsdaten.
| Ereignis | Ausloeser |
|---|---|
delivery.received | Neue Lieferbenachrichtigung verfuegbar |
delivery.shortage | Lieferung enthaelt Fehlmengen |
order.status_changed | Bestellstatus aktualisiert |
wholesaler.status_changed | Grosshaendler-Endpunkt ist hoch-/runtergefahren |
// Anfrage
{
"url": "https://example.com/hooks/msv3",
"wholesaler": "noweda",
"events": ["delivery.received", "order.status_changed"]
}
// Antwort 201
{
"id": "whk_a1b2c3d4e5f6",
"url": "https://example.com/hooks/msv3",
"wholesaler": "noweda",
"events": ["delivery.received"],
"signing_secret": "a1b2c3d4e5f6...",
"active": true
} Wichtig: Das
signing_secretwird nur einmal zurueckgegeben. Speichern Sie es sicher.
GET /v1/webhooks
Alle Webhook-Abonnements auflisten. Das Signing-Secret ist maskiert.
DELETE /v1/webhooks/{id}
Webhook-Abonnement dauerhaft loeschen. Gibt 204 bei Erfolg zurueck.
Webhook-Signaturen
Jede Webhook-Zustellung enthaelt einen X-MSV3-Signature-Header mit dem HMAC-SHA256-Digest des Anfrage-Bodies.
X-MSV3-Signature: sha256=a1b2c3d4e5f6...
X-MSV3-Event: delivery.received
X-MSV3-Request-Id: evt_9f3a... Verifizieren Sie immer die Signatur, bevor Sie Webhook-Payloads verarbeiten. Verwenden Sie Roh-Bytes -- parsen Sie den Body nicht vor der Verifizierung.