Idempotency — Grep API v2

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
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.

bash
# 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

StateReplay window
Committed24 hours after the job terminates
Pending1 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 changed

Same 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 running

Same 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 window

Key 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.