Crear un Payment Link
Un Payment Link es una URL de webview hospedado que permite a un comercio Migo cobrar un pago a un cliente final sin escribir código de pagos en el front-end. Tu backend crea el link llamando a Migo, y tú entregas la URL resultante al cliente a través de cualquier canal que operes (WhatsApp, SMS, email, mensaje in-app, código QR, etc.).
Tu única llamada a la API es crear la transacción. Después, el cliente completa todo el pago dentro del webview hospedado de Migo — ingresando la tarjeta, eligiendo cuotas, pasando 3D Secure — y Migo reporta el resultado de vuelta a tu backend mediante un webhook. Nunca recolectas datos de tarjeta ni llamas tú mismo a un endpoint de "cobro".
Ciclo de vida del Payment Link
┌─ tu backend ────────────────┐
│ 1. POST /transactions │ ───────────► Migo
│ (crea el link) │
│ │ ◄─────────── 2. { uid, reference, URL }
└─────────────────────────────┘
│
│ 3. entrega la URL al cliente
│ (WhatsApp · SMS · email · QR · in-app)
▼
┌─ cliente (webview hospedado) ───────────────────────┐
│ 4. abre la URL y paga dentro del webview de Migo: │
│ ingresa tarjeta · elige cuotas · 3D Secure │
│ (aquí no ocurren llamadas a la API del integrador)│
└──────────────────────────────────────────────────────┘
│
│ 5. Migo alcanza un estado terminal
▼
┌─ tu backend ────────────────┐
│ 6. recibe el resultado │ ◄─────────── webhook (Merchant Generic Callback)
│ approved / denied / … │ { uid, reference, status, … }
└─────────────────────────────┘
Los pasos 1–3 y 6 son tuyos; los pasos 4–5 ocurren íntegramente dentro de Migo. El resto de esta página detalla el paso 1 (las dos formas de crear el link) y te dirige al webhook para el paso 6.
Cómo elegir el endpoint
Migo expone dos endpoints que producen un Payment Link. Ambos llegan al mismo webview hospedado y solo difieren en cómo se autentica la solicitud:
POST /transactions(principal, recomendado) — backend-a-backend con un merchant token del lado servidor. Retorna lareferencelegible.POST /transactions-hook(alternativa) — amigable al navegador, autenticado con un parpublicKey+privateKeyen el cuerpo. No retornareference.
Si controlas un backend, usa POST /transactions. Si no tienes ningún servidor (SPA estática), usa POST /transactions-hook. Para el árbol de decisión completo, la comparación lado a lado y cómo combinar ambos, consulta Elige tu flujo.
El resultado del pago se entrega después a tu backend mediante el Merchant Generic Callback.
Principal: POST /transactions
Este es el endpoint recomendado para integraciones backend-a-backend.
Endpoint
POST https://sb-mw.migopayments.com/transactions (Sandbox)
POST https://mw.migopayments.com/transactions (Producción)
Content type: application/json. Envía el merchant token que Migo emitió para tu aplicación como el valor del header Authorization. Se recomienda el token crudo (sin prefijo de esquema); un Bearer inicial se tolera y se elimina:
Authorization: b6a615d8...0ba65c1 ✅ recomendado (token crudo)
Authorization: Bearer b6a615d8... ✅ aceptado (el prefijo "Bearer " se elimina)
Para las reglas canónicas sobre formato del token y convenciones de header, consulta Autenticación.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
amount | integer | sí | Subtotal de la transacción en la unidad mínima de la moneda permitida por tu configuración de cliente. Debe estar dentro del rango min/max configurado para tu cliente. |
userId | string | sí | Identificador del cliente final en tu dominio (número de teléfono, email o tu id interno). |
channel | string | sí | Canal de comunicación por el que pretendes entregar el Payment Link al cliente final (por ejemplo wa, app, sms, email, web). |
client | string | sí | Slug de tu cliente como está registrado en la configuración de Migo. |
ads | array | no | Array reservado, envía [] si no se usa. |
/transactions-hookPOST /transactions y POST /transactions-hook son consumidos por el mismo constructor de transacciones, así que los campos opcionales documentados para /transactions-hook más abajo — currency, externalId, customKeys, processorAmount, customerId, subscriptionData, createdBy — son igualmente aceptados por POST /transactions. Por lo tanto, los ejemplos de cURL y SDK que envían currency/externalId también son válidos contra este endpoint.
Valores permitidos para channel, userId, currency
Estos tres campos se validan contra tu configuración de cliente. Los valores que puedes usar dependen de lo que esté habilitado para tu slug client específico:
| Campo | Valores comunes | Cómo descubrir lo que acepta tu cliente |
|---|---|---|
channel | wa (WhatsApp), sms, email, web, app | Los canales se controlan por cliente. Si tu llamada retorna ownCode 5000 para channel, el valor no está habilitado — pide a tu contacto de Migo que lo habilite. |
userId | Teléfono E.164 (+50224865444), email o tu id interno | El formato es libre: Migo lo guarda tal cual. Elige el formato que puedas correlacionar con tus propios registros de usuario y mantente consistente. Para la entrega por SMS / WhatsApp, el campo debe ser un teléfono al que Migo pueda enviar. |
currency | ISO 4217 (GTQ, USD, MXN, CRC, HNL, DOP, COP, SVC) | Si se omite, Migo usa la primera moneda configurada para tu cliente. Si el valor no está en la lista configurada, se coerciona silenciosamente al valor por defecto — pásalo explícitamente cuando necesites estar seguro. |
Hoy no existe un endpoint público de "client config", por lo que los canales, monedas y procesadores habilitados no son auto-descubribles. Coordina con tu contacto de Migo para confirmar lo que acepta tu slug client, y trata una respuesta ownCode 5000/5004 como señal de que un valor no está habilitado.
Ejemplo cURL (Sandbox)
Reemplaza el token y el slug del cliente de marcador de posición con los valores que se te emitieron para Sandbox.
curl --location 'https://sb-mw.migopayments.com/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: <your-sandbox-token>' \
--data '{
"amount": 1,
"userId": "50224865444",
"channel": "wa",
"client": "<your-client-slug>",
"ads": []
}'
Respuesta exitosa
{
"uid": "Ypo5z2zTpLqWoe3eVvZMH",
"reference": "CAMPGT020007SB",
"URL": "https://sandbox.migopayments.com/?orderId=Ypo5z2zTpLqWoe3eVvZMH"
}
| Campo | Descripción |
|---|---|
uid | Identificador único de la transacción en Migo. Úsalo para correlacionar la transacción con el Merchant Generic Callback y con cualquier consulta a soporte. |
reference | Referencia legible que Migo deriva de tu configuración de cliente. Aparece en payloads de webhook, dashboards y operaciones de reembolso. |
URL | URL del webview hospedado que entregas al cliente final. El nombre del campo está en mayúsculas (URL, no url), exactamente como lo emite el handler — preserva ese casing al parsear la respuesta. |
URLLos snippets de TypeScript / JavaScript que usan const { url } = response obtendrán undefined silenciosamente. Siempre desestructura como const { URL: paymentLink } = response o lee el campo con notación de corchetes response.URL. Lo mismo aplica para /transactions-hook más abajo.
Alternativa: POST /transactions-hook
Usa esta variante en cualquiera de los siguientes casos:
- No quieres usar el endpoint autenticado por bearer token. Te autenticas con un par
privateKey+publicKeyenviado en el cuerpo, así que no tienes que emitir ni refrescar tokens. - Necesitas llamar desde un navegador sin problemas de CORS.
/transactions-hookestá configurado para aceptar solicitudes cross-origin, así que un front-end puede invocarlo directamente sin un proxy del lado servidor.
El webview hospedado producido por esta variante es idéntico al que produce /transactions. La única diferencia de comportamiento visible para el comercio es la forma de la respuesta (no se retorna reference).
Endpoint
POST https://sb-mw.migopayments.com/transactions-hook (Sandbox)
POST https://mw.migopayments.com/transactions-hook (Producción)
Content type: application/json. CORS está habilitado y la autenticación se realiza dentro del handler contra las credenciales del cuerpo, así que la solicitud no requiere un header Authorization.
La especificación OpenAPI lista esta operación bajo /mw-default/transactions-hook, pero el dominio personalizado en *.migopayments.com elimina el prefijo /mw-default/. La ruta pública que llamas es /transactions-hook (sin el segmento /mw-default/) — exactamente lo que usa el ejemplo de cURL a continuación.
Autenticación
Envía estos dos campos en el cuerpo JSON:
| Campo | Descripción |
|---|---|
privateKey | Credencial privada de tu aplicación Migo registrada. |
publicKey | Credencial pública de tu aplicación Migo registrada. |
Ambas credenciales se te emiten cuando se registra tu aplicación. Si no coinciden con una aplicación registrada, el endpoint responde con HTTP 401 y ownCode 2007.
Si llamas a este endpoint desde tu backend, trata privateKey como un secreto y nunca lo embebas en URLs. Si lo llamas desde un navegador, restringe cada par publicKey / privateKey al cliente y rango de monto específicos que necesitas, para acotar la exposición.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
amount | integer | sí | Subtotal de la transacción en la unidad mínima de la moneda permitida por tu configuración de cliente. Debe estar dentro del rango min/max configurado para tu cliente. |
userId | string | sí | Identificador del cliente final en tu dominio. |
channel | string | sí | Canal de comunicación por el que pretendes entregar el Payment Link al cliente final. |
client | string | sí | Slug de tu cliente como está registrado en la configuración de Migo. |
privateKey | string | sí | Credencial privada de tu aplicación registrada. |
publicKey | string | sí | Credencial pública de tu aplicación registrada. |
currency | string | no | Código de moneda ISO 4217 (por ejemplo GTQ, USD). Si se omite, o si no está en la lista de monedas permitidas para tu cliente, Migo usa la primera moneda configurada para el cliente. |
processorAmount | object | no | Mapa de nombre de procesador a monto override. Cada valor debe ser <= amount. |
customKeys | object | no | Datos arbitrarios definidos por el comercio, preservados verbatim en la transacción. Disponibles para los templates del webview y del Generic Callback. |
externalId | string | no | Identificador que usas en tu propio sistema para correlacionar la transacción de Migo con tu registro. |
createdBy | string | no | Identificador del operador que creó la transacción (usado por los dashboards de Migo). |
customerId | string | no | Identificador interno que asocia la transacción con un registro de cliente. Se almacena bajo additionalData.clientCode. |
subscriptionData | object | no | Metadata de suscripción anexada a additionalData.subscriptionInfo. |
Ejemplo cURL (Sandbox)
curl --location 'https://sb-mw.migopayments.com/transactions-hook' \
--header 'Content-Type: application/json' \
--data-raw '{
"privateKey": "<your-sandbox-private-key>",
"publicKey": "<your-sandbox-public-key>",
"amount": 1,
"userId": "50224865444",
"channel": "app",
"client": "<your-client-slug>",
"createdBy": "operator@example.com"
}'
Respuesta exitosa
{
"uid": "7JV3UKvc2XEretWV2Rb57",
"URL": "https://sandbox.migopayments.com/?orderId=7JV3UKvc2XEretWV2Rb57"
}
/transactions-hook retorna { uid, URL } — no hay campo reference. Si necesitas la referencia legible, usa POST /transactions en su lugar, o lee el valor del payload del Merchant Generic Callback una vez que la transacción alcance un estado terminal.
Qué hace el cliente a continuación
Una vez que entregas la URL, todo lo demás ocurre dentro del webview hospedado de Migo — no hay ninguna otra llamada a la API que debas hacer. Cuando el cliente abre el link, el webview resuelve automáticamente tu configuración de cliente y los procesadores habilitados y renderiza la UI de pago. Dentro de él, el cliente:
- ingresa los datos de su tarjeta en el formulario de pago,
- elige el número de cuotas (cuando el procesador lo soporta),
- pasa el reto de 3D Secure si el procesador lo requiere,
- y confirma el pago.
Migo tokeniza la tarjeta y cobra la transacción internamente como parte de ese flujo. Nunca recolectas datos de tarjeta, nunca tokenizas y nunca llamas tú mismo a un endpoint de cobro — esos son pasos internos del webview. Consulta Webview hospedado para ver cómo se comporta el checkout dentro del webview.
Recibir el resultado
Migo notifica a tu backend una vez que la transacción alcanza un estado terminal (approved, denied, refunded, reversed). El producto Payment Link entrega esto mediante el Merchant Generic Callback — un POST saliente de Migo hacia una URL que registras con soporte, que lleva { uid, reference, status, amount, currency, ... }.
| Mecanismo | Dirección | Cuándo |
|---|---|---|
| Merchant Generic Callback | Migo → tu backend | La transacción alcanza un estado terminal |
Usa el uid que recibiste en el paso 1 para correlacionar el callback con la transacción que creaste. El callback no se firma con HMAC — la autenticidad se delega a una API key/header estático que registras con Migo. Consulta Merchant Generic Callback → Autenticando la solicitud.
Errores
Ambos endpoints retornan un ErrorResponseDto de Migo. El campo más accionable es ownCode, que mapea a una entrada del catálogo de errores de Migo.
Los errores de Payment Link usan el espacio de ownCode del Middleware (enteros bajos como 2002, 2007, 5000, 5004). Son distintos de los códigos de error del Gateway/CMS (7000–8099) documentados en el Catálogo de errores. La lista completa de errores de Payment Link está reflejada al final de esa página para que puedas mapear cada código en un solo lugar.
| HTTP | ownCode | Causa | Qué hacer |
|---|---|---|---|
| 409 | 5000 | Faltan campos requeridos o el cuerpo es inválido | Verifica que amount, userId, channel, client (y privateKey / publicKey para /transactions-hook) estén presentes con los tipos correctos. |
| 401 | 2007 | Credenciales del cuerpo inválidas — solo /transactions-hook | Verifica el par privateKey / publicKey contra el registro de tu aplicación; asegúrate de usar credenciales de Sandbox contra Sandbox y de Producción contra Producción. |
| 401 | (ninguno) | Token inválido en POST /transactions | El token lo valida el authorizer personalizado del API Gateway, no el handler. En caso de fallo, el gateway retorna un 401 genérico con cuerpo { "message": "Unauthorized" } — no hay un ErrorResponseDto de Migo ni un ownCode. Verifica que el merchant token y el entorno Sandbox/Producción coincidan. |
| 409 | 5004 | Slug client no encontrado en la configuración de Migo | Confirma el slug; crea o activa la configuración de cliente en coordinación con Migo. |
| 409 | 2003 | amount fuera del rango min/max configurado para tu cuenta de comercio, o algún valor en processorAmount excede amount | Ajusta el monto, o actualiza los overrides por procesador para que cada uno sea <= amount. |
| 400 | 2006 | El cliente final está excluido para este comercio | Los usuarios excluidos no pueden transaccionar para este comercio. |
| 400 | 2004 | El cliente final está bloqueado para este comercio | Los usuarios bloqueados no pueden transaccionar para este comercio. |
| 400 | 2005 | El cliente final está suspendido para este comercio | Los usuarios suspendidos no pueden transaccionar mientras la suspensión esté activa. |
| 400 | 2002 | Error genérico de creación | Reintenta; si el error persiste, contacta a soporte de Migo con el uid (cuando esté disponible) y el payload de la solicitud. |
Siguientes pasos
- Entrega la
URLal cliente final a través del canal que elijas. - Implementa el Merchant Generic Callback para que tu backend reciba el resultado de la transacción (
approved/denied/refunded/reversed) una vez que el cliente complete el webview. - Para una integración en el navegador lista para copiar y pegar, sigue la receta de Payment Link en React. Para una lista de verificación de cada valor que necesitas en Sandbox, consulta el Cheat sheet de Sandbox.
- Para el resto del ciclo de vida del pago (reembolsos, capturas, comportamiento específico del procesador, 3DS), explora la referencia del Migo Middleware API y las secciones adicionales de este portal.