Errors
Red Cloud currently exposes two public error models:
- OAuth token endpoint errors
- CORE API wrapper errors
Your integration should treat those as two different contracts with different retry behavior.
OAuth errors
POST /api/auth/token returns OAuth-style errors.
These errors are about credential exchange. They are not the same as downstream messaging or number-operation failures.
Example: invalid client
{
"error": "invalid_client",
"error_description": "Client authentication failed"
}
Example: unsupported grant type
{
"error": "unsupported_grant_type",
"error_description": "Only client_credentials is supported"
}
Example: missing credentials
{
"error": "invalid_request",
"error_description": "client_id and client_secret are required"
}
CORE API errors
/api/core/* routes use the standardized CORE wrapper.
Shape
{
"error": {
"code": "INVALID_REQUEST",
"message": "Idempotency-Key header is required",
"details": {}
},
"requestId": "req_send_001"
}
What the wrapper means
error.codeis the machine-readable classificationerror.messageis the human-readable explanationerror.detailsmay include route-specific contextrequestIdshould be captured for support and escalation
HTTP status to error code patterns
400INVALID_REQUEST
401UNAUTHORIZED
403FORBIDDEN
404NOT_FOUND
409CONFLICT
500SERVER_ERROR
502UPSTREAM_ERROR
These are patterns, not a promise that every route emits every code in every scenario. Always parse the actual body returned.
Common scenarios
Invalid token
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing bearer token",
"details": {}
},
"requestId": "req_auth_001"
}
Forbidden number access
{
"error": {
"code": "FORBIDDEN",
"message": "sendFrom is not owned by this API client",
"details": {}
},
"requestId": "req_send_002"
}
Validation failure
{
"error": {
"code": "INVALID_REQUEST",
"message": "sendFrom must have campaignregId configured",
"details": {}
},
"requestId": "req_send_003"
}
Upstream platform dependency error
{
"error": {
"code": "UPSTREAM_ERROR",
"message": "Upstream search failed with status 502.",
"details": {
"providerStatus": 502
}
},
"requestId": "req_search_001"
}
How to handle errors in practice
Retry only when the problem is plausibly transient
Good retry candidates:
- transient
5xx UPSTREAM_ERROR- a protected API call that failed because the bearer token expired and can be refreshed once
Do not blindly retry validation or ownership failures
Do not blindly retry:
invalid_client- malformed bearer token
- missing
Idempotency-Key - invalid recipient format
sendFromownership failures- malformed request bodies
Those are typically integration or configuration defects, not transient platform issues.
Suggested client decision model
When a request fails:
- inspect the HTTP status
- parse the response body shape
- determine whether the failure is:
- OAuth authentication failure
- CORE validation failure
- authorization or ownership failure
- transient server or upstream failure
- retry only if the failure class is actually retryable
- log
requestIdfor all CORE wrapper failures
Practical guidance
- treat OAuth errors and CORE API errors as different shapes
- always capture
requestIdfrom CORE route failures - keep client retry behavior different for:
- invalid credentials
- token refresh
- transient server or upstream failures
Escalation checklist
Before escalating an API issue, capture:
- endpoint called
- HTTP status
- request timestamp
requestIdfrom the CORE error wrapper, if present- whether the issue reproduces consistently
- whether the bearer token was freshly acquired
That information materially shortens diagnosis time.