# API Idempotency - Grep

[Developers](/developers)[API Reference](/developers/api)Idempotency

# 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

| 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_mismatch`Body 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_flight`Original 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_expired`Past 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.
