Skip to main content
The API uses standard HTTP status codes and returns errors in a consistent JSON format.

HTTP status codes

Every response carries one of these status codes. Check the code first, then read the response body for details:
Create endpoints do not all return the same status code. Transaction and record endpoints (for example POST /public/v2/bills/) return 200; master-data endpoints (for example POST /public/v2/customers/) return 201. Check the specific endpoint in the API reference for the documented response code.

Error response format

All errors follow this structure:
  • errors.__all__: General errors not specific to a field
  • errors.<field_name>: Errors specific to a particular field
Some errors also carry two top-level fields alongside errors:
  • error_code (string, optional): Stable identifier of the error
  • error_reason (string, optional): General explanation of the error
The 409 and 422 responses tied to retry handling are described in the idempotency and write validation guide.

Common errors

Authentication error (403)

Returned when the X-API-KEY header is missing or empty, or the key is unknown or revoked. A key that authenticates but lacks the roles for the operation also returns 403, with Access denied as the message. Authentication covers both cases.

Subscription required (402)

Returned when your organization does not have the subscription required for the requested feature.

Validation error (422)

Returned when the request body fails validation. Each key in errors names a field that failed, with the reasons as a list:
An example with error_code and error_reason, from a write in a locked accounting period:

Not found (404)

Returned when no record matches the ID or number in the request path:

Rate limit exceeded (429)

Returned when the API key exceeds its rate limit. Rate limiting covers the limits and how to use the Retry-After header:

Handling errors

Best Practices:
  • Always check HTTP status codes
  • Parse the errors object for field-specific details
  • Implement retry logic for rate limits (429) and server errors (5xx)
  • Use the Idempotency-Key header so retries do not create duplicate records
  • Log error responses for debugging

Retrying safely with idempotency keys

Write requests (POST, PUT, PATCH, DELETE) accept an optional Idempotency-Key header so a retry after a network error or timeout does not create a duplicate record.
  • Send a unique value in the Idempotency-Key header on the original request. A UUID works well.
  • If you retry with the same key, the API replays the original response instead of processing the request again. No duplicate record is created.
  • Replays are available for 48 hours after the original request. After that window, the key is forgotten and a retry with the same key is treated as a new request.
  • Reusing the same key with a different request body returns 422. Either use a new key for the new request, or send the exact same body.

Example


Next: Explore the API Reference →
Last modified on October 28, 2026