---
title: Callbacks | RunAPI
description: Receba e verifique entregas de callback de Task com segurança.
url: https://runapi.ai/pt-BR/docs/guides/task-api/callbacks.md
canonical: https://runapi.ai/pt-BR/docs/guides/task-api/callbacks
locale: pt-BR
---

> Versão HTML: https://runapi.ai/pt-BR/docs/guides/task-api/callbacks
> Índice do site para agentes: https://runapi.ai/llms.txt

# Callbacks

Use Callbacks para receber eventos do ciclo de vida de Tasks em um endpoint HTTPS público. Verifique cada callback antes de processar seu corpo JSON para que apenas entregas assinadas para a sua conta possam alterar o estado da aplicação.

## Configurar uma URL de callback

Adicione um `callback_url` HTTPS público ao criar uma Tarefa. O corpo do evento
e os estados do ciclo de vida dependem do endpoint; consulte a Referência da API
daquele endpoint para conhecer os payloads de callback.

```json
{
  "model": "flux-2-pro-text-to-image",
  "prompt": "A product photograph on a clean studio background",
  "callback_url": "https://your-domain.com/webhooks/runapi"
}
```

## Criar um Callback Secret

Siga o [Guia de Autenticação](https://runapi.ai/pt-BR/docs/guides/authentication.md) para fazer
login, depois abra Chaves de API e crie um Callback Secret para a conta que
cria a Task. Armazene o valor em um gerenciador de segredos e o disponibilize
somente para o seu receptor de callbacks. Não é uma Chave de API e nunca deve
ser enviado em uma requisição de Task.

O secret assina os callbacks daquela conta. Rotacioná-lo altera a assinatura para entregas posteriores, portanto atualize imediatamente todos os receptores de callback e mantenha ambos os valores disponíveis apenas pelo tempo necessário para tratar as entregas em andamento.

## Verificar uma assinatura de callback

Cada callback é um HTTP `POST` com `Content-Type: application/json`.
O RunAPI não adiciona um cabeçalho `Authorization` a esta requisição. Verifique estes cabeçalhos antes de desserializar o corpo:

| Cabeçalho | Significado |
|----------
| `X-Callback-Id` | Identificador único para esta tentativa de entrega. |
| `X-Callback-Timestamp` | Timestamp Unix em segundos de quando a entrega foi assinada. |
| `X-Callback-Signature` | Assinatura HMAC-SHA-256 codificada em Base64. |

Construa o valor assinado exatamente como descrito abaixo, utilizando os bytes do corpo da
requisição sem modificações:

```text
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
```

Decodifique o Callback Secret em Base64, calcule o HMAC-SHA-256 sobre esse
valor, codifique o resultado em Base64 e compare-o com
`X-Callback-Signature` usando uma comparação segura contra timing. Não analise nem
re-serialize o JSON antes de verificar.

### JavaScript

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyCallback({headers, rawBody, callbackSecret}) {
  const callbackId = headers["x-callback-id"];
  const timestamp = Number(headers["x-callback-timestamp"]);
  const signature = headers["x-callback-signature"];

  if (!callbackId || !signature || !Number.isSafeInteger(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const signedContent = `${callbackId}.${timestamp}.${rawBody}`;
  const expected = createHmac("sha256", Buffer.from(callbackSecret, "base64"))
    .update(signedContent, "utf8")
    .digest();
  const received = Buffer.from(signature, "base64");

  return expected.length === received.length && timingSafeEqual(expected, received);
}
```

Passe a string de corpo bruto da solicitação do framework para `rawBody`; não chame
`JSON.stringify` em dados já analisados.

### Python

```python
import base64
import hashlib
import hmac
import time


def verify_callback(headers, raw_body, callback_secret):
    callback_id = headers.get("X-Callback-Id")
    timestamp = headers.get("X-Callback-Timestamp")
    signature = headers.get("X-Callback-Signature")

    if not callback_id or not timestamp or not signature:
        return False

    try:
        timestamp = int(timestamp)
        secret = base64.b64decode(callback_secret, validate=True)
        received = base64.b64decode(signature, validate=True)
    except (ValueError, TypeError):
        return False

    if abs(time.time() - timestamp) > 300:
        return False

    signed_content = f"{callback_id}.{timestamp}.{raw_body}".encode("utf-8")
    expected = hmac.new(secret, signed_content, hashlib.sha256).digest()
    return hmac.compare_digest(expected, received)
```

Passe a string exata do corpo bruto da solicitação recebida pelo seu framework HTTP
como `raw_body`.

## Processar entregas com segurança

* Retorne uma resposta `2xx` somente após o callback ter sido aceito para
  processamento. Após uma resposta não `2xx` ou falha de transporte, a entrega
  é tentada até 10 vezes.
* Responda dentro de 15 segundos. Enfileire trabalhos mais lentos após a
  verificação, em vez de bloquear a resposta HTTP.
* Rejeite Callbacks com cabeçalhos de assinatura ausentes, assinatura inválida
  ou timestamp fora da janela de tolerância definida pelo seu receptor.

## Solucionar problemas de verificação

* **Incompatibilidade de assinatura:** confirme que o Callback Secret pertence à mesma conta que a Tarefa, decodifique-o com Base64 e assine o corpo original em vez do JSON parseado.
* **Cabeçalhos de assinatura ausentes:** crie um Callback Secret antes de depender de callbacks para mudanças de estado.
* **Timestamp rejeitado:** sincronize o relógio do receptor e utilize uma tolerância adequada para o seu ambiente de implantação.

Para orientações de configuração e ciclo de vida, volte ao [Início rápido da API de
Task](https://runapi.ai/pt-BR/docs/guides/task-api/quickstart.md).

---

## Mais de RunAPI

- [Início](https://runapi.ai/pt-BR/.md)
- [Catálogo de modelos](https://runapi.ai/pt-BR/models.md)
- [Preços](https://runapi.ai/pt-BR/pricing.md)
- [Provedores](https://runapi.ai/pt-BR/models)
- [Documentação](https://runapi.ai/pt-BR/docs/guides)
- [SDKs](https://runapi.ai/pt-BR/sdk.md)
- [CLI](https://runapi.ai/pt-BR/cli.md)
- [Servidor MCP](https://runapi.ai/pt-BR/mcp.md)
- [Claude Code vs Cursor](https://runapi.ai/pt-BR/claude-code-vs-cursor.md)
- [Configuração da API do Cursor](https://runapi.ai/pt-BR/cursor-api-setup.md)
- [RunAPI vs OpenRouter](https://runapi.ai/pt-BR/openrouter-alternative.md)
- [Enterprise](https://runapi.ai/pt-BR/contact.md)
- [Contato](https://runapi.ai/pt-BR/contact.md)
- [Termos](https://runapi.ai/pt-BR/terms.md)
- [Privacidade](https://runapi.ai/pt-BR/privacy.md)
- [Índice do site para agentes](https://runapi.ai/llms.txt)

Contato: contact@runapi.ai

## Dados estruturados

```json
[
  {
    "@context": "https://schema.org",
    "inLanguage": "pt-BR",
    "@type": "WebSite",
    "name": "RunAPI",
    "url": "https://runapi.ai/pt-BR",
    "potentialAction": {
      "@type": "SearchAction",
      "target": {
        "@type": "EntryPoint",
        "urlTemplate": "https://runapi.ai/pt-BR/models?q={search_term_string}"
      },
      "query-input": "required name=search_term_string"
    }
  },
  {
    "@context": "https://schema.org",
    "inLanguage": "pt-BR",
    "@type": "Organization",
    "name": "RunAPI",
    "url": "https://runapi.ai/pt-BR",
    "logo": {
      "@type": "ImageObject",
      "url": "https://runapi.ai/pt-BRicon.svg"
    },
    "sameAs": [
      "https://github.com/runapi-ai"
    ]
  },
  {
    "@context": "https://schema.org",
    "inLanguage": "pt-BR",
    "@type": "TechArticle",
    "headline": "Callbacks",
    "description": "Receba e verifique entregas de callback de Task com segurança.",
    "url": "https://runapi.ai/pt-BR/docs/guides/task-api/callbacks",
    "mainEntityOfPage": "https://runapi.ai/pt-BR/docs/guides/task-api/callbacks"
  }
]
```
