Adsly.pro
Documentation pages All documentation

Tasks (async operations)

Creating, copying and bulk changes run in the background. How to follow a task with GET /v1/tasks/{id}, what its statuses mean and how to read its result.

View as Markdown

Some operations talk to Telegram once per campaign, so they can take longer than an HTTP request should wait. These return 202 Accepted with a task instead of the final result:

  • POST /v1/campaigns — create
  • POST /v1/campaigns/{ad_id}/copy — copy
  • POST /v1/campaigns/bulk — pause, resume, budget, CPM or delete many

Single-campaign changes (PATCH, pause, resume, budget, delete) answer directly — no task.

The 202 response

HTTP/1.1 202 Accepted
Location: /api/v1/tasks/81234
Retry-After: 2
{
  "success": true,
  "data": {
    "id": 81234,
    "type": "create",
    "status": "pending",
    "account_id": 53,
    "progress": 0,
    "total": 3,
    "succeeded": null,
    "failed": null,
    "ad_ids": [],
    "errors": [],
    "paused_reason": null,
    "error": null,
    "created_at": "2026-10-08T10:15:02.411Z",
    "started_at": null,
    "completed_at": null
  }
}

GET /v1/tasks/{id}

curl -s https://app.adsly.pro/api/v1/tasks/81234 -H "X-API-Key: $ADSLY_API_KEY"

Same shape as above. Poll it until status is final; while a task is pending or running the response carries Retry-After: 2 — wait that long between polls. Any key of the same owner can read the task.

FieldMeaning
typecreate, copy, status (bulk pause/resume), budget, cpm, delete
statussee below
progress / totalcampaigns processed so far / in total
succeeded / failedcounts, once known
ad_idscampaigns the task created (create, copy) or changed (bulk)
errors[]up to 50 failures: { ad_id, index, error } — index is the position in your campaigns array for creates
paused_reasonwhy a task stopped to wait, e.g. the cabinet ran out of balance
errorwhy the whole task failed

Statuses

StatusMeaningFinal?
pendingqueued — the cabinet runs one create and one other operation at a timeno
runningin progressno
pausedstopped to wait — usually the cabinet balance ran out mid-way. Top up the cabinet; resume it from the panelno
completedfinished. Check failed and errors — a completed task can contain individual failuresyes
failedthe task as a whole failed — see erroryes
cancelledcancelled from the panelyes

Things to know about creates

  • New campaign ids appear in ad_ids when the task completes (they are found by syncing the cabinet after the last campaign is created).
  • If the first campaign of a batch fails, the task stops there rather than repeat the same mistake 100 times. Fix the input and send again.
  • If Telegram can’t resolve any of a campaign’s channels or bots, that campaign fails with No targets found: … listing them.
  • Telegram reviews every new ad. A created campaign usually starts In Review; a webhook tells you when that changes.

A polling loop

async function waitForTask(id) {
  for (;;) {
    const res = await fetch(`https://app.adsly.pro/api/v1/tasks/${id}`, {
      headers: { 'X-API-Key': process.env.ADSLY_API_KEY },
    });
    const { data } = await res.json();
    if (['completed', 'failed', 'cancelled'].includes(data.status)) return data;
    if (data.status === 'paused') throw new Error(`Task paused: ${data.paused_reason}`);
    await new Promise(r => setTimeout(r, Number(res.headers.get('Retry-After') || 2) * 1000));
  }
}
import time, requests

def wait_for_task(task_id):
    while True:
        r = requests.get(f"https://app.adsly.pro/api/v1/tasks/{task_id}",
                         headers={"X-API-Key": API_KEY}, timeout=30)
        task = r.json()["data"]
        if task["status"] in ("completed", "failed", "cancelled"):
            return task
        if task["status"] == "paused":
            raise RuntimeError(f"Task paused: {task['paused_reason']}")
        time.sleep(int(r.headers.get("Retry-After", 2)))

Updated 2026-10-08

Discuss your project