Idempotency
Safely retry POST /research without creating duplicate work. Replay semantics, body matching, TTL, and 409 conflict codes.
The Idempotency-Key header
POST /api/v2/research accepts an optional Idempotency-Key header. Send a fresh UUID per logical request when you need retry safety — the server dedupes retries and returns the same job_id.
curl -X POST "https://api.grep.ai/api/v2/research" \
-H "Authorization: Bearer $GREP_API_KEY" \
-H "Idempotency-Key: 8b9c1f24-3c1e-4a8d-9f7b-2a6e1c4d5b8e" \
-H "Content-Type: application/json" \
-d '{"question":"Due diligence on Stripe","effort":"medium"}'Replay semantics
If a request fails partway (timeout, connection drop), retry with the same key. The server returns the original committed response — same job_id, same body. No duplicate jobs are created.
# Same key + same body → same job_id, no new work scheduled.
curl -X POST "https://api.grep.ai/api/v2/research" \
-H "Authorization: Bearer $GREP_API_KEY" \
-H "Idempotency-Key: 8b9c1f24-3c1e-4a8d-9f7b-2a6e1c4d5b8e" \
-H "Content-Type: application/json" \
-d '{"question":"Due diligence on Stripe","effort":"medium"}'
# Returns identical envelope as the original call:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed"
}Body-hash matching
Replay only succeeds if the request body matches the original. The server hashes the JSON body and compares — if you change the body but reuse the key, the request is rejected with 409 idempotency_key_reuse_mismatch. This protects against accidental key reuse across different operations.
TTL windows
| State | Replay window |
|---|---|
| Committed | 24 hours after the job terminates |
| Pending | 1 hour while the job is in flight |
After the window expires, the same key can be reused for a fresh job. In practice, generate a new UUID per request and you'll never hit the boundary.
409 conflict codes
Three distinct 409 codes you might see when reusing a key:
idempotency_key_reuse_mismatchBody changedSame key, different request body. The server rejects rather than silently overwrite — you almost certainly meant to use a fresh key.
idempotency_key_in_flightOriginal still runningSame key while the original job is still in progress. Retry the GET on the original job_id instead of POSTing again.
idempotency_key_ttl_expiredPast the replay windowKey was valid but the TTL elapsed. Generate a new key and try again.
API-key caller mode only
Idempotency keys are only honored for API-key callers. USER and CAPABILITY callers always get a fresh job — the assumption is interactive UI, where retry semantics are different. If you're building a retryable API-key workflow, send Idempotency-Key.