Tracking issue for the client-side ergonomics of AdCP #2308 — idempotency_key is now required on every mutating request in the spec.
Client-side changes
1. Auto-generate idempotency_key when caller omits it
Every mutating tool call should generate a UUID v4 if the caller didn't pass one:
# Caller doesn't think about it — SDK handles it
result = client.create_media_buy(account=..., brand=..., start_time=..., end_time=...)
# Caller passes their own (e.g., restored from DB) — SDK respects it
result = client.create_media_buy(idempotency_key=stored_key, ...)
The list of mutating tasks is in the spec — 26 total across media_buy, creative, signals, brand, governance, accounts, SI.
2. Retry-safety: reuse the same key
When the SDK retries internally (timeout, 5xx, network error), it MUST reuse the same key across retries. Re-generating a key on retry defeats the whole point.
3. Surface the key for external correlation
The key should be observable on both the sent request and the returned response so callers can log it, store it alongside their own objects, or correlate across retries:
result = client.create_media_buy(...)
print(result.idempotency_key, result.media_buy_id)
4. Typed IdempotencyConflictError
Map the new IDEMPOTENCY_CONFLICT error code to a dedicated exception class:
from adcp_client import IdempotencyConflictError
try:
client.create_media_buy(idempotency_key=reused_key, ...different_payload)
except IdempotencyConflictError:
# Caller reused a key by mistake — use a fresh one
...
5. Optional: use_idempotency_key(key) context manager for bring-your-own-key
For buyers who persist keys across process restarts (e.g., store key in their DB alongside a campaign row):
with client.use_idempotency_key(campaign.idempotency_key):
client.create_media_buy(...)
Scope notes
- SI send_message needs the key too but lives in session scope — SDK should auto-generate per turn.
- si_terminate_session is naturally idempotent via session_id — SDK can continue to omit
idempotency_key.
Acceptance
Related: adcontextprotocol/adcp#2308, adcontextprotocol/adcp#2315
Tracking issue for the client-side ergonomics of AdCP #2308 — idempotency_key is now required on every mutating request in the spec.
Client-side changes
1. Auto-generate
idempotency_keywhen caller omits itEvery mutating tool call should generate a UUID v4 if the caller didn't pass one:
The list of mutating tasks is in the spec — 26 total across media_buy, creative, signals, brand, governance, accounts, SI.
2. Retry-safety: reuse the same key
When the SDK retries internally (timeout, 5xx, network error), it MUST reuse the same key across retries. Re-generating a key on retry defeats the whole point.
3. Surface the key for external correlation
The key should be observable on both the sent request and the returned response so callers can log it, store it alongside their own objects, or correlate across retries:
4. Typed
IdempotencyConflictErrorMap the new
IDEMPOTENCY_CONFLICTerror code to a dedicated exception class:5. Optional:
use_idempotency_key(key)context manager for bring-your-own-keyFor buyers who persist keys across process restarts (e.g., store key in their DB alongside a campaign row):
Scope notes
idempotency_key.Acceptance
idempotency_keywhen not providedidempotency_keysurfaced on the sent request for loggingIdempotencyConflictErrorexported as a typed exceptionRelated: adcontextprotocol/adcp#2308, adcontextprotocol/adcp#2315