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

# Webhooks de servicios públicos

> Recibe el resultado de los pagos de servicios públicos que hace tu empresa: aprobados (utility.paid) y rechazados (utility.rejected).

[Realizar pago](/client/utilities/payment) responde de inmediato con `status: "pending"`: el convenio
confirma el pago después. Estos webhooks te avisan el resultado final para que no tengas que consultar
el pago una y otra vez.

## Eventos disponibles

| Evento | Cuándo se envía |
| - | - |
| `utility.paid` | El convenio confirmó el pago. Aplica a los pagos que tu empresa hace con su saldo, por API ([Realizar pago](/client/utilities/payment)) o desde el panel (pago en lote), y también si el pago se aprueba tras una conciliación manual. |
| `utility.rejected` | El pago ya no se va a lograr: la factura venció o el convenio no lo aceptó después de nuestros reintentos. El motivo llega en `remarks`. |

<Warning>
  Estos eventos solo se envían a webhooks de **producción**. Un webhook creado en modo prueba no los
  recibe, y `event.environment` siempre llega `live`. Para recibirlos, suscribe un webhook de
  producción a `utility.paid` y `utility.rejected` ([Crear webhook](/client/webhooks/create)).
</Warning>

## Estructura del payload

Los dos eventos llegan como un `POST` con `Content-Type: application/json` y este cuerpo:

```json theme={null}
{
  "utility": { ... },
  "event": {
    "type": "utility.paid",
    "timestamp": 1760630400,
    "environment": "live",
    "company_id": "f1e2d3c4-b5a6-9788-7654-321fedcba098"
  }
}
```

## Objeto `utility`

<ResponseField name="id" type="string (UUID)" required>
  Identificador del pago. Si lo creaste por API, es el mismo `id` que te devolvió [Realizar
  pago](/client/utilities/payment). Úsalo para deduplicar: un mismo evento puede llegarte más de una
  vez (ver [Entrega y reintentos](/client/webhooks/index#entrega-y-reintentos)).
</ResponseField>

<ResponseField name="group_id" type="string (UUID) | null">
  Lote al que pertenece el pago. Por API, OnePay agrupa en un lote los pagos de cada día; desde el
  panel es el lote que creaste. **No es el mismo valor que `group_id` en la respuesta de [Realizar
  pago](/client/utilities/payment)**, que trae el nombre del convenio y la referencia: para
  relacionar el webhook con tu solicitud usa `id` o `external_id`.
</ResponseField>

<ResponseField name="provider_id" type="string (UUID)" required>
  Convenio pagado. Es el `provider_id` que enviaste al pagar, el mismo de [Consultar
  convenios](/client/utilities/providers).
</ResponseField>

<ResponseField name="provider_name" type="string" required>
  Nombre del convenio.
</ResponseField>

<ResponseField name="amount" type="number" required>
  Monto pagado, en pesos colombianos y no en centavos: `250000` son \$250.000. Si el monto tiene
  centavos, llega con decimales (`12345.67`).
</ResponseField>

<ResponseField name="reference" type="string" required>
  Referencia de pago del convenio: la que enviaste en `reference`, sin guiones.
</ResponseField>

<ResponseField name="external_id" type="string | null" required>
  Tu propio identificador, si lo enviaste al [realizar el pago](/client/utilities/payment). Llega
  `null` si no lo enviaste, y siempre en los pagos en lote desde el panel.
</ResponseField>

<ResponseField name="status" type="string" required>
  `paid` en `utility.paid` y `rejected` en `utility.rejected`.
</ResponseField>

<ResponseField name="remarks" type="string | null">
  Solo en `utility.rejected`: motivo del rechazo, por ejemplo `La deuda actual es diferente.`
</ResponseField>

<Note>
  El webhook no trae la fecha del pago. Si la necesitas y creaste el pago por API, [consulta el
  pago](/client/utilities/view): la respuesta incluye `paid_at`.
</Note>

## Objeto `event`

<ResponseField name="type" type="string" required>
  Nombre del evento: `utility.paid` o `utility.rejected`. También llega en el header
  `x-webhook-event`.
</ResponseField>

<ResponseField name="timestamp" type="integer" required>
  Momento en que OnePay generó el evento, en segundos Unix (UTC).
</ResponseField>

<ResponseField name="environment" type="string" required>
  Siempre `live` en estos eventos.
</ResponseField>

<ResponseField name="company_id" type="string (UUID)" required>
  Empresa dueña del pago.
</ResponseField>

## Cómo validar que viene de OnePay

Cada entrega trae los headers `x-webhook-token` (el token estático de tu webhook), `x-webhook-event`
(`utility.paid` o `utility.rejected`) y, si tu webhook tiene un `secret`, `Signature`: el HMAC-SHA256 en
hexadecimal del cuerpo crudo. El código para verificarlos está en
[Autenticación de los eventos](/client/webhooks/index#autenticación-de-los-eventos).

Responde con un `2xx` en menos de 10 segundos; si no, OnePay reintenta la entrega
([Entrega y reintentos](/client/webhooks/index#entrega-y-reintentos)). Un `3xx` no cuenta como éxito
por sí solo: OnePay sigue la redirección y lo que vale es la respuesta final.

## Ejemplo `utility.paid`

```json theme={null}
{
  "utility": {
    "id": "9d1cd37a-a6bc-472d-b4e6-c913769d005a",
    "group_id": "9d1cd37a-8f21-4d9c-9c7e-0b3a1f5c2d44",
    "provider_id": "9d1cd37a-94e5-4cf1-aa7c-daac8ebf4ed9",
    "provider_name": "Kirlin Group",
    "amount": 250000,
    "reference": "2381762387",
    "external_id": "FACT-2026-00123",
    "status": "paid"
  },
  "event": {
    "type": "utility.paid",
    "timestamp": 1760630400,
    "environment": "live",
    "company_id": "f1e2d3c4-b5a6-9788-7654-321fedcba098"
  }
}
```

## Ejemplo `utility.rejected`

```json theme={null}
{
  "utility": {
    "id": "9d1cd37a-a6bc-472d-b4e6-c913769d005a",
    "group_id": "9d1cd37a-8f21-4d9c-9c7e-0b3a1f5c2d44",
    "provider_id": "9d1cd37a-94e5-4cf1-aa7c-daac8ebf4ed9",
    "provider_name": "Kirlin Group",
    "amount": 250000,
    "reference": "2381762387",
    "external_id": "FACT-2026-00123",
    "status": "rejected",
    "remarks": "La deuda actual es diferente."
  },
  "event": {
    "type": "utility.rejected",
    "timestamp": 1760630400,
    "environment": "live",
    "company_id": "f1e2d3c4-b5a6-9788-7654-321fedcba098"
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.