Safe Retries
Use a stable idempotency key whenever your client, queue worker, or webhook handler might retry the same request. Keel will replay the original decision or execution result instead of treating the retry as new work.
Built-in SDK Retry (v0.2.0+)
The Python and JavaScript SDKs include retry with exponential backoff. KeelClient retries only when you pass a retry config, as below. The Go SDK does not retry; add your own policy.
from keel_sdk import KeelClient, RetryConfig
client = KeelClient(
base_url="https://api.keelapi.com",
api_key="keel_sk_...",
retry_config=RetryConfig(max_retries=3),
)
# Requests now retry on transient failuresimport { KeelClient, DEFAULT_RETRY_CONFIG } from "keel-sdk";
const client = new KeelClient({
baseUrl: "https://api.keelapi.com",
apiKey: "keel_sk_...",
retryConfig: DEFAULT_RETRY_CONFIG,
});The provider wrappers (from keel_sdk.providers.openai import OpenAI) include retry by default — no configuration needed.
Manual Retry (without SDK)
When you call the API directly, choose the idempotency field for the route family: permit routes use JSON body fields, while execution and proxy routes use the Idempotency-Key header.
Hosted Keel also requires a current X-Keel-Timestamp and a new X-Keel-Nonce on every permit-creation and execution request. A retry keeps the same idempotency key but must send a new timestamp and nonce; resending the original nonce returns 409 nonce_reuse, and omitting the headers returns 401 request_not_fresh. See Request Freshness.
Permit example
import secrets
import time
import requests
response = requests.post(
"https://api.keelapi.com/v1/permits",
headers={
"Authorization": "Bearer keel_sk_your_key_here",
"Content-Type": "application/json",
# New values on every attempt, including retries.
"X-Keel-Timestamp": str(int(time.time())),
"X-Keel-Nonce": secrets.token_hex(16),
},
json={
"project_id": "<project_uuid>",
"idempotency_key": "invoice-summary-2026-001",
"subject": {"type": "job", "id": "job_9001"},
"action": {"name": "ai.generate"},
"resource": {
"type": "request",
"id": "req_retry_001",
"attributes": {
"provider": "openai",
"model": "gpt-4o-mini",
"operation": "generate.text",
"modality": "text",
"execution_mode": "sync",
"estimated_input_tokens": 320,
"estimated_output_tokens": 120,
"max_output_tokens_requested": 160,
},
},
},
)
print(response.json())Execution example
curl -sS https://api.keelapi.com/v1/executions \
-H "Authorization: Bearer keel_sk_your_key_here" \
-H "Content-Type: application/json" \
-H "X-Keel-Timestamp: $(date +%s)" \
-H "X-Keel-Nonce: $(openssl rand -hex 16)" \
-H "Idempotency-Key: invoice-summary-2026-001" \
-d '{
"operation": "generate.text",
"messages": [
{"role": "user", "content": "Summarize invoice INV-2026-001 for finance review."}
],
"routing": {
"provider": "openai",
"model": "gpt-4o-mini"
},
"parameters": {
"max_output_tokens": 120
}
}'