Skip to content

Webhooks -- Vision General

Los webhooks permiten que su aplicacion reciba notificaciones en tiempo real sobre eventos en la plataforma Minha Konta. Cuando ocurre un evento, Minha Konta envia un HTTP POST a la URL registrada.

Como Funciona

  1. Registre una URL de webhook en su cuenta
  2. Cuando ocurra un evento (ej: PIX recibido), Minha Konta envia un HTTP POST a su URL
  3. Su aplicacion procesa la notificacion y responde con estado 2xx (200, 201 o 204)

Eventos Disponibles

Minha Konta entrega eventos de PIX, TEF entre cuentas Minha Konta y prueba operacional de webhook. Otros productos (boleto, cuentas y STA) no estan en alcance. Cualquier intento de suscribir eventos fuera de la tabla abajo es rechazado con events: contains invalid events: ....

EventoStatus bodyDescripcionDisparo
pix.charge.createdcreatedQR code generado o cash-in iniciadoActivo
pix.charge.paidpaidPIX recibido y liquidadoActivo
pix.charge.expiredexpiredQR code expiro sin pagoActivo
pix.charge.cancelledcancelledQR code cancelado antes del pagoRegistrado, aun no disparado
pix.payout.queuedqueuedPIX enviado encolado por limite operacional. Retry automatico con TTL maximo de 2hActivo
pix.payout.processingprocessingPIX enviado, aguardando confirmacion BACENActivo
pix.payout.heldprocessingPIX enviado retenido para analisis en el agente de liquidacion (autorizacion/anti-fraude). Liquida o rechaza despues — no reenviarActivo
pix.payout.confirmedsettledPIX enviado y confirmado (terminal)Activo
pix.payout.failedrejectedPIX enviado rechazado por el SPI (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 DICT; puede exigir analisis y defensa MEDActivo
pix.infraction.resolvedCLOSED / CANCELLEDInfraccion resuelta por decision final o cancelacion de la contraparteActivo
pix.infraction.defense_submitteddefense_submittedDefensa enviada por el merchant (portal o API); aguarda analisis BACENActivo
tef.transfer.sentsettledTEF entre cuentas Minha Konta liquidada para la cuenta de origenActivo
tef.transfer.receivedsettledTEF entre cuentas Minha Konta liquidada para la cuenta de destinoActivo
tef.transfer.failedfailedTEF entre cuentas Minha Konta rechazada o no liquidadaActivo
webhook.testtestPrueba manual. Disponible solo via Admin/Merchant portal - la External API no expone endpoint para disparar pruebaDisparo manual (no External API)

pix.charge.cancelled aun no es disparado

El evento esta en el enum y puede ser suscrito, pero el sistema no posee flujo de cancelacion de QR code hoy. Si lo suscribe, el POST /webhooks responde 201 normalmente - pero ninguna notificacion llegara. Continue monitoreando pix.charge.expired para el ciclo natural de vida del QR.

Seguridad

Cada notificacion incluye headers de seguridad e identificacion para validacion:

HeaderDescripcion
X-Minha Konta-SignatureFirma HMAC-SHA256 del payload (prefijo sha256=). En casos raros (webhook registrado sin secret), el valor literal es unsigned - vea nota abajo
X-Minha Konta-TimestampUnix timestamp en segundos del envio
X-Minha Konta-Event-IdUUID unico de la delivery (para deduplicacion)
X-Minha Konta-Event-TypeTipo del evento (ej: pix.charge.paid)
Content-TypeSiempre application/json
User-AgentSiempre Minha Konta-Webhook/1.0 - use para whitelisting en firewalls/WAF

Signature unsigned cuando webhook no tiene secret

Si el webhook fue registrado sin campo secret en un registro legacy, el header X-Minha Konta-Signature puede venir como unsigned. Esto deshabilita la validacion HMAC de su lado. Si recibe unsigned, registre un nuevo webhook con secret explicito y remueva el antiguo.

SHA256 en webhooks vs SHA512 en la API

La API usa HMAC-SHA512 para autenticar solicitudes que usted envia. Los webhooks enviados por Minha Konta usan HMAC-SHA256 en la firma X-Minha Konta-Signature. Son algoritmos diferentes -- cada uno en su contexto.

Validando la Firma

Valide la firma para garantizar que la notificacion fue enviada por Minha Konta:

javascript
const crypto = require('crypto');

function validateWebhook(rawBody, timestamp, signature, secret) {
  // rawBody is the RAW request body string (before any JSON parse)
  // timestamp is unix seconds (e.g., 1712160000)
  const message = `${timestamp}.${rawBody}`;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

Use el body RAW, no re-serializado

Usted debe usar el cuerpo exacto de la solicitud HTTP como los bytes llegaron a su aplicacion. Si hace JSON.parse y despues JSON.stringify, los bytes resultantes no seran identicos a los que Minha Konta uso para firmar, y la validacion fallara.

En Express/Node: use express.raw({ type: 'application/json' }) o guarde el body antes de cualquier middleware de parse.

En otros frameworks: configure para capturar el raw body antes del middleware JSON.

Ordenacion de claves en WEBHOOKS: NO es necesaria

Para validacion de webhooks (HMAC-SHA256) usted NO necesita ordenar las claves - use el body raw como fue recibido en el HTTP request de Minha Konta.

⚠️ Atencion - diferencia vs envio de solicitudes: En la firma HMAC-SHA512 de SOLICITUDES que usted envia, la ordenacion alfabetica de las claves ES obligatoria (el servidor Minha Konta reordena antes de validar). No confunda los dos escenarios:

  • Webhook recibido (HMAC-SHA256): valide el body raw sin reordenar
  • Request enviada (HMAC-SHA512): ordene sus claves alfabeticamente antes de firmar

Valide siempre

Nunca procese un webhook sin validar la firma. Esto protege contra solicitudes falsificadas.

Adicionalmente, valide que el X-Minha Konta-Timestamp este dentro de ± 5 minutos de la hora actual (proteccion anti-replay) y deduplique eventos por X-Minha Konta-Event-Id (proteccion contra retries).

Retry Policy

Si su URL retorna un estado diferente de 2xx (o timeout despues de 30 s), Minha Konta realiza hasta 8 intentos con backoff exponencial. El tiempo total entre el primer y el octavo intento es aproximadamente 7h45min:

IntentoDelay desde intento anteriorTiempo acumulado
1o- (inmediato)~50-200 ms
2o30 segundos~30 s
3o2 minutos~2,5 min
4o10 minutos~12,5 min
5o30 minutos~42,5 min
6o1 hora~1,75 h
7o2 horas~3,75 h
8o4 horas~7,75 h

Despues de 8 intentos sin exito, el webhook_delivery es marcado con estado failed y no es reenviado automaticamente. Usted puede solicitar replay manual al soporte Minha Konta proporcionando el X-Minha Konta-Event-Id (o tener un operador con acceso admin replayar por el portal).

Estado de una delivery

Cada delivery pasa por los estados: pending (creada, aguardando entrega) → delivered (2xx recibido) O failed (8 intentos agotados) O expired (replay protection).

Sobre expired: cuando un intento de entrega queda demasiado antiguo antes del envio, puede ser descartado y marcado como expired. Esto impide que reprocesamientos tardios disparen notificaciones antiguas. Replays manuales solicitados al soporte Minha Konta siguen un flujo controlado y pueden reenviar el evento al cliente.

Durabilidad

Antes de intentar la primera entrega, el evento se persiste para retry. Si ocurre una falla durante la entrega, el sistema retoma automaticamente en el proximo retry - ningun evento es perdido.

Idempotencia

Su aplicacion debe ser idempotente: si recibe el mismo evento mas de una vez (identificado por el X-Minha Konta-Event-Id), debe procesarlo sin duplicar efectos.

Replay manual via admin

Si una delivery fallo y usted necesita re-enviar, el equipo Minha Konta puede ejecutar replay manual via admin dashboard. Contacte al soporte con el event_id de la delivery.

Entregas duplicadas (race condition conocida)

El sistema puede usar mas de un camino de entrega para acelerar la primera notificacion y mantener retry durable. En escenarios de alta concurrencia, puede recibir el mismo payload 2 veces via HTTP, pero con el mismo X-Minha Konta-Event-Id - es el mismo event, no un retry.

Para evitar impacto duplicado:

  • Dedupe por X-Minha Konta-Event-Id (recomendado - UUID unico por delivery, estable en retries y en la race condition arriba)
  • O alternativamente dedupe por end_to_end_id + event_type cuando tenga sentido para el evento

Esto es comportamiento esperado, no error. Retries legitimos (despues de 5xx/timeout) tambien reusan el mismo X-Minha Konta-Event-Id.

External ID en los Webhooks

Cuando una transaccion fue creada con external_id, ese campo se incluye en el payload del webhook dentro del objeto data. Uselo para correlacionar el evento con el pedido en su sistema sin necesidad de hacer una consulta adicional.

Requisitos del Endpoint

  • La URL debe usar HTTPS (a menos que allow_insecure: true en el registro)
  • Debe responder con estado 2xx en hasta 30 segundos
  • El body de la respuesta es ignorado
  • Recomendado responder rapido (200 OK inmediato) y procesar el evento de forma asincronica en su lado; delays largos reducen el throughput y aumentan chance de retries

Proximos Pasos

Minha Konta Instituição de Pagamento - ISPB 39929224