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

# Implementar un receptor

> Tutorial completo para recibir el primer webhook de Cobrix

Un webhook es una petición HTTP `POST` que Cobrix envía a tu servidor cuando ocurre algo relevante. Tu receptor debe validar que la petición proviene de Cobrix, guardar el evento y responder rápido.

## Antes de programar

<Check>Una URL pública con HTTPS para sandbox</Check>
<Check>El secreto del webhook guardado como variable de entorno</Check>
<Check>El evento `webhook.test` habilitado para la prueba inicial</Check>
<Check>Acceso al cuerpo crudo de la petición, antes de convertirlo a objeto</Check>

## Configura el endpoint

En Cobrix abre **Configuración → Integraciones → Webhooks**, crea un endpoint y define:

| Campo   | Qué colocar                                                                              |
| ------- | ---------------------------------------------------------------------------------------- |
| URL     | La ruta pública de tu receptor, por ejemplo `https://api.tu-sistema.com/webhooks/cobrix` |
| Secreto | Un valor largo y aleatorio. No lo envíes en el payload ni lo registres en logs.          |
| Eventos | Selecciona únicamente los eventos que tu sistema procesa.                                |
| Estado  | Debe estar habilitado para recibir entregas.                                             |

<Info>
  Usa endpoint y secreto distintos para sandbox y producción. El ambiente se determina por la aplicación Cobrix desde la que configuraste el webhook.
</Info>

## Flujo de una entrega

<Steps>
  <Step title="Cobrix construye el evento">
    El payload incluye un identificador, el tipo de evento, la fecha, la versión y los datos específicos.
  </Step>

  <Step title="Cobrix firma los bytes">
    La firma HMAC-SHA256 se calcula sobre el cuerpo JSON exacto. Los eventos generales incluyen también un timestamp.
  </Step>

  <Step title="Tu endpoint verifica">
    Lee el cuerpo crudo, calcula la firma esperada y compárala en tiempo constante.
  </Step>

  <Step title="Tu endpoint deduplica">
    Guarda `payload.id` con una restricción única. Si ya existe, no repitas la acción.
  </Step>

  <Step title="Tu endpoint responde">
    Encola el trabajo y devuelve `200` inmediatamente. El procesamiento financiero o de negocio continúa en segundo plano.
  </Step>
</Steps>

## Receptor mínimo en Node.js

```javascript theme={null}
import crypto from 'node:crypto'
import express from 'express'

const app = express()

// express.raw conserva exactamente los bytes firmados por Cobrix.
app.post('/webhooks/cobrix', express.raw({ type: 'application/json' }), async (req, res) => {
  const rawBody = req.body
  const signatureHeader = req.get('X-Cobrix-Signature') ?? ''
  const parts = Object.fromEntries(signatureHeader.split(',').map(part => part.split('=')))
  const timestamp = Number(parts.t)

  if (!Number.isFinite(timestamp) || Math.abs(Math.floor(Date.now() / 1000) - timestamp) > 300) {
    return res.status(401).json({ error: 'stale_webhook' })
  }

  const expected = crypto
    .createHmac('sha256', process.env.COBRIX_WEBHOOK_SECRET)
    .update(`${timestamp}.${rawBody.toString('utf8')}`)
    .digest()
  const received = Buffer.from(parts.v1 ?? '', 'hex')

  if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
    return res.status(401).json({ error: 'invalid_signature' })
  }

  const payload = JSON.parse(rawBody.toString('utf8'))
  await saveEventIfNew(payload.id, payload.event, payload)
  await enqueueWebhook(payload.id)

  return res.status(200).json({ received: true })
})
```

<Warning>
  No uses `express.json()` antes de esta ruta. Si el framework vuelve a serializar el objeto, espacios, orden o escapes pueden cambiar y la firma dejará de coincidir.
</Warning>

## Qué evento procesar primero

<Columns cols={2}>
  <Card title="Confirmar un pago" icon="circle-check" href="/guides/webhooks/events/payment-succeeded" cta="Ver payment.succeeded" arrow>
    Úsalo como señal final de pago confirmado.
  </Card>

  <Card title="Probar conectividad" icon="flask" href="/guides/webhooks/events/webhook-test" cta="Ver webhook.test" arrow>
    Comprueba URL, firma, timeout y respuesta sin crear movimientos reales.
  </Card>
</Columns>
