Errors
Paybond services share one wire error envelope and a common set of status-code semantics. Kit SDKs wrap these into typed exceptions (HarborHttpError, GatewayAuthError); see Error handling for the language-level surface.
Envelope
All 4xx and 5xx responses (outside of 3xx redirects and the 410 Gone bundle-expired case) return a JSON object of the form:
{
"error": {
"code": "intent.predicate.failed",
"message": "predicate evaluation failed",
"details": { "clause": "completion", "path": ["status"] }
},
"request_id": "01JABY5…"
}Rules:
error.codeis a stable, snake-cased, dotted identifier. New codes may be added; callers must treat unknown codes as their parent class (prefix before the last dot).error.messageis safe to log. It never contains secrets, bearer tokens, or cross-tenant identifiers.error.detailsis optional, structured, and only present when it adds diagnosability. It is not user-facing copy.request_idis the Gateway request correlation id. Include it when reporting issues.
Some older routes return { "error": "message" } as a plain string. Clients should accept either shape: read response.error as either a string or an object with code / message.
Status-code contract
| Status | Meaning | Retriable? |
|---|---|---|
400 Bad Request | Validation failure (bad JSON, missing fields, disallowed parameters, predicate document malformed). | No — fix the request. |
401 Unauthorized | Missing, expired, or mismatched Bearer JWT. Also returned when x-tenant-id header does not match the tid claim. | Yes — refresh credentials or re-authenticate. Kit sessions rotate automatically. |
403 Forbidden | Authentication succeeded, but the principal lacks RBAC or entitlement for the operation (for example policy lifecycle requires tenant.admin). | No — ask tenant admin to grant the required role. |
404 Not Found | Resource does not exist in the authenticated tenant scope. Cross-tenant accesses return 404, not 403, so presence is not leaked. | Varies — retry only if the resource was just created. |
409 Conflict | State conflict. Examples: idempotency-key reuse with a different body; policy lifecycle transition from an invalid state; double-publish of the same version. | No — inspect state and either resolve or use a new key. |
410 Gone | Audit export bundle expired or revoked. | No — request a new export. |
422 Unprocessable Entity | Request is well-formed but semantically inconsistent with server state (for example predicate evaluation error distinct from passed: false). | No. |
429 Too Many Requests | Rate limit tripped (currently: arbitration export). Honor Retry-After. | Yes — back off and retry. |
500 Internal Server Error | Unhandled server error. request_id is the primary diagnostic anchor. | Sometimes — retry with exponential backoff on idempotent or idempotency-key-guarded requests only. |
503 Service Unavailable | A dependency (Postgres, Stripe, signing key, storage) is unavailable or not configured. | Yes — retry with backoff; page ops after the second 503 in a minute. |
Idempotency & safe retries
Mutating Harbor POSTs are safe to retry only when the same idempotency-key is reused with the same request body. A different body under the same key returns 409 Conflict and leaves the original response materialized. See harbor-idempotency-openapi.yaml.
GET requests are idempotent; retrying them on 5xx is always safe. DELETE /v1/compliance/audit-exports/{job_id} is idempotent — repeated calls return 200 once the row is gone.
Tenant-safe logging
Paybond services never put secrets, tokens, or another tenant's identifiers into error.message or error.details. When integrating, apply the same discipline: log request_id, error.code, and the status, but redact bearers and avoid logging other tenants' intent_id / operator_did unless a support session explicitly authorized the trace.
Kit surface
| Error | Thrown when |
|---|---|
HarborHttpError (TS / Python) | A Harbor HTTP call returns a non-2xx. Carries status_code, url, and body_text. |
GatewayAuthError | POST /v1/auth/harbor-access returned non-2xx while the Kit was minting a Harbor JWT. |
PaybondCapabilityError | Capability verification failed (invalid signature, wrong tenant, expired, revoked). |
See Error handling for language-level patterns (retry policy, structured logging, circuit breakers).