Errors

All RSA Platform APIs return errors in the RFC 9457 ProblemDetails format.

ProblemDetails Structure

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404,
  "detail": "Store with id 'f1e2d3c4-...' was not found",
  "instance": "GET /admin/api/v1/stores/f1e2d3c4-...",
  "traceId": "00-4bf5122f344c2c6f5b0a6f5b0a6f5b0a-1"
}
FieldDescription
typeURI identifying the error type (standard HTTP status types)
titleShort human-readable summary
statusHTTP status code
detailHuman-readable explanation specific to this instance
instanceThe request that caused the error (METHOD /path)
traceIdW3C trace ID — include this when contacting support

Common Status Codes

StatusCauseResolution
400 Bad RequestMalformed JSON or missing required fieldsFix request body
401 UnauthorizedMissing, expired, or invalid tokenRe-authenticate
402 Payment RequiredTenant suspended (payment overdue)Contact platform admin
403 ForbiddenToken lacks required scope or roleCheck scope/role requirements
404 Not FoundResource does not existVerify ID is correct
409 ConflictDuplicate resource (e.g., duplicate slug)Use a unique identifier
422 Unprocessable EntityValidation failure or business rule violationSee validation errors below
429 Too Many RequestsRate limit exceededBack off and retry
500 Internal Server ErrorUnexpected server errorInclude traceId in support ticket

422 Validation Errors

Validation failures include field-level details:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.23",
  "title": "One or more validation errors occurred",
  "status": 422,
  "errors": {
    "name": ["'Name' must not be empty."],
    "phone": ["'Phone' is not a valid phone number."]
  },
  "traceId": "00-4bf5122f344c2c6f5b0a-1"
}

429 Rate Limiting

Rate limit headers are returned with 429 responses:

HTTP/1.1 429 Too Many Requests
Retry-After: 15
APILimit
Platform API, Admin API, Shopper API200 tokens/min per user (token bucket)
POS API500 requests/min per API key (fixed window)

Implement exponential backoff with jitter. Start with a 1-second delay, double on each retry, add random jitter, cap at 60 seconds.

async function retryWithBackoff(fn: () => Promise<Response>, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const res = await fn();
    if (res.status !== 429) return res;
    const delay = Math.min(1000 * Math.pow(2, i) + Math.random() * 100, 60_000);
    await new Promise((r) => setTimeout(r, delay));
  }
  throw new Error("Max retries exceeded");
}

Getting Support

When contacting support, always include the traceId from the error response. This maps to a structured log entry in the platform's observability system.