Fehlerreferenz
Alle Non-2xx-Responses von /api/v1/* verwenden RFC 7807 application/problem+json:
1HTTP/1.1 422 Unprocessable Entity
2Content-Type: application/problem+json
3
4{
5 "type": "https://accounting.example/problems/validation-failed",
6 "title": "The given data was invalid.",
7 "status": 422,
8 "detail": "The invoice.positions.0.amount_cents field is required when invoice.positions.0.mode is fixed.",
9 "errors": {
10 "invoice.positions.0.amount_cents": [
11 "The amount_cents field is required when mode is fixed."
12 ]
13 }
14}
Die type-URI ist stabil und ist das, worauf Ihr Code verzweigen sollte — niemals auf den title (der menschenlesbar ist und übersetzt sein kann).
#Häufige Problemtypen
#validation-failed (422)
Fehler in der Body-Form. Enthält ein errors-Objekt, das nach Feldpfad indiziert ist.
Was tun: dem Entwickler / Händler anzeigen; niemals dem Endkunden (die Feldpfade leaken das Schema). Die meisten Validierungsfehler bedeuten, dass Ihr Shop etwas geschickt hat, das Vorgio nicht akzeptiert — korrigieren Sie die Request-Form.
#idempotency-key-conflict (409)
Sie haben einen Idempotency-Key mit einem anderen Request-Body wiederverwendet. Vorgio lehnt ab, weil das einzig sichere Verhalten ist, den Konflikt sichtbar zu machen.
Was tun: wählen Sie einen anderen Idempotency-Key (oder schränken Sie den vorhandenen auf diesen Versuch ein — hängen Sie einen Retry-Counter an, z. B. wc-order-1234-checkout-r2). Modifizieren Sie nicht den Body und senden Sie ihn nicht unter demselben Key erneut.
#forbidden (403)
Der Token verfügt nicht über die Berechtigung, die der Endpoint erfordert. Zum Beispiel der Aufruf von POST /v1/checkouts mit einem Token, der nur clients:read hat.
Was tun: stellen Sie den Token mit den korrekten Abilities neu aus. Das Preset "Payment-provider integration" in der Token-UI wählt das richtige Set aus.
#unauthenticated (401)
Bearer-Token fehlt, ist fehlerhaft oder abgelaufen/widerrufen.
Was tun: prüfen Sie den Authorization-Header. Das Format ist Bearer {numeric_id}|{plain_secret} — beide Hälften durch einen Pipe getrennt. Senden Sie nicht nur die Secret-Hälfte.
#too-many-requests (429)
Rate Limit überschritten. Siehe Rate Limits.
#not-found (404)
Die Ressource existiert in Ihrem Team nicht. Beachten Sie, dass Ressourcen in anderen Teams ebenfalls 404 zurückgeben, nicht 403 — das ist Absicht (verhindert das Leaken der Existenz von Daten anderer Teams).
Was tun: prüfen Sie die client_id / invoice_id doppelt. Falls sie existieren sollte, prüfen Sie, ob sie soft-deleted wurde oder ob der Token zum falschen Team gehört.
#client-has-retained-invoices (409, bei DELETE /v1/clients/{id})
Sie haben versucht, einen Kunden zu löschen, dessen Rechnungen sich innerhalb der gesetzlichen 10-jährigen Aufbewahrungsfrist (HGB §257, AO §147) befinden. Vorgio lehnt dies aus rechtlichen Gründen ab.
Was tun: nicht löschen; stattdessen in Ihrem Shop archivieren.
#internal-error (5xx)
Etwas ist serverseitig explodiert. Das detail kann eine Fehlerreferenz für den Support enthalten.
Was tun: mit exponentiellem Back-off wiederholen; falls es weiterhin auftritt, senden Sie die Fehlerreferenz an den Vorgio-Support. Zeigen Sie die interne Fehlermeldung nicht Ihrem Endkunden an.
#Feldpfade bei Validierungsfehlern
Bei verschachtelten Request-Bodies (wie /v1/checkouts) verwenden Error-Keys Punkt-Notation:
| Pfad | Was er bedeutet |
|---|---|
client.external_id |
Top-Level-Feld im client-Block |
invoice.positions.0.amount_cents |
Das amount_cents-Feld der ersten Position |
send.cc.2 |
Der dritte Eintrag im send.cc-Array |
Wenn Sie Fehler an einen Entwickler zurückgeben, rendern Sie jeden Eintrag im errors-Array als Aufzählungspunkt unter dem zugehörigen Feldpfad.
#Empfohlenes Error-Handling-Muster (PHP)
1try {
2 $response = $http->post('/api/v1/checkouts', [...]);
3} catch (RequestException $e) {
4 $body = json_decode((string) $e->getResponse()->getBody(), true);
5 $type = $body['type'] ?? '';
6
7 match (true) {
8 str_ends_with($type, 'validation-failed') => $this->reportToDeveloper($body),
9 str_ends_with($type, 'too-many-requests') => $this->scheduleRetry($body, $e->getResponse()->getHeader('Retry-After')[0] ?? 60),
10 str_ends_with($type, 'idempotency-key-conflict') => $this->logAndAlertEng($body),
11 $e->getCode() >= 500 => $this->retryWithBackoff(),
12 default => throw $e,
13 };
14}