Errors, Limits, and Retry

Error response format

Intentional API failures use the RFC 7807 ProblemDetails structure with the application/problem+json media type. Branch on code and HTTP status, not human-readable text, and tolerate codes added later.

      
        {
          "type": "https://arelhub.com/errors/quota-exceeded",
          "title": "Quota exceeded",
          "status": 429,
          "detail": "Monthly message quota for the subaccount has been reached.",
          "instance": "/v1/accounts/00000000-0000-0000-0000-000000000001/messages",
          "code": "QUOTA_EXCEEDED",
          "traceId": "00-abc123-def456-00",
          "retryAfterSeconds": 30,
          "dailyRemaining": 0,
          "monthlyRemaining": 0
        }
      
    

type, title, status, code, and traceId are required. Validation failures may include an errors map; quota and throttling failures may include retry and remaining-count extensions. Include traceId in support requests.

Numbered error catalog

Numeric IDs organize the catalog for documentation and support tooling. The wire contract uses the stable string code, not a numeric enum.

Family IDs Codes
General / protocol 1001-1005 INVALID_INPUT, INVALID_OPERATION, NOT_FOUND, CONFLICT, INTERNAL_ERROR
Authentication 1101-1108 UNAUTHORIZED, TOKEN_EXPIRED, TOKEN_REVOKED, API_KEY_INVALID, API_KEY_EXPIRED, API_KEY_REVOKED, API_KEY_DELETED, INVALID_TOKEN
Authorization / session 1201-1205 FORBIDDEN, CSRF_HEADER_REQUIRED, STEP_UP_REQUIRED, SESSION_INVALID, SESSION_IDLE_TIMEOUT
Validation 1301-1304 INVALID_JSON, VALIDATION_FAILED, BODY_REQUIRED, INVALID_REQUEST
Account / user state 1401-1406 USER_NOT_FOUND, USER_INACTIVE, ACCOUNT_LOCKED, ACCOUNT_INACTIVE, STAFF_NOT_FOUND, STAFF_INACTIVE
Multi-factor auth 1411-1418 MFA_REQUIRED, MFA_CHALLENGE_INVALID, MFA_ALREADY_ENABLED, MFA_NOT_ENABLED, MFA_ENROLLMENT_REQUIRED, STEP_UP_FACTOR_REQUIRED, MFA_REQUIRED_BY_ACCOUNT, WEBAUTHN_VERIFICATION_FAILED
Security challenges 1501-1502 CAPTCHA_FAILED, IP_THROTTLED
Token / OTP / step-up 1601-1607 RATE_LIMITED, INVALID_CODE, LOCKED, ALREADY_USED, INVALID_OR_EXPIRED, SUBJECT_MISMATCH, ACTION_MISMATCH
Quotas / throttling 1701-1702 QUOTA_EXCEEDED, RATE_LIMIT_EXCEEDED
Billing / subscription 1801 NO_ACTIVE_SUBSCRIPTION
Messaging / compliance 1901 COMPLIANCE_REJECTED
Concurrency / persistence 2001-2002 CONCURRENCY_ERROR, DATABASE_ERROR
Reply options 2203-2204 REPLY_OPTION_RESERVED_KEYWORD, REPLY_OPTION_INVALID
Scheduled sends, expiry 2201, 2202, 2205 SEND_AT_OUT_OF_RANGE, EXPIRES_AT_INVALID, MESSAGE_NOT_CANCELABLE
Recipient consent 2301-2304 RECIPIENT_OPT_OUT_SCOPE_REQUIRED, RECIPIENT_NOT_OPTED_OUT, RECIPIENT_OPT_OUT_NOT_LIFTABLE, CONSENT_IMPORT_INVALID
Dependencies / timeouts 2101-2103 TIMEOUT, REQUEST_CANCELLED, EXTERNAL_SERVICE_ERROR

Status code reference

Code Title Recommended action
400 Bad Request Fix request syntax
401 Unauthorized Refresh token or verify API key
403 Forbidden Check API key rights or account policy
404 Not Found Verify ID and account ownership
409 Conflict Check existing state before retrying
422 Validation Error Inspect detail for constraint violation
429 Too Many Requests See rate limits below
500 Internal Server Error Retry with backoff; file support ticket if persistent

Rate limits

When a rate limit is exceeded the response includes a Retry-After header (when present):

      
        {
          "type": "https://arelhub.com/errors/rate-limit-exceeded",
          "title": "Rate limit exceeded",
          "status": 429,
          "detail": "Request rate limit exceeded. Retry after 30 seconds.",
          "code": "RATE_LIMIT_EXCEEDED",
          "traceId": "00-abc123-def456-00",
          "retryAfterSeconds": 30
        }
      
    

Quota limits

Quota depletion returns a distinct 429 with code QUOTA_EXCEEDED. Check remaining quota before bulk sends:

      
        GET /v1/user/quota/subaccounts/{subaccountId}
        Authorization: Bearer eyJ...
      
    

Retry posture

Error Retry? Strategy
400, 422 No Fix request and resubmit
401 Conditional Refresh token, then retry once
403 No Contact support if unexpected
404 No Verify resource ID
429 Yes Respect Retry-After; exponential backoff
500 Yes Exponential backoff with jitter; cap at 3-5 attempts
Network timeout Yes Treat timed-out requests as idempotent; check status first

Exponential backoff formula

      
        delay = min(base x 2^attempt, maxDelay) + random(0, jitter)
        // Recommended: base=1s, maxDelay=30s, jitter=500ms
      
    

Idempotent requests

Message submission is not idempotent by default. If a POST /v1/accounts/{accountId}/messages request times out, check status before retrying. Use the externalId field on submission to correlate your internal request ID with ArelHub's message ID.

Support

For persistent errors or incidents, include in your support request: traceId, request timestamp (UTC), endpoint and HTTP method, and anonymized request body.

Contact support


← Webhooks  ·  API Reference →