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

HTTP status codes

Status CodeMeaning
200Success
201Resource created
400Bad request (malformed request)
401Missing API key
402Subscription required for this feature
403Invalid or revoked API key
404Resource not found
422Validation error
429Rate limit exceeded
500Server error
503Service unavailable
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:
{
  "success": false,
  "errors": {
    "<field_name|__all__>": ["error message"]
  }
}
  • errors.__all__: General errors not specific to a field
  • errors.<field_name>: Errors specific to a particular field

Common errors

Authentication error (403)

{
  "success": false,
  "errors": {
    "__all__": ["API key authentication failed"]
  }
}

Subscription required (402)

Returned when your organization does not have the subscription required for the requested feature.
{
  "success": false,
  "errors": {
    "__all__": ["Subscription required for this feature"]
  }
}

Validation error (422)

{
  "success": false,
  "errors": {
    "customer_id": ["Customer with this ID does not exist"],
    "date": ["Invalid date format. Use ISO 8601 format (YYYY-MM-DD)"],
    "lines": ["At least one line item is required"]
  }
}

Not found (404)

{
  "success": false,
  "errors": {
    "__all__": ["Invoice matching query does not exist."]
  }
}

Rate limit exceeded (429)

{
  "success": false,
  "errors": {
    "__all__": ["Rate limit exceeded. Please try again later."]
  }
}

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)
  • Log error responses for debugging

Example

response = requests.post(url, headers=headers, json=data)

if response.status_code in (200, 201):
    # Success, 200 for record endpoints, 201 for master-data endpoints
    result = response.json()
elif response.status_code == 402:
    # Subscription not enabled for this feature
    print(response.json()["errors"]["__all__"])
elif response.status_code == 422:
    # Validation errors
    errors = response.json()["errors"]
    for field, messages in errors.items():
        print(f"{field}: {messages}")
elif response.status_code == 429:
    # Rate limited - wait and retry
    time.sleep(60)
    response = requests.post(url, headers=headers, json=data)
else:
    # Other error
    print(f"Error {response.status_code}: {response.json()}")

Next: Explore the API Reference →
Last modified on July 13, 2026