Error format
The whole BSP API uses a single error envelope, inspired by Meta’s format:
{
"error": {
"code": 400,
"error_data": {
"details": "error description"
}
}
}Error codes
Client errors (4xx)
| Code | Meaning |
|---|---|
400 | Invalid request: malformed body, missing parameters, failed validation |
401 | Not authenticated: missing or invalid token |
403 | Not authorized: no BSP_CN to operate on another client, or DID outside the hierarchy |
404 | Resource not found (nonexistent template, unavailable rate) |
413 | Multipart exceeds the maximum allowed size |
External service errors (5xx)
When the API cannot reach an external service (e.g. Meta), the error never exposes infrastructure details:
| Code | Detail |
|---|---|
502 | upstream service unavailable — the external service did not respond |
504 | upstream timeout — the external service exceeded the wait time |
Golden rule: errors with a response code from the external service are preserved (e.g. a
429 from Meta is returned as 429). Generic failures without a response always collapse to 502.Common examples
Failed validation
{
"error": {
"code": 400,
"error_data": {
"details": "did is required"
}
}
}Non-HTTPS media header URL
{
"error": {
"code": 400,
"error_data": {
"details": "URL must use https scheme"
}
}
}Media header with both header_source and header_handle
{
"error": {
"code": 400,
"error_data": {
"details": "header_source and header_handle are mutually exclusive for media headers"
}
}
}Unreachable external service
{
"error": {
"code": 502,
"error_data": {
"details": "upstream service unavailable"
}
}
}Raw Meta errors
When the Meta API returns an error (e.g. rejection due to category policy), the platform passes it as-is to the client, preserving Meta’s code and original details.
For more information about Meta errors, see Meta’s error documentation.