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

# Consumindo eventos

> Consuma eventos do Streaming Hub: verifique uma assinatura HMAC de webhook, lide com duas assinaturas durante a rotação, leia os cabeçalhos de correlação X-Lerian, deduplique entregas e consuma eventos por pull com cursor-as-ack.

O Streaming Hub entrega eventos de duas formas. Os sinks **push** (`webhook`, `sqs`, `rabbitmq`, `eventbridge`) enviam cada evento que deu match a um destino de sua propriedade. Um sink **pull** mantém os eventos em um cursor do lado do servidor que o seu consumidor lê no seu próprio ritmo. Esta página cobre o que o seu consumidor precisa fazer em cada caso.

## Verificando uma assinatura de webhook

***

Toda entrega de webhook é assinada com um HMAC sobre o timestamp da requisição e o corpo exato da requisição, para que você possa provar que a requisição veio do Streaming Hub e não foi adulterada nem sofreu replay. Dois cabeçalhos carregam a assinatura:

| Cabeçalho             | Valor                                               |
| --------------------- | --------------------------------------------------- |
| `X-Webhook-Signature` | `v1,sha256=<hex>` — a assinatura.                   |
| `X-Webhook-Timestamp` | O timestamp em segundos Unix dobrado na assinatura. |

A assinatura é computada como:

```
signature_input = "v1:" + X-Webhook-Timestamp + "." + <corpo bruto da requisição>
X-Webhook-Signature = "v1,sha256=" + hex( HMAC-SHA256(key = signing_secret, message = signature_input) )
```

Para verificar uma entrega:

1. **Leia o corpo bruto e o timestamp** — verifique **antes** de fazer o parse do corpo, sobre os bytes exatos recebidos. Qualquer re-serialização muda os bytes e quebra a assinatura.
2. **Cheque a atualidade** — rejeite a requisição se o `X-Webhook-Timestamp` estiver a mais de **5 minutos** do momento atual. Esta é a janela de proteção contra replay.
3. **Recompute a assinatura** — construa o `signature_input` como acima com o seu segredo de assinatura e codifique em hex o HMAC-SHA256.
4. **Compare em tempo constante** — compare o seu `v1,sha256=<hex>` contra o `X-Webhook-Signature` recebido com uma comparação em tempo constante (timing-safe). Rejeite em caso de divergência.
5. **Responda** — retorne `2xx` somente depois que a assinatura e a atualidade passarem.

O segredo de assinatura é aquele que você recebeu quando criou a assinatura (ou na última rotação). Ele nunca é enviado em um cabeçalho — apenas a assinatura derivada é. Veja [criando uma assinatura de webhook](/pt/streaming-hub/managing-subscriptions) para saber de onde vem o segredo.

## Lidando com duas assinaturas durante a rotação

***

Quando você [rotaciona um segredo de assinatura](/pt/streaming-hub/managing-subscriptions), o hub executa uma **sobreposição de assinatura dupla de 24 horas**. Durante a sobreposição, cada entrega carrega **dois cabeçalhos `X-Webhook-Signature`** — um assinado com o novo segredo e um com o segredo anterior — enviados como **cabeçalhos repetidos**, para que você possa migrar para o novo segredo sem perder nenhuma entrega.

Verifique contra os dois: recompute a assinatura esperada com cada segredo que você tem no momento, e **aceite a requisição se qualquer uma das assinaturas recebidas der match**. Uma vez que você tenha feito o deploy e confirmado o novo segredo, aposente o antigo.

<Warning>
  Leia o `X-Webhook-Signature` como uma **lista de valores de cabeçalho repetidos** usando o acessor de cabeçalho multi-valor do seu framework (ou a sua visão de cabeçalhos brutos). **Não** divida uma única string unida por vírgulas: o próprio valor da assinatura contém uma vírgula (`v1,sha256=…`), então uma divisão ingênua por vírgula o corrompe. Alguns stacks HTTP unem cabeçalhos repetidos com `", "` por padrão — use o acessor de lista para obter cada valor intacto.
</Warning>

## Cabeçalhos de correlação

***

Toda entrega de webhook também carrega um conjunto de cabeçalhos de contexto `X-Lerian-*`:

| Cabeçalho                 | Carrega                                                                                                                       |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `X-Lerian-Event-Id`       | O id de evento estável (o `ce-id` do CloudEvents). **A chave de deduplicação** — constante entre re-entregas do mesmo evento. |
| `X-Lerian-Event-Type`     | O tipo de evento, apenas o final `<resource>.<event>` (por exemplo, `transaction.created`).                                   |
| `X-Lerian-Tenant-Id`      | O id do tenant proprietário (apenas atribuição).                                                                              |
| `X-Lerian-Delivery-Id`    | O id por tentativa — **muda a cada retentativa** do mesmo evento.                                                             |
| `X-Lerian-Schema-Version` | A versão do esquema do payload.                                                                                               |

## Deduplicando entregas

***

A entrega é **at-least-once**: o hub pode entregar o mesmo evento mais de uma vez, através de retentativas ou de uma re-entrega após o reinício de um worker. Deduplique por **`X-Lerian-Event-Id`** — ele é estável entre toda re-entrega do mesmo evento, enquanto o `X-Lerian-Delivery-Id` difere por tentativa. Trate um `X-Lerian-Event-Id` que você já processou como uma duplicata: confirme-o com um `2xx` e não o reprocesse. Mantenha o seu handler idempotente.

## Respondendo rapidamente

***

Retorne um `2xx` assim que você tiver verificado e aceito o evento de forma durável — então faça o trabalho de verdade de forma assíncrona. Uma resposta lenta ou que falha é tratada como uma entrega falha, o que dispara a [curva de retentativa](/pt/streaming-hub/how-streaming-hub-works) e, se o destino permanecer quebrado por tempo suficiente, eventualmente [desativa automaticamente](/pt/streaming-hub/how-streaming-hub-works) a assinatura. Confirme rápido, processe fora de banda.

## Consumindo eventos por pull

***

Uma assinatura `pull` não recebe push. Em vez disso, o seu consumidor lê uma página dos seus eventos com:

```
GET /v1/events?subscription_id=<uuid>
```

Os eventos voltam em ordem crescente de chegada, cada um com o seu `seq`, o seu `ceId` (para dedup), o seu tipo e o seu payload. A resposta inclui um `next_cursor`.

**A leitura é a confirmação (cursor-as-ack).** Buscar uma página avança o cursor durável da assinatura até o maior `seq` retornado. Não há uma chamada de ack separada — ler uma página a confirma. Isso é monotônico, então nunca anda para trás.

Para paginar normalmente, retome a partir do `next_cursor` do servidor e pare quando uma página curta (com menos itens do que o seu `limit`) retornar `null`. Dois comportamentos a ter em mente:

* **Um seek `?after=` para frente abre mão da lacuna.** Passar `?after=N` maior do que o seu cursor atual avança o cursor para além de tudo até `N` — os eventos pulados **nunca são re-entregues**. Pedir eventos após `N` declara tudo até `N` como consumido. Isso só pode acontecer com um seek para frente feito à mão, nunca através da paginação normal por `next_cursor`.
* **Um seek `?after=` para trás nunca rebobina.** Um `?after=` obsoleto ou menor que lê uma página mais antiga não move o cursor para trás, porque o cursor só avança.

A leitura por pull é limitada por taxa por tenant. Uma leitura negada retorna **`429 rate_limited`** — faça back-off e tente de novo. Deduplique os eventos consumidos por pull pelo `ceId`, exatamente como um consumidor de webhook deduplica pelo `X-Lerian-Event-Id`.

## Próximos passos

***

<CardGroup cols={2}>
  <Card title="Gerenciando assinaturas" icon="gear" href="/pt/streaming-hub/managing-subscriptions">
    Crie assinaturas, rotacione segredos e recupere destinos desativados.
  </Card>

  <Card title="Operando o Streaming Hub" icon="server" href="/pt/streaming-hub/operating-streaming-hub">
    Faça o deploy, configure e observe o hub.
  </Card>
</CardGroup>
