paybondpaybond
Sign in

Error envelope and status codes

Canonical error shape, HTTP status contract, and retry rules for Harbor, Gateway, and Signal APIs.

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.code is 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.message is safe to log. It never contains secrets, bearer tokens, or cross-tenant identifiers.
  • error.details is optional, structured, and only present when it adds diagnosability. It is not user-facing copy.
  • request_id is 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

StatusMeaningRetriable?
400 Bad RequestValidation failure (bad JSON, missing fields, disallowed parameters, predicate document malformed).No — fix the request.
401 UnauthorizedMissing, 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 ForbiddenAuthentication 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 FoundResource 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 ConflictState 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 GoneAudit export bundle expired or revoked.No — request a new export.
422 Unprocessable EntityRequest is well-formed but semantically inconsistent with server state (for example predicate evaluation error distinct from passed: false).No.
429 Too Many RequestsRate limit tripped (currently: arbitration export). Honor Retry-After.Yes — back off and retry.
500 Internal Server ErrorUnhandled server error. request_id is the primary diagnostic anchor.Sometimes — retry with exponential backoff on idempotent or idempotency-key-guarded requests only.
503 Service UnavailableA 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

ErrorThrown when
HarborHttpError (TS / Python)A Harbor HTTP call returns a non-2xx. Carries status_code, url, and body_text.
GatewayAuthErrorPOST /v1/auth/harbor-access returned non-2xx while the Kit was minting a Harbor JWT.
PaybondCapabilityErrorCapability verification failed (invalid signature, wrong tenant, expired, revoked).

See Error handling for language-level patterns (retry policy, structured logging, circuit breakers).