Skip to content

Registrar Webhook

Endpoints para crear, listar y remover webhooks de notificacion.


Crear Webhook

POST /api/external/webhooks

Headers

HeaderTipoObligatorioDescripcion
AuthorizationStringSiApiKey {client_id}:{client_secret}
Content-TypeStringSiapplication/json
hmacStringSiFirma HMAC-SHA512 del body (mas informacion)

Request Body

CampoTipoObligatorioDefaultDescripcion
urlStringSi--URL para recibir notificaciones (HTTPS por defecto)
eventsArraySi--Lista de eventos a suscribir. Debe ser un array no-vacio con al menos un evento valido de la tabla abajo. Omitir el campo retorna 400 {"errors": {"events": ["can't be blank"]}}.
secretStringNoauto-generadoClave para firma HMAC-SHA256 de las entregas. Si se omite, un valor aleatorio es generado automaticamente.
descriptionStringNonullDescripcion libre del webhook para identificacion interna
allow_insecureBooleanNofalsePermite URLs HTTP (no-HTTPS). La seguridad de los datos es responsabilidad del cliente.

Eventos disponibles (solo PIX — otros productos no estan en alcance en Owem hoy):

EventoStatus bodyDescripcionDisparo
pix.charge.createdcreatedQR code generado o cash-in iniciadoActivo
pix.charge.paidpaidPIX recibido y liquidadoActivo
pix.charge.expiredexpiredQR code expiro sin pago (worker cada 5 min)Activo
pix.charge.cancelledcancelledQR code cancelado antes del pagoRegistrado, aun no disparado
pix.payout.queuedqueuedPIX enviado encolado por rate limit (ClientLimiter por merchant O bucket DICT BACEN)Activo
pix.payout.processingprocessingPIX enviado, aguardando confirmacionActivo
pix.payout.confirmedsettledPIX enviado y confirmado (terminal)Activo
pix.payout.failedrejectedPIX enviado rechazado (terminal)Activo
pix.payout.returnedreturnedPIX enviado devueltoActivo
pix.refund.requestedrequestedSolicitud de devolucion recibida (infraccion BACEN); bloqueo cautelar creado en el saldo del clienteActivo
pix.refund.completedsettled / completedAnalisis de la defensa finalizado y devolucion ejecutada (o liberada)Activo
pix.return.receivedsettledDevolucion PIX recibida (credito)Activo
pix.infraction.createdACKNOWLEDGEDInfraccion PIX reportada por la contraparte via BACEN DICTActivo
pix.infraction.resolvedCLOSED / CANCELLEDInfraccion resuelta (admin close, auto-deny o contraparte cancelo)Activo
pix.infraction.defense_submitteddefense_submittedDefensa enviada por el merchantActivo
webhook.testtestPrueba manual. Disponible solo via portal Admin/Merchant — no hay endpoint External API para dispararDisparo manual

pix.charge.cancelled aun no es disparado

El evento esta en el enum de suscripciones validas, pero ningun codigo en produccion dispara notificaciones de ese tipo hoy (flujo de cancelacion de QR code no implementado). Usted puede incluirlo en el array events — la API acepta — pero ninguna notificacion llegara a su endpoint hasta que el flujo sea implementado.

Cualquier evento fuera de esa tabla es rechazado

Al crear un webhook, validate_events en el backend verifica cada item contra el enum @valid_events (schema Fluxiq.Schemas.Webhooks.Webhook). Eventos desconocidos (boleto.paid, account.created, sta.file.*, etc.) retornan 400 con error events: contains invalid events: .... Antes de la sesion 163 esos nombres estaban en el enum como aspiracional — fueron removidos porque no habia dispatchers en codigo.

Payloads de cada evento

Ejemplos de payload completos para cada evento estan en Payloads de los Webhooks.

Ejemplo

bash
BODY='{"url":"https://seusite.com.br/webhook","events":["pix.charge.paid","pix.payout.confirmed"]}'
HMAC=$(echo -n "$BODY" | openssl dgst -sha512 -hmac "$CLIENT_SECRET" | awk '{print $2}')

curl -X POST https://api.owem.com.br/api/external/webhooks \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "hmac: $HMAC" \
  -d "$BODY"

Respuesta de Exito (201)

json
{
  "worked": true,
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "https://seusite.com.br/webhook",
  "events": ["pix.charge.paid", "pix.payout.confirmed"],
  "secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "description": null,
  "is_active": true,
  "created_at": "2026-03-07T15:30:00Z"
}

Formato del id

El id del webhook es un UUID v4 canonico (36 caracteres con guiones). Use ese valor directo en DELETE /api/external/webhooks/:id.

Respuesta de Error (422)

json
{
  "worked": false,
  "detail": "URL deve utilizar HTTPS"
}

Solo HTTPS por Default

La URL del webhook debe usar HTTPS. URLs con HTTP seran rechazadas, a menos que allow_insecure: true sea enviado en el registro.

Importante — Secret del Webhook

El campo secret retornado en la respuesta del registro es la clave usada para firmar las entregas del webhook (HMAC-SHA256). Almacene ese valor con seguridad tan pronto lo reciba — es el que valida que una notificacion vino realmente de Owem Pay.

NO confunda con client_secret:

  • client_secret = autenticacion de sus solicitudes a la API (header Authorization)
  • secret del webhook = verificacion de la firma de las entregas recibidas (header X-Owem-Signature)

Si usted no envia el campo secret en el registro, un valor aleatorio sera generado automaticamente y retornado en la respuesta.

Vea Validacion de Webhooks para ejemplos de como verificar la firma.

Recuperando el secret despues

El secret es retornado tanto en POST /api/external/webhooks (creacion) como en GET /api/external/webhooks y GET /api/external/webhooks/:id (consulta). Si usted perdio el valor, basta consultar el webhook nuevamente via GET.

En una futura version este comportamiento puede ser restringido (exhibir solo en la creacion); recomendamos almacenar el secret en un secreto gestionado (vault, SSM, etc.) en el momento del registro.

URLs HTTP

Por defecto, los webhooks exigen HTTPS para garantizar la seguridad de los datos en transito. Para utilizar HTTP, envie allow_insecure: true en el registro del webhook.

Atencion

URLs HTTP transmiten datos sin cifrado. La seguridad y el secreto de las informaciones transitadas quedan bajo entera responsabilidad del cliente. Owem Pay realiza la entrega del webhook normalmente, pero no se responsabiliza por interceptacion o fuga de datos en conexiones no cifradas.

URLs privadas son siempre bloqueadas

Incluso con allow_insecure: true, URLs apuntando para direcciones privadas/internas son rechazadas:

  • localhost / 127.x.x.x
  • RFC1918: 10.x.x.x, 192.168.x.x, 172.16-31.x.x
  • TLDs internos: .local, .internal

Webhooks deben apuntar para URLs publicas accesibles por internet.


Listar Webhooks

GET /api/external/webhooks

Headers

HeaderTipoObligatorioDescripcion
AuthorizationStringSiApiKey {client_id}:{client_secret}

Ejemplo

bash
curl -X GET https://api.owem.com.br/api/external/webhooks \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"

Respuesta de Exito (200)

Retorna un array de objetos (no envuelto en {"worked": true}). Cada item contiene los mismos campos del registro, incluyendo secret.

json
[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "url": "https://seusite.com.br/webhook",
    "events": ["pix.charge.paid", "pix.payout.confirmed"],
    "description": null,
    "account_id": 10014,
    "is_active": true,
    "allow_insecure": false,
    "status": "active",
    "secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
    "created_at": "2026-03-07T15:30:00",
    "updated_at": "2026-03-07T15:30:00"
  }
]
CampoTipoDescripcion
idstring (UUID)Identificador del webhook
urlstringURL de destino
eventsarrayEventos suscritos
descriptionstring o nullDescripcion opcional
account_idinteger o nullCuenta asociada. null = webhook global para la API key (si soportado)
is_activebooleanfalse = webhook pausado, ninguna delivery es disparada
allow_insecurebooleantrue = URLs HTTP aceptadas
statusstringDerivado de is_active"active" o "inactive"
secretstringClave HMAC-SHA256 usada para firmar entregas. Retornada en el LIST para permitir recuperacion caso el cliente haya perdido el valor original
created_at / updated_atstring ISO 8601Timestamps en UTC, formato NaiveDateTime (sin sufijo Z, ej: "2026-03-07T15:30:00"). Diferente de otros campos de fecha en payloads de webhook (paid_at, returned_at, expired_at) que usan DateTime ISO 8601 con Z final. Siempre asuma UTC para los campos del webhook object

Remover Webhook

DELETE /api/external/webhooks/:id

Headers

HeaderTipoObligatorioDescripcion
AuthorizationStringSiApiKey {client_id}:{client_secret}

Path Parameters

ParametroTipoObligatorioDescripcion
idString (UUID)SiID del webhook (UUID v4 retornado por el endpoint de creacion)

Ejemplo

bash
curl -X DELETE https://api.owem.com.br/api/external/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"

Respuesta de Exito (204)

HTTP 204 No Content — body vacio. El webhook fue removido con exito; ninguna delivery pendiente sera disparada.

Primera llamada: 204. Subsecuentes: 404

La primera llamada exitosa retorna 204 No Content. Llamadas subsecuentes con el mismo id retornan 404 { "errors": { "not_found": "webhook not found" } } — el webhook ya fue removido. Esto no es idempotencia estricta HTTP (en que toda llamada retornaria 204) — es el comportamiento estandar de DELETE cuando el recurso deja de existir. Escriba su integracion para aceptar tanto 204 como 404 como "el webhook no esta mas activo".

Respuesta de Error (400)

Formato de id invalido (no es UUID):

json
{
  "errors": {
    "bad_request": "id must be a valid UUID"
  }
}

Respuesta de Error (404)

Webhook no existe o no pertenece a su cuenta:

json
{
  "errors": {
    "not_found": "webhook not found"
  }
}

Owem Pay Instituição de Pagamento — ISPB 37839059