Saltar al contenido principal
Migo Docs

Merchant Generic Callback

El Merchant Generic Callback es la solicitud HTTP saliente que Migo envía a un endpoint del comercio cuando una transacción alcanza un estado terminal. Es el segundo contrato que tu backend implementa para integrar Payment Link: tu backend crea el link (vía POST /transactions o POST /transactions-hook) y luego recibe el resultado de la transacción en la URL que registras con Migo al momento de integrar.

Para la mayoría de integraciones Migo envía un payload JSON estándar documentado abajo. El despacho está dirigido por configuración por cliente, así que el método HTTP, URL, headers, body y timeout pueden personalizarse cuando es necesario; el payload estándar cubre el caso común y es lo que deberías diseñar como base de tu handler salvo que hayas acordado un shape personalizado con Migo.

Flujo propio de Payment Link

El Merchant Generic Callback es un flujo separado: es la notificación saliente del producto Payment Link. No firma el body con HMAC y no sigue semánticas de reintento estandarizadas. Léelo por su cuenta.

Cómo configurar tu callback

Hay dos formas de configurar el callback:

  • Configuración asistida por Migo. Envía la información a Migo vía ticket de soporte o tu contacto de integración para que Migo registre tu endpoint.
  • Configuración self-service. Si tu comercio tiene acceso habilitado a Client Config Management, puedes actualizar config.callback desde el flujo de Update Client Config.

Para la configuración asistida, envía:

  1. URL del endpoint. La URL de tu lado que recibirá las notificaciones POST (por ejemplo https://api.yourdomain.com/webhooks/transactions).
  2. Headers de seguridad (opcional). Cualquier header HTTP personalizado que Migo deba incluir para que puedas autenticar la solicitud — típicamente un x-api-key estático o un Authorization: Bearer <token>. Por defecto Migo no envía headers extra; debes proveerlos explícitamente si los necesitas.

Configuración self-service vía Client Config Management

Cuando el acceso está habilitado para tu comercio, el flujo de Update Client Config de Client Config Management (PUT /properties en esa superficie) puede persistir la configuración del callback en la estructura existente de Client Config. Envía callback dentro de config; si no envías callback, Update Client Config mantiene el comportamiento anterior y solo actualiza las propiedades que incluiste.

status define los estados transaccionales configurados para el callback. La aplicación efectiva del filtro depende del mecanismo de callback habilitado para el cliente. No lo pongas dentro de callback.data.status: se persiste como callback.status.

Ejemplo de request:

{
"client": "merchant-slug",
"source": "merchant-portal",
"config": {
"callback": {
"enabled": true,
"type": "generic",
"functionName": "generic",
"status": ["approved", "denied"],
"data": {
"url": "https://merchant.example.com/callback",
"method": "POST",
"headers": {
"x-api-key": "<merchant-secret>"
},
"data": {
"reference": "{{reference}}",
"uid": "{{uid}}",
"country": "{{country}}",
"currency": "{{currency}}",
"channel": "{{channel}}",
"status": "{{status}}",
"createdAt": "{{createdAt}}",
"amount": "{{total}}",
"externalId": "{{externalId}}"
},
"extraData": {
"source": "client-config"
}
}
}
}
}
CampoTipoRequeridoDescripción
config.callback.enabledbooleanHabilita la configuración de callback para el cliente.
config.callback.typestringTipo de callback configurado. Para este contrato usa generic.
config.callback.functionNamestringCondicionalNombre de función o mecanismo configurado para el callback. Para callback genérico puede usarse generic; otros mecanismos pueden requerir un valor acordado con Migo.
config.callback.statusarray de stringsEstados transaccionales configurados para el callback. Debe ser un array no vacío con estados soportados, por ejemplo approved y denied. Se persiste como callback.status.
config.callback.data.urlstringURL absoluta de tu receiver. Debe ser válida y no vacía.
config.callback.data.methodstringMétodo HTTP que Migo usará para llamar tu endpoint. Debe ser un método soportado por la configuración de callback.
config.callback.data.headersobjectHeaders que Migo enviará al receiver. Debe ser un objeto; usa placeholders o valores estáticos solo cuando estén acordados para tu integración.
config.callback.data.dataobjectTemplate del body que Migo resolverá contra la transacción antes de enviar el callback. Debe ser un objeto.
config.callback.data.extraDataobjectNoDatos adicionales de configuración para el mecanismo de callback.

Validaciones de configuración:

  • url debe ser una URL válida y no vacía.
  • method debe ser un método HTTP soportado.
  • headers debe ser un objeto.
  • data debe ser un objeto.
  • extraData es opcional.
  • status debe ser un array no vacío con estados soportados.
  • Si callback es inválido, la actualización no se persiste.
Headers sensibles

Los headers como Authorization, x-api-key, token, secret, password o apiKey pueden contener credenciales. No deben exponerse completos en logs, tickets, capturas o ejemplos compartidos; usa valores enmascarados o placeholders cuando los documentes.

Cuándo se dispara el callback

Migo emite el callback al final de la transacción, solo para estados terminales:

Origen del triggerEstados que disparan el callback
Flujos de pago (finalUpdate)approved, denied, refunded, reversed
Flujos de servicios / créditos (despacho directo)approved, denied

Puedes recibir el callback por cualquiera de los dos caminos dependiendo de qué flujo de Migo manejó la transacción. Tu handler no debe asumir una sola fuente; diseñalo para ser idempotente sobre (uid, status).

Payload estándar

Migo envía un POST con Content-Type: application/json a la URL que registraste. El body es:

{
"reference": "ORDER-98765",
"uid": "ak_D3b0ETlw3HwPmQ3MNK",
"country": "GT",
"currency": "GTQ",
"channel": "WhatsApp",
"status": "approved",
"amount": 150,
"externalId": "ext_auth_123",
"createdAt": "05/03/2026 07:22:32",
"transactionId": "txn_1029384756",
"paymentMethodType": "credit_card"
}
CampoTipoLargo máx.DescripciónEjemplo
referencestring100Referencia emitida por Migo para la transacción. Devuelta en la respuesta de POST /transactions; para POST /transactions-hook se entrega aquí.ORDER-98765
uidstring100Identificador único de la transacción emitido por Migo. Mismo valor que devuelve la llamada de creación de link.ak_D3b0ETlw3Hw...
countrystring2Código ISO 3166-1 alpha-2 del país donde se realizó la operación.GT
currencystring3Código de moneda ISO 4217.GTQ
channelstring100Canal o plataforma donde originó la transacción.WhatsApp
statusstring20Estado terminal de la transacción. Uno de approved, denied, reversed, refunded.approved
amountinteger12Monto total de la transacción en la unidad mínima de la moneda.150
externalIdstring100Código de autorización o identificador externo devuelto por el procesador de pago.ext_auth_123
createdAtstring19Marca temporal de cuándo se creó originalmente la transacción, formato DD/MM/YYYY HH:MM:SS.05/03/2026 07:22:32
transactionIdstring100Id interno de la transacción que usa el procesador.txn_1029384756
paymentMethodTypestring100Tipo de método de pago usado para la transacción (por ejemplo credit_card, bank_transfer).credit_card

Autenticando la solicitud en tu lado

El Merchant Generic Callback no firma el body con HMAC. La autenticidad se delega al comercio mediante los headers que registraste con Migo — típicamente un API key estático en Authorization o un header personalizado (por ejemplo x-api-key).

Verifica el header en tu handler antes de procesar el body. Si necesitas garantías más fuertes (HMAC, JWT firmado, mTLS), coordínalo con Migo para extender la configuración de tu cliente; no es parte del contrato estándar.

Esqueleto de receiver (Node.js / Express)

import express from 'express';

const app = express();
const MIGO_API_KEY = process.env.MIGO_WEBHOOK_API_KEY;

app.post(
'/webhooks/transactions',
express.json({ limit: '1mb' }),
async (req, res) => {
// 1. Authenticate the request via the header you registered with Migo.
if (req.header('x-api-key') !== MIGO_API_KEY) {
return res.status(401).send('invalid credentials');
}

const { uid, status, reference, amount, currency } = req.body;

// 2. Idempotency: dedupe on (uid, status). Migo may deliver the same
// notification more than once if a queued message is replayed.
if (await alreadyProcessed(uid, status)) {
return res.status(200).json({ ack: 'duplicate' });
}

// 3. Process based on req.body.status:
// - "approved" -> mark order as paid, fulfill, etc.
// - "denied" -> mark order as failed, notify the customer.
// - "refunded" -> reverse fulfillment, update accounting.
// - "reversed" -> idem.
await processCallback(req.body);

// 4. Respond 2xx so Migo records a successful delivery.
res.status(200).json({ ack: 'received' });
},
);

Recomendaciones:

  • Responde siempre 2xx una vez tu procesamiento sea durable; fallar la respuesta hace que Migo registre un error de entrega.
  • Haz tu handler idempotente sobre (uid, status). Trata las entregas repetidas como un caso normal.
  • Valida el schema contra el payload estándar de arriba; extiéndelo solo si tienes acordado un payload personalizado con Migo.
  • Mantén el procesamiento rápido o muévelo a una cola dentro de tu sistema. Migo aplica un timeout por defecto de 25 segundos.

Comportamiento ante error

Migo registra los fallos de entrega y persiste los pasos request / response para que el operador pueda reprocesar manualmente si es necesario. Las semánticas de reintento dependen del camino de despacho que Migo seleccionó para tu cliente (algunos flujos pasan la solicitud a un mecanismo de despacho interno con su propia política de reintentos; otros hacen una sola llamada directa). Trata cada entrega como best-effort y apóyate en la idempotencia de tu lado.

Avanzado: templates de payload personalizado

La mayoría de los comercios no necesita esta sección. Documenta la configuración por cliente que dirige el despacho y permite personalizar la solicitud cuando el payload estándar no es suficiente.

El callback se configura por cliente en el documento ClientConfig.callback. El shape es:

interface GenericCallback {
// HTTP method Migo uses to call your endpoint. Typically "POST".
method: string;

// Merchant endpoint URL. Supports template placeholders resolved with
// transaction values via getValues().
url: string;

// Optional template headers. Each value can include placeholders resolved
// with transaction values via getDataCallback().
headers?: { [key: string]: string };

// Optional template body. Recursively resolved with transaction values
// via getDataCallback().
data?: { [key: string]: any };

// Optional extra configuration for the callback mechanism.
extraData?: { [key: string]: any };

// Optional timeout in milliseconds. Defaults to 25000.
timeout?: number;
}

El wrapper que vive en la configuración de cliente añade estos campos:

CampoTipoDescripción
enabledbooleanDebe ser true para que el callback se dispare.
typestringUno de "generic", "queue", "lambda". Selecciona el mecanismo de despacho — ver Variantes de type.
functionNamestringRequerido cuando type es "lambda". Nombre de la función que Migo invoca para entregar el callback. El literal %env% se reemplaza por el ambiente de despliegue.
statusstring[]Estados transaccionales configurados para el callback. La aplicación efectiva del filtro depende del mecanismo de callback habilitado para el cliente.
notifyExpirationbooleanOpcional. Controla si las transacciones expiradas también notifican; el comportamiento depende del servicio originario.
dataobjectEl payload GenericCallback de arriba (method, url, headers, body, timeout).

Variantes de type

typeImplementaciónMecanismo
"generic"V1Migo entrega la solicitud del callback a un mecanismo de despacho interno que hace la llamada HTTP a tu endpoint.
"queue"V1Mismo camino de despacho que "generic" — usa el mecanismo de despacho interno.
"lambda"V1Migo invoca una función nombrada específica (functionName) responsable de entregar el callback a tu endpoint. Úsalo solo si acordaste con Migo una función de despacho personalizada.
(sin campo type)V2Migo llama tu endpoint directamente con un solo request axios desde el servicio originario.

Para el comercio, el request que aterriza en tu endpoint se ve igual en V1 (generic / queue) y V2: la URL, método, headers y body resueltos desde tu configuración. Las diferencias son operativas (cola, reintentos, manejo de errores — ver Comportamiento ante error).

Reglas de templating

Los valores de configuración son templates. Migo sustituye placeholders contra el objeto transaction antes de enviar la solicitud.

  • getValues(template, transaction) se aplica al campo url. Sustituye placeholders como {{uid}}, {{reference}}, {{status}} con sus valores en la transacción.
  • getDataCallback(template, transaction) se aplica a headers y data (el body). Recorre el objeto recursivamente y sustituye placeholders dentro de cada valor string.

Los placeholders disponibles en runtime corresponden a campos del objeto transaction que Migo persiste para el pago, incluyendo (no exhaustivo): uid, reference, status, total, currency, customKeys, userId, clientCode, y los timestamps emitidos por Migo. Solo los campos que existen en la transacción se sustituyen; los faltantes se dejan como el placeholder literal, así que diseña tus templates alrededor de los campos que acordaste con Migo.

Ejemplo de configuración

{
"enabled": true,
"type": "generic",
"functionName": "generic",
"status": ["approved", "denied"],
"data": {
"method": "POST",
"url": "https://api.merchant.com/migo/callback?trx={{uid}}",
"headers": {
"Authorization": "Bearer <merchant-static-api-key>",
"Content-Type": "application/json"
},
"data": {
"transactionUid": "{{uid}}",
"reference": "{{reference}}",
"status": "{{status}}",
"amount": "{{total}}",
"currency": "{{currency}}",
"metadata": "{{customKeys}}"
},
"extraData": {
"source": "client-config"
},
"timeout": 30000
}
}

Cuando una transacción con uid = "abcd1234efgh" alcanza approved, Migo envía un POST a https://api.merchant.com/migo/callback?trx=abcd1234efgh con el header Authorization de arriba y un body JSON donde cada placeholder se resuelve contra la transacción.

Detalles de despacho

Origen del triggerMecanismo
Flujos de pago (V1)Migo entrega la solicitud a un mecanismo de despacho interno con su propia política de reintentos a nivel de infraestructura.
Flujos de servicios / créditos (V2)Migo hace una sola llamada directa desde el servicio originario. Ante error HTTP o timeout, el fallo se registra y la solicitud / respuesta se persisten como pasos de la transacción; no hay reintento dentro del proceso.

Las semánticas exactas de reintento son operativas y pueden evolucionar. Coordina con Migo si tu negocio requiere garantías de entrega específicas.

Relacionado