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
codefield (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 detaildetails→ structured metadatainvalid_args→ field-level validation issues
- Use
code+ HTTP status for programmatic handling - Do not rely on parsing
errorstrings
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
| Field | Type | Required | Description |
|---|---|---|---|
error | String | Required | Customer-facing message. |
code | String | Conditionally required | Machine-readable error code. |
message | String | Optional | Internal/debug detail. |
details | Object | Optional | Structured metadata. |
invalid_args | Array of Objects | Optional | Field-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
| Status | Meaning | When it occurs |
|---|---|---|
400 | Bad Request | Invalid syntax, missing fields, invalid values |
401 | Unauthorized | Missing or invalid authentication |
403 | Forbidden | Authenticated but blocked by policy |
404 | Not Found | Invalid endpoint or resource ID |
415 | Unsupported Media Type | Invalid Content-Type |
422 | Unprocessable Entity | Semantically invalid data |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
502 | Bad Gateway | Upstream dependency failure |
503 | Service Unavailable | Temporary service disruption |
504 | Gateway Timeout | Upstream timeout |
Retry transient errors such as
408,409,423,429,502,503, and504using 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
INVALID_REQUESTHTTP: 400 Bad Request
Category: Validation
Occurs when the request contains invalid syntax, missing required fields, or unsupported values.
How to troubleshoot
- Check the
invalid_argsarray 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
INVALID_PAYLOADHTTP: 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
UNSUPPORTED_MEDIA_TYPEHTTP: 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
INVALID_IDHTTP: 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
WORKFLOW_NOT_FOUNDHTTP: 400 Bad Request
Category: Configuration
{
"error": "workflow not found with the given version",
"code": "WORKFLOW_NOT_FOUND"
}WORKFLOW_NOT_PUBLISHED
WORKFLOW_NOT_PUBLISHEDHTTP: 400 Bad Request
Category: Configuration
{
"error": "workflow is not published",
"code": "WORKFLOW_NOT_PUBLISHED"
}Authentication and authorization
AUTHENTICATION_FAILED
AUTHENTICATION_FAILEDHTTP: 401 Unauthorized
Category: Authentication
How to troubleshoot
- Ensure
Authorization: Bearerheader is present - Verify API key is valid
{
"error": "authentication failed",
"code": "AUTHENTICATION_FAILED"
}PERMISSION_DENIED
PERMISSION_DENIEDHTTP: 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
IP_NOT_ALLOWEDHTTP: 403 Forbidden
Category: Security
{
"error": "ip address rejected",
"code": "IP_NOT_ALLOWED"
}NO_IP_FILTER_CONFIGURED
NO_IP_FILTER_CONFIGUREDHTTP: 403 Forbidden
Category: Security
{
"error": "ip address rejected, no filter configured",
"code": "NO_IP_FILTER_CONFIGURED"
}Resource errors
NOT_FOUND
NOT_FOUNDHTTP: 404 Not Found
Category: Resource
Note: May not include code in legacy responses.
{
"error": "evaluation record not found"
}Request format errors
UNPROCESSABLE_ENTITY
UNPROCESSABLE_ENTITYHTTP: 422 Unprocessable Entity
Category: Validation
{
"error": "unsupported_schema",
"message": "Address country not supported"
}Rate limiting and server errors
RATE_LIMIT
RATE_LIMITHTTP: 429 Too Many Requests
Category: Rate Limiting
How to troubleshoot
- Use the
Retry-Afterheader when provided - Otherwise apply exponential backoff
{
"error": "rate_limit",
"message": "Too many requests, slow down"
}INTERNAL_ERROR
INTERNAL_ERRORHTTP: 500 Internal Server Error
Category: Server
{
"error": "workflow test execution failed",
"code": "INTERNAL_ERROR"
}BAD_GATEWAY
BAD_GATEWAYHTTP: 502 Bad Gateway
Category: Server
Occurs when an upstream service fails.
{
"error": "upstream service error"
}Error code index
| Code | HTTP | Category |
|---|---|---|
| INVALID_REQUEST | 400 | Validation |
| INVALID_PAYLOAD | 400 | Validation |
| INVALID_ID | 400 | Validation |
| WORKFLOW_NOT_FOUND | 400 | Configuration |
| WORKFLOW_NOT_PUBLISHED | 400 | Configuration |
| AUTHENTICATION_FAILED | 401 | Authentication |
| PERMISSION_DENIED | 403 | Authorization |
| IP_NOT_ALLOWED | 403 | Security |
| UNSUPPORTED_MEDIA_TYPE | 415 | Validation |
| INTERNAL_ERROR | 500 | Server |
| RATE_LIMIT | 429 | Rate Limiting |
Best practices for handling errors
Important:
POST /evaluationis not idempotent. Retrying a request (for example after a timeout) will create a new evaluation, even if the sameidis 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 ownstatus_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
idis 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 OKas 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_KEYContent-Type: application/jsonAccept: 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
ideval_id(if available)- HTTP
status_code - Error response body
- Timestamps
- Correlation identifiers (e.g., One-Time Passcode (OTP) or SDK request IDs)

