Error Codes

Learn how RiskOS™ API errors are structured, what they mean, and how to troubleshoot common failures.

Overview

RiskOS™ APIs return errors in a consistent JSON structure with an appropriate HTTP status code.

📘

Note:

Some endpoints may omit the code field (legacy behavior), but the overall structure and error categories remain consistent.


Error model summary

  • All errors typically include error (customer-facing message)
  • Most errors include code (machine-readable identifier)
  • Optional fields:
    • message → internal/debug detail
    • details → structured metadata
    • invalid_args → field-level validation issues
  • Use code + HTTP status for programmatic handling
  • Do not rely on parsing error strings

Standard error response format

{
  "error": "Customer-facing error message",
  "code": "MACHINE_READABLE_ERROR_CODE",
  "message": "Internal error details (optional)",
  "details": {
    "key": "Additional context (optional)"
  },
  "invalid_args": [
    {
      "field": "field_name",
      "value": "invalid_value",
      "tag": "Validation error details"
    }
  ]
}

Error fields

FieldTypeRequiredDescription
errorStringRequiredCustomer-facing message.
codeStringConditionally requiredMachine-readable error code.
messageStringOptionalInternal/debug detail.
detailsObjectOptionalStructured metadata.
invalid_argsArray of ObjectsOptionalField-level validation errors (includes field, value, and tag).

Message types

Message types help interpret how error strings may vary and whether they are safe to parse.

  • Exact → always returned as written
  • Template → contains variables like {contentType}
  • Dynamic → varies at runtime
  • Upstream → returned from an external system

HTTP status codes

StatusMeaningWhen it occurs
400Bad RequestInvalid syntax, missing fields, invalid values
401UnauthorizedMissing or invalid authentication
403ForbiddenAuthenticated but blocked by policy
404Not FoundInvalid endpoint or resource ID
415Unsupported Media TypeInvalid Content-Type
422Unprocessable EntitySemantically invalid data
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
502Bad GatewayUpstream dependency failure
503Service UnavailableTemporary service disruption
504Gateway TimeoutUpstream timeout

Retry transient errors such as 408, 409, 423, 429, 502, 503, and 504 using exponential backoff.

📘

Note:

  • 400 → structural or schema issues (invalid JSON, missing required fields)
  • 422 → valid structure, but invalid data semantics (e.g., unsupported values)

Error categories

Each error below follows a consistent pattern: HTTP status → category → meaning → troubleshooting → example. This structure is intentional to support both developer readability and machine parsing.


Validation errors

INVALID_REQUEST

HTTP: 400 Bad Request
Category: Validation

Occurs when the request contains invalid syntax, missing required fields, or unsupported values.

How to troubleshoot

  • Check the invalid_args array for field-level issues
  • Validate payload against API specification

Examples

{
  "error": "invalid request payload. please refer invalid_args for details",
  "code": "INVALID_REQUEST",
  "invalid_args": [
    {
      "field": "Workflow",
      "value": "",
      "tag": "required"
    }
  ]
}
{
  "error": "attachment extension tws not supported",
  "code": "INVALID_REQUEST"
}

INVALID_PAYLOAD

HTTP: 400 Bad Request
Category: Validation

Occurs when the request body is not valid JSON.

How to troubleshoot

  • Ensure valid JSON format
  • Confirm Content-Type: application/json
{
  "error": "The evaluation request body contains invalid JSON.",
  "code": "INVALID_PAYLOAD"
}

UNSUPPORTED_MEDIA_TYPE

HTTP: 415 Unsupported Media Type
Category: Validation
Message Type: Template

Occurs when the request uses an unsupported Content-Type.

{
  "error": "unsupported media type: {contentType}",
  "code": "UNSUPPORTED_MEDIA_TYPE"
}

INVALID_ID

HTTP: 400 Bad Request
Category: Validation

Occurs when an identifier is malformed or invalid.

{
  "error": "specified id is invalid",
  "code": "INVALID_ID"
}

Workflow errors

WORKFLOW_NOT_FOUND

HTTP: 400 Bad Request
Category: Configuration

{
  "error": "workflow not found with the given version",
  "code": "WORKFLOW_NOT_FOUND"
}

WORKFLOW_NOT_PUBLISHED

HTTP: 400 Bad Request
Category: Configuration

{
  "error": "workflow is not published",
  "code": "WORKFLOW_NOT_PUBLISHED"
}

Authentication and authorization

AUTHENTICATION_FAILED

HTTP: 401 Unauthorized
Category: Authentication

How to troubleshoot

  • Ensure Authorization: Bearer header is present
  • Verify API key is valid
{
  "error": "authentication failed",
  "code": "AUTHENTICATION_FAILED"
}

PERMISSION_DENIED

HTTP: 403 Forbidden
Category: Authorization

Occurs when the API key is valid but lacks required permissions.

{
  "error": "you don't have permission to access this workflow",
  "code": "PERMISSION_DENIED"
}

Security errors

IP_NOT_ALLOWED

HTTP: 403 Forbidden
Category: Security

{
  "error": "ip address rejected",
  "code": "IP_NOT_ALLOWED"
}

NO_IP_FILTER_CONFIGURED

HTTP: 403 Forbidden
Category: Security

{
  "error": "ip address rejected, no filter configured",
  "code": "NO_IP_FILTER_CONFIGURED"
}

Resource errors

NOT_FOUND

HTTP: 404 Not Found
Category: Resource

Note: May not include code in legacy responses.

{
  "error": "evaluation record not found"
}

Request format errors

UNPROCESSABLE_ENTITY

HTTP: 422 Unprocessable Entity
Category: Validation

{
  "error": "unsupported_schema",
  "message": "Address country not supported"
}

Rate limiting and server errors

RATE_LIMIT

HTTP: 429 Too Many Requests
Category: Rate Limiting

How to troubleshoot

  • Use the Retry-After header when provided
  • Otherwise apply exponential backoff
{
  "error": "rate_limit",
  "message": "Too many requests, slow down"
}

INTERNAL_ERROR

HTTP: 500 Internal Server Error
Category: Server

{
  "error": "workflow test execution failed",
  "code": "INTERNAL_ERROR"
}

BAD_GATEWAY

HTTP: 502 Bad Gateway
Category: Server

Occurs when an upstream service fails.

{
  "error": "upstream service error"
}

Error code index

CodeHTTPCategory
INVALID_REQUEST400Validation
INVALID_PAYLOAD400Validation
INVALID_ID400Validation
WORKFLOW_NOT_FOUND400Configuration
WORKFLOW_NOT_PUBLISHED400Configuration
AUTHENTICATION_FAILED401Authentication
PERMISSION_DENIED403Authorization
IP_NOT_ALLOWED403Security
UNSUPPORTED_MEDIA_TYPE415Validation
INTERNAL_ERROR500Server
RATE_LIMIT429Rate Limiting


Best practices for handling errors

⚠️

Important:

POST /evaluation is not idempotent. Retrying a request (for example after a timeout) will create a new evaluation, even if the same id is used.

1. Retry behavior

2xx – Success

  • 200 / 201 – Request accepted and processed successfully.
  • Evaluation is created and executed; response includes decision, eval_status, and enrichment results (each with its own status_code, typically 200).

4xx – Client Errors (Do Not Retry As-Is)

  • 400 – Invalid input, schema, or payload. Always permanent. Fix the request before retrying.
  • 401 / 403 – Authentication or permission issues. Verify API keys, headers, and environment.

Retry-safe (Transient) Errors

  • 408, 409, 423, 429, 502, 503, 504
  • These indicate temporary conditions such as timeouts, rate limits, or service availability issues

Notes on Retry Safety

  • 400 is never transient in RiskOS™; it always indicates an input/schema issue.
  • 429 responses are supported (see Rate Limits documentation) and should be handled with backoff.
  • 502/503/504 are typically safe to retry, but behavior can vary depending on integration patterns.

Recommended Retry Strategy

  • Start with a 1–2 second delay
  • Double delay after each attempt (2s, 4s, 8s, 16s, …)
  • Add small random jitter (±1s)
  • Cap at ~5 attempts or ~1 minute total

2. Idempotency

POST /api/evaluation

  • Each request is treated as a new evaluation, even if the same id is reused.
  • If a client timeout occurs, RiskOS™ aborts processing and a retry will create a new evaluation.

Best Practices

  • Use client timeouts appropriate for your workflow latency
  • If deduplication is required, implement your own idempotency layer or coordinate with Socure

PATCH (Evaluation Updates)

  • PATCH requests (e.g., OTP, SSN, eCBSV consent) are considered safe to retry on 503
  • A 503 response indicates the operation can be retried without advancing evaluation state twice under normal conditions
  • Continue to follow exponential backoff guidance

3. Webhooks

RiskOS™ → Your Endpoint

  • Your endpoint must return a 2xx (typically 200) within the timeout window
  • Any 2xx response stops retries permanently

Failure Handling & Retry Triggers

  • RiskOS™ retries 3–5 times with exponential backoff when:

    • Timeout occurs
    • Endpoint returns: 504, 503, 502, 429, 423, 409, 408

Non-Retryable Responses (Stop Retries)

  • Any 2xx → success (stop retries)
  • Any non-retryable 4xx (e.g., 400, 401, 403) → treated as permanent failure (no retries)

Best Practices for Webhook Handlers

  • Respond with 200 OK as soon as the event is durably stored
  • Make handlers idempotent using a unique event identifier (e.g., event_id, eventReferenceId)
  • Keep processing under 30 seconds; offload longer work to background jobs

4. Troubleshooting

400 – Bad Request
Check:

  • JSON schema alignment with API reference (field names, types, required fields)
  • Required top-level fields (id, timestamp, workflow)
  • Required enrichment-specific data (PII, address, phone, bank data)

401 / 403 – Authentication & Authorization
Verify:

  • Correct API key for environment (sandbox vs production)

  • Required headers:

    • Authorization: Bearer YOUR_API_KEY
    • Content-Type: application/json
    • Accept: application/json
    • Optional version headers (e.g., X-API-Version)

408 / Timeout

  • Requests interrupted by client timeout are not completed
  • Retrying a POST creates a new evaluation
  • Adjust client timeout thresholds to match expected latency

429 – Rate Limiting

  • Apply exponential backoff with jitter
  • Persistent 429s may indicate capacity or configuration issues

502 / 503 / 504 – Service or Upstream Errors

  • Generally safe to retry using exponential backoff

mTLS (No HTTP Status Returned)

  • TLS handshake failures occur before HTTP response
  • Verify client certificate validity, chain, expiration, and CA configuration

5. FAQs

Which HTTP errors are safe to retry?

Retry transient errors such as 408, 409, 423, 429, 502, 503, 504 using exponential backoff.

Can a 400 error ever be transient?

No. 400 is always a permanent input or schema error in RiskOS™.

Are 429 responses possible?

Yes. RiskOS™ may return 429 for rate limiting. Handle using exponential backoff.

Are 502/503/504 always safe to retry?

Generally yes, but behavior may vary based on your integration. Follow retry best practices.

Is PATCH safe to retry on 503?

Yes. PATCH operations are designed to be safely retried without duplicating state transitions under normal conditions.

Does POST /evaluation support idempotency?

No. Retrying a POST (even with the same id) creates a new evaluation.

What should my webhook endpoint return?

Return 200 OK once the event is persisted. Any non-2xx or retryable error response will trigger retries.

What should I log for debugging?
  • Request id
    • eval_id (if available)
    • HTTP status_code
    • Error response body
    • Timestamps
    • Correlation identifiers (e.g., One-Time Passcode (OTP) or SDK request IDs)