Error Handling
The Developer API uses standard HTTP status codes and returns structured JSON error responses.
Error Response Format
{
"error": "Human-readable error message"
}
Validation errors include a list of specific field errors:
{
"error": "Validation failed",
"errors": [
"Name can't be blank",
"Email is invalid"
]
}
Status Codes
Success
| Code | Meaning |
|---|---|
200 OK | Request succeeded |
201 Created | Resource created successfully |
Client Errors
| Code | Meaning | Common Cause |
|---|---|---|
400 Bad Request | Missing required parameter | Check request body |
401 Unauthorized | Invalid or missing API key | Check X-API-Key header |
403 Forbidden | Insufficient scope or endpoint not available | Check key scopes |
404 Not Found | Resource doesn't exist | Check the ID |
409 Conflict | Duplicate record | Resource already exists |
422 Unprocessable Entity | Validation failed | Check errors array |
429 Too Many Requests | Rate limit exceeded | Wait and retry |
Server Errors
| Code | Meaning |
|---|---|
500 Internal Server Error | Something went wrong on our end |
Rate Limiting (429)
When you exceed your rate limit, the response includes headers telling you when to retry:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711108860
{"error": "Rate limit exceeded. Retry later."}
Handle 429 gracefully
Implement exponential backoff in your integration. Wait the number of seconds in Retry-After before retrying.
Common Mistakes
Wrong header name
# Wrong
curl -H "Authorization: Bearer bpos_abc..."
# Correct
curl -H "X-API-Key: bpos_abc..."
Missing scope
If you get 403 Forbidden with "Insufficient scope", check that your API key has the required scope for that endpoint. For example, reading customers requires customers:read.
Write on read-only endpoint
Some endpoints only allow read access via API keys (e.g., sales). Attempting to create or modify resources on read-only endpoints returns 403 Forbidden.