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

# Webhooks

> Payload de entrega, cronograma de novas tentativas e como escrever um handler seguro.

Informe `webhook.url` em uma tarefa e enviaremos o resultado por POST quando a tarefa chegar a um estado final:
`COMPLETED` ou `FAILED`.

```json theme={null}
{
  "taskType": "PERPLEXITY",
  "payload": { "prompt": "best wireless earbuds 2026" },
  "webhook": { "url": "https://your-server.example.com/hook" }
}
```

## Payload de entrega

Enviamos por POST `Content-Type: application/json` com este corpo:

<ResponseField name="task" type="object" required>
  Os mesmos metadados de tarefa recebidos no envio, agora com um `status` final e o seu `idempotencyKey` devolvido.
</ResponseField>

<ResponseField name="credits" type="object" required>
  O custo em créditos do mecanismo: `2` para Perplexity, `3` para ChatGPT e assim por diante (1–3 créditos conforme o
  mecanismo). `creditsCharged` é `0` quando a tarefa falhou. Ao contrário das respostas de envio e polling, que sempre
  informam zero, este campo não é zero.
</ResponseField>

<ResponseField name="response" type="object" required>
  O resultado específico do mecanismo. Veja [Mecanismos](/pt/engines/overview). Em uma tarefa com falha, é
  `{ "error": "<reason>" }` em vez do resultado do mecanismo.
</ResponseField>

```json theme={null}
{
  "task": {
    "id": "8f2c1e40-...",
    "taskType": "PERPLEXITY",
    "status": "COMPLETED",
    "priority": 1,
    "createdAt": "2026-07-09T04:12:00.000Z",
    "idempotencyKey": "job-42:prompt-7:perplexity"
  },
  "credits": { "creditsToCharge": 3, "creditsCharged": 3 },
  "response": {
    "text": "The best wireless earbuds in 2026 are ...",
    "sources": [{ "position": 1, "url": "https://...", "label": "..." }]
  }
}
```

Uma tarefa com falha também é entregue:

```json theme={null}
{
  "task": { "id": "8f2c1e40-...", "status": "FAILED", "...": "..." },
  "credits": { "creditsToCharge": 3, "creditsCharged": 0 },
  "response": { "error": "ENGINE_TIMEOUT: The engine did not answer before the task deadline." }
}
```

## Novas tentativas

Retorne qualquer `2xx` para confirmar. Qualquer outra coisa, inclusive um timeout, é falha, e tentamos de novo com
backoff exponencial:

| Tentativa | Disparo |
| - | - |
| 1 | imediatamente |
| 2 | após 2 minutos |
| 3 | após 4 minutos |
| 4 | após 8 minutos |
| 5 | após 16 minutos |

Depois da quinta tentativa, a entrega é abandonada e registrada em log. Não existe fila de mensagens mortas que você
possa ler. Para obter o resultado pela API de tarefas, consulte dentro da janela pública de polling de 24 horas. Essa
janela não define a vida útil do registro subjacente.

Cada tentativa tem timeout de requisição de **30 segundos**.

<Warning>
  Do ponto de vista da tarefa, a entrega é do tipo "enviar e esquecer". Uma tarefa concluída cujo webhook nunca é
  entregue continua mostrando `COMPLETED` em `GET /v1/async/task/{id}`: o status descreve o trabalho do mecanismo,
  não a notificação.
</Warning>

## Escrevendo um handler seguro

<Steps>
  <Step title="Confirme rápido">
    Retorne `200` assim que tiver enfileirado o payload de forma persistente. Faça o parsing e as gravações no banco
    depois. Um handler lento consome o timeout de 30 segundos e provoca uma nova tentativa indesejada.
  </Step>

  <Step title="Deduplique pelo idempotencyKey">
    Por causa das novas tentativas, seu handler pode receber legitimamente a mesma tarefa mais de uma vez. Compare por
    `task.idempotencyKey` (ou `task.id`) e torne a gravação idempotente.
  </Step>

  <Step title="Ramifique pelo status, não pela presença">
    Verifique `task.status === "FAILED"` explicitamente. Uma tarefa com falha também entrega webhook.
  </Step>
</Steps>

<Note>
  As requisições de webhook não têm assinatura nem segredo compartilhado. Se seu endpoint for público, trate o payload
  como não confiável e use um caminho de URL impossível de adivinhar, ou coloque o handler atrás de restrições de rede.
</Note>
