Idempotency & Concurrency
Idempotency
Create-style endpoints accept an optional Idempotency-Key header. If you retry a request with the same key and the original request succeeded, the server returns the original response without executing the operation again.
curl -X POST https://api.eunifyer.com/api/v1/partner/orgs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-abc123" \
-d '{ "name": "Acme Corp", "plan_id": "…" }'A replayed response includes X-Idempotency-Replayed: true.
Rules
- Generate a fresh
Idempotency-Keyfor each logical operation — do not reuse keys. - Keys are scoped to your organization and cached for 24 hours.
- If you send the same key with a different body, the server returns
409 Conflict. - If the original request was still in-flight when you retry, you may receive a
503— back off and retry. - If the original request failed with a 4xx, the error is not cached — you can retry with the same key and corrected body.
Generating keys
const idempotencyKey = crypto.randomUUID();import uuid
idempotency_key = str(uuid.uuid4())Which endpoints support idempotency
| Endpoint | Idempotency supported |
|---|---|
POST /partner/orgs | Yes |
POST /partner/orgs/{id}/users | Yes |
POST /partner/orgs/{id}/teams | Yes |
POST /developer/service-principals | Yes |
POST /developer/service-principals/{id}/tokens | Yes |
POST /drive/upload | Yes |
POST /webhooks/subscriptions | Yes |
Optimistic concurrency (ETag / If-Match)
Mutable resources that are edited concurrently carry an ETag response header. Use If-Match on write requests to prevent overwriting another client’s changes.
Reading the ETag
curl -I https://api.eunifyer.com/api/v1/sites/my-site-id/pages/my-page-id \
-H "Authorization: Bearer $TOKEN"
# Response headers include:
# ETag: "abc123def456"Writing with If-Match
curl -X PATCH https://api.eunifyer.com/api/v1/sites/my-site-id/pages/my-page-id \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "If-Match: \"abc123def456\"" \
-d '{ "content": "# Updated content\n\nNew paragraph." }'If the resource was modified by someone else since you read it, the server returns:
{
"type": "https://problems.eunifyer.com/precondition_failed",
"title": "Precondition Failed",
"status": 412,
"detail": "Resource was modified since your last read. Fetch the current version and retry.",
"code": "precondition_failed"
}Re-fetch the resource, merge your changes, and retry with the new ETag.
Which resources support ETag
| Resource | ETag support |
|---|---|
Sites pages (GET/PATCH /sites/{id}/pages/{id}) | Yes |
| CardDAV contacts | Yes |
Example — safe page update
import httpx
client = httpx.Client(
base_url="https://api.eunifyer.com/api/v1",
headers={"Authorization": f"Bearer {token}"},
)
# 1. Read current version
resp = client.get(f"/sites/{site_id}/pages/{page_id}")
resp.raise_for_status()
etag = resp.headers["etag"]
page = resp.json()
# 2. Make changes locally
page["content"] = "# Updated\n\nNew content here."
# 3. Write with If-Match
update = client.patch(
f"/sites/{site_id}/pages/{page_id}",
json={"content": page["content"]},
headers={"If-Match": etag},
)
if update.status_code == 412:
# Conflict — re-fetch and retry
...
update.raise_for_status()Summary
| Concern | Mechanism | Header |
|---|---|---|
| Safe retries on create | Idempotency | Idempotency-Key (request) |
| Detect replayed response | Idempotency | X-Idempotency-Replayed: true (response) |
| Prevent lost updates on edits | Optimistic concurrency | ETag (response) + If-Match (request) |
Stale If-Match | 412 error | Re-fetch + retry |