Idempotency
How the Idempotency-Key header makes retries safe — no duplicate campaigns, no double top-ups — and exactly how the API treats repeated, changed and concurrent requests.
Networks fail in the worst place: after your request reached us, before the answer reached you. Retrying a top-up blindly could move money twice; retrying a create could launch the same campaign twice. An Idempotency-Key makes the retry safe.
Where it is required
| Endpoint | Header |
|---|---|
POST /v1/campaigns | required |
POST /v1/campaigns/{ad_id}/copy | required |
POST /v1/campaigns/bulk | required |
POST /v1/campaigns/{ad_id}/budget | required |
Other writes (PATCH, pause/resume, DELETE, media) | optional — they are safe to repeat on their own |
Without the header these return 400 IDEMPOTENCY_KEY_REQUIRED.
How to use it
Generate a new random value — a UUID — for each operation, and send the same value every time you retry that operation.
KEY=$(uuidgen)
curl -X POST https://app.adsly.pro/api/v1/campaigns/90412/budget \
-H "X-API-Key: $ADSLY_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
-d '{"account_id":53,"action":"add","amount":5}'
# timed out? run exactly the same command again, with the same $KEY
import uuid, requests
def add_budget(ad_id, account_id, amount):
key = str(uuid.uuid4()) # one per operation
for attempt in range(3):
try:
return requests.post(
f"https://app.adsly.pro/api/v1/campaigns/{ad_id}/budget",
headers={"X-API-Key": API_KEY, "Idempotency-Key": key},
json={"account_id": account_id, "action": "add", "amount": amount},
timeout=30,
)
except requests.Timeout:
continue # same key → never added twice
What happens on a repeat
| Situation | Response |
|---|---|
| First request with this key | Runs normally. |
| Same key, same request, first one finished | The stored response, unchanged, with the header Idempotent-Replayed: true. Nothing runs again. |
| Same key, same request, first one still running | 409 IDEMPOTENCY_IN_PROGRESS + Retry-After. Retry shortly. |
| Same key, different body or endpoint | 422 IDEMPOTENCY_KEY_REUSED. A new operation needs a new key. |
| First request ended in a 4xx (bad input, plan, queue full…) | The key is released: fix the request and send it with the same key. |
| First request ended in a 5xx | The 5xx is stored and replayed — the change may have reached Telegram, and the key exists to stop it running twice. Check the campaign with GET, then use a new key if you still want to act. |
“Same request” means the same method, path and JSON body (key order doesn’t matter).
Details
- Keys are scoped to your API key — two integrations can’t collide.
- Keys are kept for 24 hours. After that the same value starts a new operation.
- Any string of 8–255 characters works; a UUID is the right default.
- If we can’t record the key, the operation doesn’t run and you get
503 IDEMPOTENCY_UNAVAILABLE— retry with the same key.
Updated 2026-10-08