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

# Webhooks de Feed

> Assine eventos do ciclo de vida de feeds e verifique assinaturas HMAC-SHA256.

## Visão Geral

Os webhooks de feed notificam seu servidor quando a geração de um feed é concluída, falha ou a validação termina. Configure um ou mais endpoints de webhook por workspace.

## Eventos de Webhook

| Evento           | Gatilho                               |
| ---------------- | ------------------------------------- |
| `feed.generated` | Geração de feed concluída com sucesso |
| `feed.failed`    | Geração de feed falhou                |
| `feed.validated` | Verificação de validação concluída    |

## Criar uma Assinatura

```
POST /api/v1/feeds/{platform}/webhooks
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://app.alana.shopping/api/v1/feeds/google/webhooks" \
    -H "X-API-Key: sk_live_sua_chave_api" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://seuservidor.com/webhooks/alana",
      "events": ["feed.generated", "feed.failed"],
      "secret": "seu_segredo_webhook"
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://app.alana.shopping/api/v1/feeds/google/webhooks",
    {
      method: "POST",
      headers: {
        "X-API-Key": "sk_live_sua_chave_api",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        url: "https://seuservidor.com/webhooks/alana",
        events: ["feed.generated", "feed.failed"],
        secret: "seu_segredo_webhook",
      }),
    }
  );
  const assinatura = await res.json();
  ```

  ```python Python theme={null}
  import requests

  res = requests.post(
      "https://app.alana.shopping/api/v1/feeds/google/webhooks",
      headers={
          "X-API-Key": "sk_live_sua_chave_api",
          "Content-Type": "application/json",
      },
      json={
          "url": "https://seuservidor.com/webhooks/alana",
          "events": ["feed.generated", "feed.failed"],
          "secret": "seu_segredo_webhook",
      },
  )
  assinatura = res.json()
  ```
</CodeGroup>

## Payload do Webhook

```json theme={null}
{
  "event": "feed.generated",
  "workspace_id": "ws_abc123",
  "platform": "google",
  "feed_url": "https://app.alana.shopping/api/v1/feeds/google",
  "product_count": 1432,
  "generated_at": "2026-03-17T12:00:00Z"
}
```

## Verificando Assinaturas (HMAC-SHA256)

Toda requisição de webhook inclui um header `X-Alana-Signature`. Verifique-o para confirmar que a requisição veio do Alana:

<CodeGroup>
  ```javascript JavaScript theme={null}
  import crypto from "crypto";

  function verificarAssinatura(payload, assinatura, segredo) {
    const esperado = crypto
      .createHmac("sha256", segredo)
      .update(payload, "utf8")
      .digest("hex");
    const recebido = assinatura.replace("sha256=", "");
    return crypto.timingSafeEqual(
      Buffer.from(esperado, "hex"),
      Buffer.from(recebido, "hex")
    );
  }

  // Exemplo com Express:
  app.post("/webhooks/alana", (req, res) => {
    const assinatura = req.headers["x-alana-signature"];
    const valido = verificarAssinatura(
      JSON.stringify(req.body),
      assinatura,
      process.env.WEBHOOK_SECRET
    );

    if (!valido) return res.status(401).send("Assinatura inválida");

    const { event, platform, product_count } = req.body;
    console.log(`Feed ${event} para ${platform}: ${product_count} produtos`);
    res.sendStatus(200);
  });
  ```

  ```python Python theme={null}
  import hmac
  import hashlib

  def verificar_assinatura(payload: bytes, assinatura: str, segredo: str) -> bool:
      esperado = hmac.new(
          segredo.encode(), payload, hashlib.sha256
      ).hexdigest()
      recebido = assinatura.replace("sha256=", "")
      return hmac.compare_digest(esperado, recebido)

  # Exemplo com Flask:
  from flask import Flask, request, abort

  app = Flask(__name__)

  @app.post("/webhooks/alana")
  def handle_webhook():
      assinatura = request.headers.get("X-Alana-Signature", "")
      if not verificar_assinatura(request.data, assinatura, WEBHOOK_SECRET):
          abort(401)

      data = request.json
      print(f"Feed {data['event']} para {data['platform']}")
      return "", 200
  ```
</CodeGroup>

## Política de Retry

O Alana tenta reenviar entregas de webhook com backoff exponencial: 1 min, 5 min, 30 min, 2 h, 8 h. Após 5 tentativas falhas, a assinatura é marcada como inativa.

Responda com qualquer status `2xx` em até 10 segundos para confirmar o recebimento.
