OBAPI OBAPI

Error Handling

OBAPI uses conventional HTTP response codes and a structured JSON error body.

HTTP status codes

Code Meaning When
200 OK Request succeeded
400 Bad Request Invalid parameters (e.g. malformed date, unknown filter value)
401 Unauthorized Missing or invalid Bearer token
403 Forbidden Token valid but insufficient permissions for this resource
404 Not Found Object does not exist or endpoint not implemented
405 Method Not Allowed Using POST/PUT/DELETE on a read-only API
422 Unprocessable Entity Parameters are syntactically valid but semantically wrong
429 Too Many Requests Rate limit exceeded (if provider implements rate limiting)
500 Internal Server Error Unexpected server-side failure
503 Service Unavailable Server temporarily down for maintenance

Error response format

All errors return a JSON body with this structure:

{
    "error": {
        "type": "string -- error category",
        "code": "string -- machine-readable error code",
        "message": "string -- human-readable description"
    }
}

Error types

Type HTTP Code Description
authentication_error 401 Token missing, invalid, or expired
authorization_error 403 Token valid but access denied
not_found 404 Resource does not exist
invalid_request 400, 422 Request parameters are invalid
method_not_allowed 405 HTTP method not supported
rate_limit 429 Too many requests
server_error 500 Internal failure
service_unavailable 503 Temporary downtime

Error codes reference

Authentication (401)

Code Message Cause
MISSING_TOKEN Authorization header is required No Authorization: Bearer header sent
INVALID_TOKEN The provided Bearer token is invalid or expired Token does not match any active API key
EXPIRED_TOKEN The provided Bearer token has expired Token was valid but is past its expiry

Authorization (403)

Code Message Cause
INSUFFICIENT_PERMISSIONS Your token does not have access to this resource API key exists but lacks the required scope

Not Found (404)

Code Message Cause
OBJECT_NOT_FOUND Requested object does not exist The {id} does not match any record
ENDPOINT_NOT_FOUND This endpoint is not available Server does not implement this endpoint
DOCUMENT_NOT_FOUND No document available for this object The object exists but has no downloadable file

Invalid Request (400, 422)

Code Message Cause
INVALID_PARAMETER Parameter 'X' is invalid A query parameter has an unexpected value
INVALID_DATE_FORMAT Date must be in YYYY-MM-DD format A date parameter is malformed
INVALID_DATE_RANGE date_start must be before date_end Date range is inverted
PAGE_OUT_OF_RANGE Page number exceeds available pages Requested page > total_pages
PER_PAGE_TOO_LARGE per_page cannot exceed 200 Requested more than 200 items per page
INVALID_STATUS_FILTER Unknown status value 'X' Status filter does not match allowed values

Rate Limit (429)

Code Message Cause
RATE_LIMIT_EXCEEDED Too many requests, retry after X seconds Provider-defined rate limit hit

When a 429 is returned, the response includes a Retry-After header (in seconds).

Server Errors (500, 503)

Code Message Cause
INTERNAL_ERROR An unexpected error occurred Bug or misconfiguration on the server
SERVICE_UNAVAILABLE Service temporarily unavailable Planned maintenance or overload

Examples

Missing authentication

GET /obapi/v1/invoices
(no Authorization header)
HTTP/1.1 401 Unauthorized

{
    "error": {
        "type": "authentication_error",
        "code": "MISSING_TOKEN",
        "message": "Authorization header is required"
    }
}

Object not found

GET /obapi/v1/invoices/99999
Authorization: Bearer valid-token
HTTP/1.1 404 Not Found

{
    "error": {
        "type": "not_found",
        "code": "OBJECT_NOT_FOUND",
        "message": "Requested object does not exist"
    }
}

Invalid date range

GET /obapi/v1/invoices?date_start=2024-12-31&date_end=2024-01-01
Authorization: Bearer valid-token
HTTP/1.1 422 Unprocessable Entity

{
    "error": {
        "type": "invalid_request",
        "code": "INVALID_DATE_RANGE",
        "message": "date_start must be before date_end"
    }
}

Empty results (not an error)

A query that returns no matching items is not an error. It returns 200 with an empty array:

{
    "items": [],
    "pagination": {
        "page": 1,
        "per_page": 50,
        "total_items": 0,
        "total_pages": 0
    }
}

Best practices

  • Always check the HTTP status code first before parsing the body.
  • Log the full error response (type, code, message) for debugging.
  • Handle 429 gracefully by respecting the Retry-After header.
  • Do not retry on 4xx errors (except 429) -- the request is invalid and will fail again.
  • Retry on 5xx errors with exponential backoff (1s, 2s, 4s, max 3 retries).
  • Use Discovery to check which endpoints are available before calling them.