> ## Documentation Index
> Fetch the complete documentation index at: https://docs.acedata.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# WebExtrator завдання запиту API інтеграційний посібник

> WebExtrator Web Render & Extract API guide - Ace Data Cloud

`POST https://api.acedata.cloud/webextrator/tasks`

WebExtrator завдання запиту API використовується для запиту історичних результатів `render` / `extract` завдань. Загальні
використання:

* Після завершення асинхронного завдання **перевірити** повний envelope (окрім `callback_url` пушу або активного опитування).
* **Аудит** того, що було подано — записи завдань одночасно зберігають оригінальний `request` та остаточний `response`.
* **Пакетне заповнення** — одночасно за `id` або `trace_id` отримати кілька записів.

Записи завдань зберігаються в Redis **7 днів**.

Інтерфейс запиту завдань **безкоштовний** (не враховується в Credits).

## Аутентифікація

```
Authorization: Bearer YOUR_API_KEY
Content-Type:  application/json
```

Можна запитувати лише завдання, що належать до свого облікового запису AceDataCloud.

## Параметри запиту

Тіло запиту розділяється за `action` на два типи дій:

### `action: "retrieve"` — запит одиночного запису

| Поле       | Тип    | Обов'язково | Опис                                                                            |
| ---------- | ------ | :---------: | ------------------------------------------------------------------------------- |
| `action`   | const  |      ✅      | Фіксоване `"retrieve"`.                                                         |
| `id`       | string |    один з   | ID завдання (з'являється в кожному envelope `render/extract` у полі `task_id`). |
| `trace_id` | string |    один з   | ID виклику (поле `trace_id` у envelope).                                        |

`id` та `trace_id` передаються один з одного.

### `action: "retrieve_batch"` — пакетний запит

| Поле        | Тип       | Обов'язково | Опис                                                 |
| ----------- | --------- | :---------: | ---------------------------------------------------- |
| `action`    | const     |      ✅      | Фіксоване `"retrieve_batch"` .                       |
| `ids`       | string\[] |    один з   | Список ID завдань.                                   |
| `trace_ids` | string\[] |    один з   | Список ID викликів.                                  |
| `offset`    | number    |      ❌      | Зсув для пагінації (за замовчуванням 0).             |
| `limit`     | number    |      ❌      | Розмір однієї сторінки, 1–100 (за замовчуванням 50). |

`ids` та `trace_ids` передаються один з одного.

## Відповідь на одиночний запит

```json theme={null}
{
  "task": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "trace_id": "550e8400-e29b-41d4-a716-446655440001",
    "type": "extract",
    "created_at": 1777717800.05,
    "started_at": 1777717800.123,
    "finished_at": 1777717802.535,
    "elapsed": 2.412,
    "request": {
      "url": "https://en.wikipedia.org/wiki/Diffbot",
      "expected_type": "article"
    },
    "response": {
      "success": true,
      "data": { /* повний extract envelope */ }
    }
  }
}
```

Якщо не знайдено, повертається `{ "task": null }` (HTTP 200, не 404).

Поля часу об'єкта `task` описуються наступним чином.

* `created_at`, час створення завдання, Unix timestamp (секунди, з плаваючою комою).
* `started_at`, час початку виконання завдання, Unix timestamp (секунди, з плаваючою комою). Якщо завдання ще не почалося, то `null`.
* `finished_at`, час завершення завдання, Unix timestamp (секунди, з плаваючою комою). Якщо завдання не завершено, то `null`.
* `elapsed`, час виконання завдання, одиниця виміру — секунди (з плаваючою комою, зберігається 3 знаки після коми). Якщо завдання не завершено, то `null`.

## Пакетна відповідь

```json theme={null}
{
  "tasks": [
    { /* така ж структура, як у одиночному .task */ },
    { /* ... */ }
  ],
  "offset": 0,
  "limit":  50
}
```

Неіснуючі ID не викликають помилок, просто відсутні в `tasks`.

## Приклади

### Запит одиночного запису за task\_id

```bash theme={null}
curl -X POST https://api.acedata.cloud/webextrator/tasks \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "retrieve",
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }'
```

### Запит одиночного запису за trace\_id

```bash theme={null}
curl -X POST https://api.acedata.cloud/webextrator/tasks \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "retrieve",
    "trace_id": "550e8400-e29b-41d4-a716-446655440001"
  }'
```

### Пакетний запит

```bash theme={null}
curl -X POST https://api.acedata.cloud/webextrator/tasks \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "retrieve_batch",
    "ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "550e8400-e29b-41d4-a716-446655440002"
    ],
    "limit": 50
  }'
```

### Python (requests) — опитування до завершення

```python theme={null}
import os, time, requests

API_KEY = os.environ["ACEDATA_API_KEY"]
BASE = "https://api.acedata.cloud"

# 1) Подати асинхронний запит на витяг
queue = requests.post(
    f"{BASE}/webextrator/extract",
    headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
    json={"url": "https://example.com", "mode": "async"},
).json()

job_id = queue["jobId"]

# 2) Використати Tasks API для опитування до завершення завдання
while True:
    r = requests.post(
        f"{BASE}/webextrator/tasks",
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json={"action": "retrieve", "id": job_id},
    ).json()
    task = r.get("task")
    if task and task.get("finished_at"):
        print("Час виконання", task["elapsed"], "секунд")
        print(task["response"]["data"]["title"])
        break
    time.sleep(2)
```

### Node.js (fetch) — отримати повний envelope після отримання callback

```js theme={null}
// У вашій функції обробки callback_url:
app.post('/hooks/webextrator', async (req, res) => {
  res.status(200).end();              // Спочатку швидко ack

  const taskId = req.body?.task_id;
  if (!taskId) return;

  const fetchRes = await fetch('https://api.acedata.cloud/webextrator/tasks', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.ACEDATA_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ action: 'retrieve', id: taskId }),
  });
  const { task } = await fetchRes.json();
  console.log('Повний envelope:', task.response.data);
});
```

## Помилки у відповіді

| HTTP | `error.code`   | Значення                                                                               |
| ---- | -------------- | -------------------------------------------------------------------------------------- |
| 400  | `bad_request`  | Перевірка не пройшла (відсутній `action`, одночасно передані `id` та `trace_id` тощо). |
| 401  | `unauthorized` | Відсутній або недійсний `Authorization: Bearer …`.                                     |

```json theme={null}
{ "error": { "code": "bad_request", "message": "..." } }
```

## Поради та підводні камені

* **Можна налаштувати `trace_id`, то налаштуйте.** У початковому запиті render/extract завантажте
  `?trace_id=…` (QueryString), узгодьте його зі своїм бізнес ID (ідентифікатор виконання робочого процесу тощо),
  після цього можна буде шукати завдання за бізнес ID. Якщо не передано, сервер автоматично генерує UUID.
* **Термін зберігання 7 днів.** Раніші завдання повертають `task: null` — для тривалого архівування, будь ласка, зберігайте в базі даних самостійно.
* **Запит завдань безкоштовний.** Хочете перевіряти скільки завгодно разів, початковий виклик render/extract вже оплачений.
* **Переважно використовуйте асинхронний + зворотний виклик, а не опитування.** Якщо бізнес дозволяє, у початковому запиті передайте
  `callback_url`, щоб платформа могла надіслати вам envelope, це ефективніше, ніж опитування кожні 2 секунди.
