Idempotency Keys
Network failures, timeouts, and retries can cause a request to be sent more than once. Idempotency keys let you safely retry requests without duplicating the operation. The server stores the result of the first request and returns it for any subsequent request with the same key.
How to Use Idempotency Keys
Pass a unique string in the Idempotency-Key header. Use a UUID v4 or another value that uniquely identifies the logical operation on the client side.
curl https://api.creor.ai/v1/agents \
-u YOUR_API_KEY: \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"name": "bugfix-agent",
"repository": "org/repo",
"prompt": "Fix the failing CI test in src/auth.ts"
}'| Behavior | Description |
|---|---|
| First request | Processed normally. The result is cached against the idempotency key for 24 hours. |
| Duplicate request (same key) | Returns the cached result from the first request without re-executing the operation. |
| Same key, different body | Returns a 409 Conflict error. A key must always be paired with the same request body. |
| Key expiration | Cached results are purged after 24 hours. After that, the key can be reused. |
Tip
Which Endpoints Support Idempotency
- POST /v1/agents -- launch a new agent
- POST /v1/agents/:id/followup -- add a follow-up message
- POST /v1/chat/completions -- chat completion (non-streaming only)
GET, PUT, and DELETE requests are naturally idempotent and do not require an idempotency key.
Error Handling
The Creor API uses standard HTTP status codes and returns structured JSON error bodies. Every error response follows the same shape, making it straightforward to handle errors consistently in your client code.
Error Response Format
{
"error": {
"type": "invalid_request",
"message": "The 'model' field is required.",
"param": "model",
"code": "missing_field"
}
}| Status Code | Type | Description |
|---|---|---|
| 400 | invalid_request | The request body is malformed or missing required fields. |
| 401 | authentication_error | The API key is missing, invalid, or expired. |
| 403 | permission_denied | The API key does not have permission for this operation. |
| 404 | not_found | The requested resource does not exist. |
| 409 | conflict | Idempotency key conflict or resource state conflict. |
| 422 | unprocessable_entity | The request is well-formed but semantically invalid (e.g., unsupported model). |
| 429 | rate_limit_exceeded | You have exceeded your rate limit. See the Rate Limits page. |
| 500 | internal_error | An unexpected server error. Safe to retry with exponential backoff. |
| 503 | service_unavailable | The service is temporarily unavailable. Retry after the Retry-After header value. |
Handling Errors in Code
Note
Pagination
List endpoints return paginated results using cursor-based pagination. This approach is more reliable than offset-based pagination because it handles insertions and deletions between pages correctly.
Request Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| limit | integer | 20 | Number of items per page. Maximum 100. |
| cursor | string | null | Cursor from the previous response to fetch the next page. |
| order | string | desc | Sort order: "asc" or "desc" by creation time. |
Response Format
{
"data": [
{ "id": "agent_abc123", "name": "bugfix-agent", "status": "completed" },
{ "id": "agent_def456", "name": "review-agent", "status": "running" }
],
"has_more": true,
"next_cursor": "eyJpZCI6ImFnZW50X2RlZjQ1NiJ9"
}Iterating Through All Pages
Tip
Streaming Responses
The /v1/chat/completions endpoint supports Server-Sent Events (SSE) for streaming responses. Streaming lets you display tokens to the user as they are generated instead of waiting for the full response.
Enabling Streaming
Set "stream": true in your request body. The response will be a text/event-stream instead of a JSON object.
curl https://api.creor.ai/v1/chat/completions \
-u YOUR_API_KEY: \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-20250514",
"stream": true,
"messages": [
{"role": "user", "content": "Write a haiku about code reviews"}
]
}'Event Format
Each event is a JSON object prefixed with "data: ". The stream ends with a "data: [DONE]" sentinel. See the Gateway Streaming page for the full event schema and code examples.
Note
Webhook Reliability
Creor sends webhooks for agent lifecycle events (started, completed, failed) and usage alerts. Building a reliable webhook consumer requires handling retries, verifying signatures, and processing events idempotently.
Webhook Delivery
| Behavior | Details |
|---|---|
| Timeout | Your endpoint must respond with a 2xx status within 10 seconds. |
| Retries | Failed deliveries are retried up to 5 times with exponential backoff (1m, 5m, 30m, 2h, 12h). |
| Ordering | Events are delivered in approximate order but not guaranteed. Use the event timestamp to detect out-of-order delivery. |
| Idempotency | Each event includes a unique event_id. Store processed event IDs to avoid duplicate handling. |
Verifying Signatures
Every webhook includes a Creor-Signature header containing an HMAC-SHA256 signature of the request body. Verify this signature to ensure the webhook was sent by Creor and not tampered with in transit.
Best Practices for Webhook Consumers
- Respond with 200 immediately, then process the event asynchronously. This prevents timeouts.
- Store the event_id and skip duplicates. Creor may deliver the same event more than once.
- Use the event timestamp (not arrival time) for ordering logic.
- Log the raw request body before processing for debugging.
- Set up a dead-letter queue for events that fail processing after all retries.
- Monitor your webhook endpoint's error rate and latency in your observability stack.
Warning