> Adsly docs index: https://adsly.pro/docs/llms.txt · every page in one file: https://adsly.pro/docs/llms-full.txt · OpenAPI: https://adsly.pro/docs/api/openapi.yaml

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

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

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

---
Page: https://adsly.pro/docs/api/idempotency/ · Updated: 2026-10-08
