Error Handling
stile uses conventional HTTP status codes and structured error objects. The Node.js SDK surfaces these as typed error classes.
Error response format
All API errors return a JSON body in this shape:
{
"error": {
"type": "invalid_request_error",
"code": "parameter_invalid",
"message": "No such verification_session: 'vks_unknown'",
"param": "id",
"request_id": "req_abc123"
}
}Include the request_id when contacting support — it lets us trace the exact request in our logs.
HTTP status codes
| Code | Meaning |
|---|---|
| 200 | OK — request succeeded. |
| 201 | Created — resource was created successfully. |
| 400 | Bad Request — missing or invalid parameters. |
| 401 | Unauthorized — invalid, missing, or revoked API key. |
| 404 | Not Found — the requested resource doesn't exist. |
| 409 | Conflict — idempotency key collision or state conflict. |
| 422 | Unprocessable Entity — the request is valid but can't be fulfilled. |
| 429 | Too Many Requests — rate limit exceeded. Retry after the Retry-After header value. |
| 500 | Internal Server Error — something went wrong on our end. Retry with exponential backoff. |
Error types
| Type | When it occurs |
|---|---|
invalid_request_error | A parameter is missing, invalid, or the operation isn't allowed in the current state. |
authentication_error | The API key is missing, malformed, revoked, or expired. |
rate_limit_error | Too many requests were sent in the current window. |
api_error | An unexpected server error occurred. Safe to retry. |
SDK error classes
The Node.js SDK provides typed error classes so you can handle different failures precisely:
import {
StileError,
StileAuthenticationError,
StileRateLimitError,
} from "@stile/node";
async function createSession() {
try {
return await stile.verificationSessions.create({ type: "identity" });
} catch (err) {
if (err instanceof StileAuthenticationError) {
// 401 — your key is invalid, revoked, or missing
console.error("Check your STILE_API_KEY environment variable");
throw err;
}
if (err instanceof StileRateLimitError) {
// 429 — back off and retry
const retryAfter = err.retryAfter ?? 60;
console.warn(`Rate limited. Retry in ${retryAfter}s`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return createSession();
}
if (err instanceof StileError) {
console.error({
type: err.type,
code: err.code,
message: err.message,
statusCode: err.statusCode,
requestId: err.requestId,
});
throw err;
}
throw err;
}
}Retrying requests
The Node.js SDK automatically retries network errors and 5xx responses with exponential backoff (up to maxRetries times, default: 2). You can increase this for resilient background jobs:
const stile = new Stile(process.env.STILE_API_KEY!, {
maxRetries: 5, // retry up to 5 times for transient errors
});Don't retry 4xx errors automatically
Client errors (400, 401, 404, 429) indicate a problem with the request itself. Retrying them immediately won't help — fix the underlying issue first. The SDK only auto-retries network failures and 5xx responses.
Idempotency
Use the idempotency_key field when creating sessions to prevent duplicates if your request is retried after a network timeout:
const session = await stile.verificationSessions.create({
type: "identity",
client_reference_id: userId,
idempotency_key: `verify-${userId}-${Date.now()}`,
});