All Verilock API errors return a consistent JSON structure, making it easy to handle errors programmatically regardless of the error type.
| Field | Type | Description |
|---|
error | string | Machine-readable error code. Use this for programmatic error handling. |
message | string | Human-readable description of what went wrong. |
details | object|null | Additional context. For validation errors, contains field-level messages. May be null for other error types. |
Error Types
The error field will contain one of the following values:
| Error Code | HTTP Status | Description |
|---|
validation_error | 422 | One or more fields failed validation. Check details for field-specific messages. |
authentication_error | 401 | API key is missing, invalid, or revoked. |
not_found | 404 | The requested resource does not exist or has been deleted. |
rate_limit_exceeded | 429 | Too many requests. Back off and retry after the Retry-After header value. |
server_error | 500, 503 | An internal error occurred. Safe to retry with exponential backoff. |
Best Practices
Retry with exponential backoff — For 5xx errors and 429 rate limits, retry with increasing delays: 1s, 2s, 4s, 8s. Add random jitter to prevent thundering herd.
Respect the Retry-After header — When you receive a 429 response, always wait for the number of seconds specified in the Retry-After header before making another request.
Log error responses — Store the full error response and the X-Request-Id header for debugging. Include these when contacting support.
Do not retry 4xx errors (except 429) — Client errors like 400, 401, 403, 404, and 422 will not resolve on retry. Fix the request before retrying.
Error Response Body
{
"error": "validation_error",
"message": "The given data was invalid.",
"details": {
"field_name": [
"The field name is required.",
"The field name must be a string."
]
}
}
PHP Error Handling Example
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$client = new Client([
'base_uri' => 'https://verilock.io/api/v1/',
'headers' => [
'X-API-Key' => 'your_api_key_here',
'Accept' => 'application/json',
],
]);
$maxRetries = 3;
for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
try {
$response = $client->post('sessions', [
'json' => ['workflow_id' => 'wf_abc123'],
]);
$data = json_decode($response->getBody(), true);
// Success — process $data
break;
} catch (RequestException $e) {
$status = $e->getResponse()?->getStatusCode();
$body = json_decode($e->getResponse()?->getBody(), true);
if ($status === 422) {
// Validation error — do not retry
log_error('Validation failed', $body['details'] ?? []);
break;
}
if ($status === 429) {
// Rate limited — wait and retry
$wait = $e->getResponse()->getHeaderLine('Retry-After') ?: 5;
sleep((int) $wait);
continue;
}
if ($status >= 500) {
// Server error — retry with backoff
sleep(pow(2, $attempt));
continue;
}
// Other client error — do not retry
log_error($body['error'] ?? 'unknown', $body['message'] ?? '');
break;
}
}