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

# Guia de Integração da API de Consulta de Tarefas WebExtrator

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

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

A API de Consulta de Tarefas WebExtrator é usada para consultar os resultados de tarefas `render` / `extract` históricas. Usos comuns:

* **Verificação** do envelope completo após a conclusão da tarefa assíncrona (exceto para o envio de `callback_url` ou polling ativo).
* **Auditoria** do que foi submetido — os registros de tarefas armazenam simultaneamente a `request` original e a `response` final.
* **Preenchimento em massa** — puxar várias entradas de uma só vez por `id` ou `trace_id`.

Os registros de tarefas são mantidos no Redis por **7 dias**.

A interface de consulta de tarefas é **gratuita** (não conta para o uso de Créditos).

## Autenticação

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

Só é possível consultar as tarefas sob a conta AceDataCloud do próprio usuário.

## Parâmetros de Requisição

O corpo da requisição é uma união discriminatória baseada em `action`, com duas ações possíveis:

### `action: "retrieve"` — Consulta de uma única entrada

| Campo      | Tipo   | Obrigatório | Descrição                                                                     |
| ---------- | ------ | :---------: | ----------------------------------------------------------------------------- |
| `action`   | const  |      ✅      | Fixo como `"retrieve"`.                                                       |
| `id`       | string | Um dos dois | ID da tarefa (aparece no campo `task_id` de cada envelope de render/extract). |
| `trace_id` | string | Um dos dois | ID da cadeia de chamadas (campo `trace_id` do envelope).                      |

`id` e `trace_id` devem ser passados como um dos dois.

### `action: "retrieve_batch"` — Consulta em massa

| Campo       | Tipo      | Obrigatório | Descrição                             |
| ----------- | --------- | :---------: | ------------------------------------- |
| `action`    | const     |      ✅      | Fixo como `"retrieve_batch"`.         |
| `ids`       | string\[] | Um dos dois | Lista de IDs de tarefas.              |
| `trace_ids` | string\[] | Um dos dois | Lista de IDs de cadeia de chamadas.   |
| `offset`    | number    |      ❌      | Deslocamento de paginação (padrão 0). |
| `limit`     | number    |      ❌      | Tamanho da página, 1–100 (padrão 50). |

`ids` e `trace_ids` devem ser passados como um dos dois.

## Resposta de uma única entrada

```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": { /* envelope de extract completo */ }
    }
  }
}
```

Quando não encontrado, retorna `{ "task": null }` (HTTP 200, não 404).

Os campos de tempo do objeto `task` são descritos a seguir.

* `created_at`, hora de criação da tarefa, timestamp Unix (segundos, ponto flutuante).
* `started_at`, hora de início da execução da tarefa, timestamp Unix (segundos, ponto flutuante). Será `null` se a tarefa ainda não tiver começado.
* `finished_at`, hora de conclusão da tarefa, timestamp Unix (segundos, ponto flutuante). Será `null` se a tarefa não estiver concluída.
* `elapsed`, tempo gasto na execução da tarefa, em segundos (ponto flutuante, com 3 casas decimais). Será `null` se a tarefa não estiver concluída.

## Resposta em massa

```json theme={null}
{
  "tasks": [
    { /* mesma estrutura de .task */ },
    { /* ... */ }
  ],
  "offset": 0,
  "limit":  50
}
```

IDs inexistentes não gerarão erro, apenas estarão ausentes de `tasks`.

## Exemplos

### Consulta de uma única entrada por 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"
  }'
```

### Consulta de uma única entrada por 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"
  }'
```

### Consulta em massa

```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) — Polling até a conclusão

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

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

# 1) Submeter extração assíncrona
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) Usar a API de Tarefas para polling até a tarefa ser concluída
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("Tempo gasto", task["elapsed"], "segundos")
        print(task["response"]["data"]["title"])
        break
    time.sleep(2)
```

### Node.js (fetch) — Receber callback e puxar envelope completo

```js theme={null}
// No seu manipulador de função callback_url:
app.post('/hooks/webextrator', async (req, res) => {
  res.status(200).end();              // Primeiro, rápido 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 completo:', task.response.data);
});
```

## Respostas de erro

| HTTP | `error.code`   | Significado                                                                  |
| ---- | -------------- | ---------------------------------------------------------------------------- |
| 400  | `bad_request`  | Falha na validação (falta `action`, ambos `id` e `trace_id` enviados, etc.). |
| 401  | `unauthorized` | Falta ou inválido `Authorization: Bearer …`.                                 |

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

## Dicas e Armadilhas

* **Se puder personalizar `trace_id`, faça isso.** No pedido original de render/extract, envie `?trace_id=…` (QueryString), alinhe-o com seu próprio ID de negócio (como o ID de execução do fluxo de trabalho, etc.), e depois você poderá consultar a tarefa usando o ID de negócio. Se não for enviado, o servidor gera automaticamente um UUID.
* **Período de retenção de 7 dias.** Tarefas mais antigas retornam `task: null` — se precisar de arquivamento a longo prazo, faça o armazenamento por conta própria.
* **Consulta de tarefas gratuita.** Consulte quantas vezes quiser, o custo da chamada original de render/extract já foi pago.
* **Prefira usar assíncrono + callback, em vez de polling.** Se o negócio permitir, envie `callback_url` na solicitação original, para que a plataforma possa enviar o envelope para você, o que é mais eficiente do que fazer polling a cada 2 segundos.
