# Webhooks (https://docs.pulsarml.com/es/webhooks)

Recibe una notificación en cuanto un paro de máquina se clasifica, se reclasifica o deja de estar clasificado en Pulsar.



En lugar de consultar la API cada cierto tiempo, puedes hacer que Pulsar llame a tu aplicación cuando algo sucede. Un webhook es un endpoint HTTPS que tú alojas. Pulsar le envía una solicitud `POST` con un cuerpo JSON cada vez que ocurre un evento al que te suscribiste.

Por ahora los webhooks cubren las [clasificaciones de paros de máquina](/es/webhooks/events): Pulsar te avisa cuando un paro se clasifica, cuando una clasificación cambia y cuando se elimina.

## Configura un webhook [#set-up-a-webhook]

<Steps>
  <Step>
    ### Crea un endpoint [#build-an-endpoint]

    Agrega a tu aplicación una ruta que acepte un `POST` con un cuerpo JSON y responda con un estado `2XX`. Tiene que cumplir los [requisitos del endpoint](#endpoint-requirements) que se describen más abajo.
  </Step>

  <Step>
    ### Pide a Pulsar que lo registre [#ask-pulsar-to-register-it]

    Envía a tu contacto en Pulsar:

    * **Nombre**: una etiqueta para el endpoint, como `ERP`.
    * **URL**: la URL HTTPS completa de tu endpoint.
    * **Tipo de evento**: el [evento](/es/webhooks/events) que debe recibir.

    Cada registro recibe un solo tipo de evento. Para recibir varios, registra la misma URL una vez por cada tipo de evento y distingue los casos por `eventType` en tu handler.
  </Step>

  <Step>
    ### Guarda tu secreto de firma [#store-your-signing-secret]

    Pulsar te da un **secreto de firma**. Cada solicitud que envía Pulsar va firmada con él, para que puedas [verificar que realmente viene de Pulsar](/es/webhooks/signatures). Mantenlo fuera del control de versiones, como cualquier otra credencial. Hay un secreto por empresa, compartido por todos tus endpoints.
  </Step>

  <Step>
    ### Envía un ping de prueba [#send-a-test-ping]

    Pide a Pulsar que haga ping a tu endpoint. Recibirás un [evento `Ping`](#ping-events), que confirma que tu endpoint es accesible y que tu verificación de firma funciona, antes de que empiecen a llegar eventos reales.
  </Step>
</Steps>

## Requisitos del endpoint [#endpoint-requirements]

Pulsar solo entrega a endpoints que sean:

* **HTTPS públicos.** La URL debe usar `https://`, tener como máximo 255 caracteres y no incluir credenciales (`user:pass@`) ni `#fragmento`. El nombre de host debe resolver a direcciones IP públicas. Las direcciones privadas, de loopback y link-local se rechazan.
* **Rápidos.** Cada solicitud tiene un límite de **10 segundos**, incluidos la resolución DNS y el establecimiento de la conexión.
* **Definitivos.** Las redirecciones **no se siguen**. Una respuesta `3XX` cuenta como entrega fallida, así que registra la URL final.

## La solicitud [#the-request]

Cada notificación es un `POST` con un cuerpo JSON y estos encabezados:

```http
POST /webhooks/pulsar HTTP/1.1
Host: example.com
Content-Type: application/json
X-Pulsar-Signature: 5c0e2f4a1b9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f
X-Pulsar-Event-Type: MachineStopClassificationCreated
X-Pulsar-Event-Id: 8d2f6c1e-4b7a-4f0e-9a3c-5e1d7b9f2a64
X-Pulsar-Timestamp: 2026-09-25T14:03:12.482Z
X-Pulsar-Request-Id: 3f9b2c7d-1e4a-4c8b-b6d2-9a0e5f7c1b38

{
  "eventId": "8d2f6c1e-4b7a-4f0e-9a3c-5e1d7b9f2a64",
  "eventTimestamp": "2026-09-25T14:03:12.482Z",
  "eventType": "MachineStopClassificationCreated",
  "event": { ... }
}
```

### Encabezados [#headers]

| Encabezado            | Descripción                                                                                                        |
| --------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `Content-Type`        | Siempre `application/json`.                                                                                        |
| `X-Pulsar-Signature`  | Firma HMAC-SHA256 del cuerpo sin procesar. [Verifícala](/es/webhooks/signatures) antes de confiar en la solicitud. |
| `X-Pulsar-Event-Type` | El tipo de evento, igual que `eventType` en el cuerpo.                                                             |
| `X-Pulsar-Event-Id`   | El ID del evento, igual que `eventId` en el cuerpo.                                                                |
| `X-Pulsar-Timestamp`  | Igual que `eventTimestamp` en el cuerpo.                                                                           |
| `X-Pulsar-Request-Id` | El ID de este intento de entrega. Inclúyelo cuando contactes al soporte de Pulsar por una entrega.                 |

Los nombres de los encabezados no distinguen mayúsculas de minúsculas, así que tu framework puede mostrarlos en minúsculas.

### Cuerpo [#body]

Todas las notificaciones tienen el mismo sobre:

| Campo            | Tipo   | Descripción                                                                                                             |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------------------------------- |
| `eventId`        | string | ID único del evento. **No cambia entre reintentos**, así que úsalo para detectar duplicados.                            |
| `eventTimestamp` | string | Cuándo Pulsar encoló el evento, como marca de tiempo UTC ISO 8601. No es el momento en que ocurrió el cambio en Pulsar. |
| `eventType`      | string | El [tipo de evento](/es/webhooks/events), por ejemplo `MachineStopClassificationCreated`.                               |
| `event`          | object | Los datos del evento. Su forma depende de `eventType`; consulta [Eventos](/es/webhooks/events).                         |

## Responde con un 2XX, rápido [#respond-with-a-2xx-quickly]

Devuelve un estado `2XX` en cuanto hayas [verificado la firma](/es/webhooks/signatures). Pulsar solo lee el código de estado e ignora el cuerpo de la respuesta.

* Devuelve `200` si ya procesaste el evento.
* Devuelve `202` si lo encolaste para después.

Haz cualquier tarea lenta, como llamar a otros sistemas o trabajo pesado de base de datos, en un proceso en segundo plano después de responder. Una respuesta que tarda más de 10 segundos cuenta como fallo y se reintenta, aunque tu código termine después.

## Reintentos [#retries]

Lo que hace Pulsar con una entrega fallida depende de por qué falló:

| Tu endpoint...                                                              | Pulsar...                                                                                                                                                       |
| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Devuelve `2XX`                                                              | Marca la entrega como completada.                                                                                                                               |
| Excede el tiempo de espera, no es accesible o devuelve `408`, `429` o `5XX` | Hace hasta 3 intentos seguidos, con backoff exponencial, respetando un encabezado `Retry-After` corto. Si los 3 fallan, vuelve a intentar la entrega más tarde. |
| Devuelve cualquier otro `4XX` o una redirección `3XX`                       | **No reintenta.** La entrega queda registrada como fallida, y Pulsar puede volver a enviarla cuando tu endpoint esté corregido.                                 |

<Callout type="warn" title="Una respuesta 4XX detiene los reintentos">
  Pulsar interpreta `400`, `401`, `403`, `404` y la mayoría de los demás códigos `4XX` como un rechazo deliberado del evento por parte de tu endpoint, así que no los reintenta. Si un error en tu handler devuelve un `4XX` para eventos válidos, esos eventos esperan hasta que Pulsar los vuelva a enviar. Usa `5XX` para problemas temporales de tu lado.
</Callout>

Un endpoint que falla no retrasa las entregas a tus demás endpoints.

## Duplicados y orden [#duplicates-and-ordering]

La entrega es **al menos una vez**. En ocasiones el mismo evento llega a tu endpoint más de una vez, por ejemplo cuando tu endpoint procesó una solicitud pero Pulsar no registró la respuesta a tiempo. Un evento reintentado también llega después que los eventos que se entregaron al primer intento, así que el orden no está garantizado.

Haz que tu handler se pueda ejecutar dos veces sin problema: guarda cada `eventId` que proceses y omite los que ya hayas visto. Un reintento o un reenvío siempre lleva el `eventId` original.

## Eventos Ping [#ping-events]

Un ping prueba tu endpoint sin esperar a un evento real. Usa los mismos encabezados y la misma firma que cualquier otra notificación, tiene `eventType` igual a `Ping` y su `event` siempre es `{ "text": "ping" }`:

```json
{
  "eventId": "0b6f3d2a-9c1e-4a7b-8f5d-2e4c6a8b0d1f",
  "eventTimestamp": "2026-09-25T14:00:00.000Z",
  "eventType": "Ping",
  "event": {
    "text": "ping"
  }
}
```

Un ping puede llegar a un endpoint sin importar el tipo de evento para el que esté registrado, así que responde `2XX` a `Ping` en lugar de rechazar los tipos de evento que no esperabas.

## Siguientes pasos [#next-steps]

<Cards>
  <Card title="Verificar firmas" href="/es/webhooks/signatures" description="Comprueba que cada solicitud realmente viene de Pulsar." />

  <Card title="Eventos" href="/es/webhooks/events" description="Todos los tipos de evento y los campos que incluyen." />
</Cards>
