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

# Consumo de eventos

> Consume eventos de Streaming Hub: verifica firmas HMAC de webhook, maneja la rotación, lee los headers X-Lerian, deduplica entregas y usa pull con confirmación por cursor.

Streaming Hub entrega eventos de dos maneras. Los sinks de **push** (`webhook`, `sqs`, `rabbitmq`, `eventbridge`) envían cada evento coincidente a un destino que tú posees. Un sink de **pull** mantiene los eventos en un cursor del lado del servidor que tu consumidor lee en su propio horario. Esta página cubre qué debe hacer tu consumidor en cada caso.

## Verificación de una firma de webhook

***

Streaming Hub firma cada entrega de webhook con un HMAC sobre la marca de tiempo de la solicitud y el cuerpo exacto de la solicitud. La firma prueba que la solicitud vino de Streaming Hub y que no fue alterada ni reenviada. Dos headers llevan la firma:

| Header                | Valor                                                       |
| --------------------- | ----------------------------------------------------------- |
| `X-Webhook-Signature` | `v1,sha256=<hex>`, la firma.                                |
| `X-Webhook-Timestamp` | La marca de tiempo en segundos Unix incorporada a la firma. |

La fórmula de la firma es:

```
signature_input = "v1:" + X-Webhook-Timestamp + "." + <raw request body>
X-Webhook-Signature = "v1,sha256=" + hex( HMAC-SHA256(key = signing_secret, message = signature_input) )
```

Para verificar una entrega:

1. **Lee el cuerpo sin procesar y la marca de tiempo**: verifica **antes** de parsear el cuerpo, sobre los bytes exactos que recibiste. Cualquier reserialización cambia los bytes y rompe la firma.
2. **Comprueba la frescura**: rechaza la solicitud si `X-Webhook-Timestamp` está a más de **5 minutos** de ahora. Esta es la ventana de protección contra replay.
3. **Recalcula la firma**: construye `signature_input` como arriba con tu secreto de firma y codifica en hexadecimal el HMAC-SHA256.
4. **Compara en tiempo constante**: compara tu `v1,sha256=<hex>` con el `X-Webhook-Signature` recibido mediante una comparación de tiempo constante, segura frente a ataques de tiempo. Rechaza si no coinciden.
5. **Responde**: devuelve `2xx` solo después de que la firma y la frescura pasen las dos.

Recibes el secreto de firma cuando creas la suscripción, o en tu rotación más reciente. Streaming Hub nunca envía el secreto en un header. El header lleva solo la firma derivada. Consulta [crear una suscripción de webhook](/es/platform/streaming-hub/managing-subscriptions) para saber de dónde viene el secreto.

## Manejo de dos firmas durante la rotación

***

Cuando [rotas un secreto de firma](/es/platform/streaming-hub/managing-subscriptions), el hub ejecuta un **solapamiento de doble firma de 24 horas**. Durante el solapamiento cada entrega lleva **dos headers `X-Webhook-Signature`**, uno firmado con el secreto nuevo y otro con el secreto anterior. El hub los envía como **headers repetidos**, así que puedes migrar al secreto nuevo sin perder ninguna entrega.

Verifica contra los dos: recalcula la firma esperada con cada secreto que tengas en ese momento y **acepta la solicitud si alguna de las firmas recibidas coincide**. Una vez que hayas desplegado y confirmado el secreto nuevo, retira el viejo.

<Warning>
  Lee `X-Webhook-Signature` como una **lista de valores de header repetidos** con el accesor de headers de varios valores de tu framework (o con su vista de headers sin procesar). **No** dividas una sola cadena unida por comas: el valor de la firma contiene una coma (`v1,sha256=…`), así que una división ingenua por comas lo corrompe. Algunas pilas HTTP unen los headers repetidos con `", "` de forma predeterminada. Usa el accesor de lista para obtener cada valor intacto.
</Warning>

## Headers de correlación

***

Cada entrega de webhook también lleva un conjunto de headers de contexto `X-Lerian-*`:

| Header                    | Lleva                                                                                                                              |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `X-Lerian-Event-Id`       | El id estable del evento (el `ce-id` de CloudEvents). **La clave de deduplicación**, constante en las reentregas del mismo evento. |
| `X-Lerian-Event-Type`     | El tipo de evento, como la cola simple `<resource>.<event>` (por ejemplo, `transaction.created`).                                  |
| `X-Lerian-Tenant-Id`      | El id del tenant dueño (solo para atribución).                                                                                     |
| `X-Lerian-Delivery-Id`    | El id por intento, que **cambia en cada reintento** del mismo evento.                                                              |
| `X-Lerian-Schema-Version` | La versión de esquema del payload.                                                                                                 |

<Warning>
  La entrega por webhook no lleva ningún header con la fuente productora. `X-Lerian-Event-Type` no lleva la fuente a propósito, así que un consumidor no puede distinguir dos productores que emiten la misma clave, a menos que la suscripción fije `origin`. Crea una suscripción con el origin fijado por cada productor cuando la identidad de la fuente importa.
</Warning>

## Deduplicación de entregas

***

La entrega es **al menos una vez**: el hub puede entregar el mismo evento más de una vez, mediante reintentos o una reentrega después de que un worker se reinicia. Deduplica por **`X-Lerian-Event-Id`**. Es estable en cada reentrega del mismo evento, mientras que `X-Lerian-Delivery-Id` difiere por intento. Trata un `X-Lerian-Event-Id` que ya procesaste como un duplicado: confírmalo con un `2xx` y no lo vuelvas a procesar. Mantén tu handler idempotente.

## Respuesta rápida

***

Devuelve un `2xx` en cuanto hayas verificado y aceptado de forma duradera el evento. Luego haz el trabajo real de forma asíncrona. El hub trata una respuesta lenta o con falla como una entrega fallida. Una entrega fallida dispara la [curva de reintentos](/es/platform/streaming-hub/how-streaming-hub-works). Si el destino sigue roto el tiempo suficiente, el hub al final [desactiva automáticamente](/es/platform/streaming-hub/how-streaming-hub-works) la suscripción.

## Lectura de eventos con pull

***

Una suscripción `pull` no recibe push. En su lugar, tu consumidor lee una página de sus eventos con:

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

Los eventos vuelven en orden ascendente de llegada, cada uno con su `seq`, su `ceId` (para deduplicar), su tipo y su payload. La respuesta incluye un `next_cursor`.

**La lectura es la confirmación (el cursor como confirmación).** Traer una página avanza el cursor duradero de la suscripción hasta el `seq` más alto devuelto. No hay una llamada de confirmación aparte. Leer una página la confirma. Esto es monótono, así que nunca retrocede.

Para paginar de forma normal, retoma desde el `next_cursor` del servidor y detente cuando una página corta (con menos elementos que tu `limit`) devuelve `null`. Dos comportamientos para tener presentes:

* **Un salto hacia adelante con `?after=` renuncia al hueco.** Pasar `?after=N` mayor que tu cursor actual avanza el cursor más allá de todo hasta `N`. Los eventos saltados **nunca se reentregan**. Pedir eventos después de `N` declara consumido todo hasta `N`. Esto solo puede pasar con un salto hacia adelante hecho a mano, nunca con la paginación normal por `next_cursor`.
* **Un salto hacia atrás con `?after=` nunca rebobina.** Un `?after=` viejo o más bajo que lee una página anterior no mueve el cursor hacia atrás, porque el cursor solo avanza.

La lectura con pull tiene rate limit por tenant. Una lectura denegada devuelve **`429 rate_limited`**. Aplica backoff y reintenta. Deduplica los eventos leídos con pull por `ceId`, igual que un consumidor de webhook deduplica por `X-Lerian-Event-Id`.

## Próximos pasos

***

<CardGroup cols={2}>
  <Card title="Gestión de suscripciones" icon="gear" href="/es/platform/streaming-hub/managing-subscriptions">
    Crea suscripciones, rota secretos y recupera destinos desactivados.
  </Card>

  <Card title="Operación de Streaming Hub" icon="server" href="/es/platform/streaming-hub/operating-streaming-hub">
    Despliega, configura y observa el hub.
  </Card>
</CardGroup>
