Skip to main content

Errors

Red Cloud currently exposes two public error models:

  1. OAuth token endpoint errors
  2. 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.code is the machine-readable classification
  • error.message is the human-readable explanation
  • error.details may include route-specific context
  • requestId should be captured for support and escalation

HTTP status to error code patterns

  • 400
    • INVALID_REQUEST
  • 401
    • UNAUTHORIZED
  • 403
    • FORBIDDEN
  • 404
    • NOT_FOUND
  • 409
    • CONFLICT
  • 500
    • SERVER_ERROR
  • 502
    • UPSTREAM_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
  • sendFrom ownership failures
  • malformed request bodies

Those are typically integration or configuration defects, not transient platform issues.

Suggested client decision model

When a request fails:

  1. inspect the HTTP status
  2. parse the response body shape
  3. determine whether the failure is:
    • OAuth authentication failure
    • CORE validation failure
    • authorization or ownership failure
    • transient server or upstream failure
  4. retry only if the failure class is actually retryable
  5. log requestId for all CORE wrapper failures

Practical guidance

  • treat OAuth errors and CORE API errors as different shapes
  • always capture requestId from 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
  • requestId from the CORE error wrapper, if present
  • whether the issue reproduces consistently
  • whether the bearer token was freshly acquired

That information materially shortens diagnosis time.