Saltar al contenido principal

Retiros en Moneda Extranjera (Pay Out)

Este módulo permite crear retiros (pay-out) en moneda local usando fondos de origen en moneda extranjera (por ejemplo, USDC → MXN).

Como Comercio, tu integración habla exclusivamente con Pago46. Pago46 gestiona internamente la cotización, el seguimiento de la recepción de fondos y la habilitación del retiro en efectivo.

Endpoint Base

Todas las rutas descritas a continuación son relativas a la URL base de la API: /api/v1

Flujo General

  1. Creas una cotización para un par de activos (POST /merchants/quotes/).
  2. Tu usuario acepta la cotización en tu aplicación.
  3. Creas una orden de retiro foreign asociada a esa cotización.
  4. Tu usuario envía los fondos al address indicado por Pago46.
  5. Si el fondeo llega dentro de la ventana válida, la orden avanza a READY y queda lista para continuar el flujo normal de retiro.

Nota: la generación y entrega de la transacción blockchain ocurre en segundo plano, nunca en la respuesta inmediata del POST. Siempre espera el webhook antes de continuar con la firma.


Requisitos Previos

  • Credenciales de Comercio (Merchant-Key y Merchant-Secret).
  • Firma HMAC en cada request (Message-Date, Message-Hash).
  • notify_url pública por HTTPS para cambios de estado.
  • Al menos uno entre consumer_email o consumer_phone_number al crear la orden.

Revisa la sección de Autenticación para la firma.


1) Crear Cotización

Solicita una cotización para el par de activos deseado.

Endpoint: POST /merchants/quotes/

Campos de Request

CampoTipoRequeridoDescripción
blockchainStringRed de fondeo (SOLANA, STELLAR, MONAD).
sendDecimalMonto que enviará el usuario.
send_currencyStringMoneda de origen (ej. USDC).
target_countryStringPaís de destino (MX, CL, etc.).
target_currencyStringMoneda local objetivo (ej. MXN).

Ejemplo de Request

curl -X POST "https://api.dev.pago46.io/api/v1/merchants/quotes/" \
-H "Merchant-Key: <TU_MERCHANT_KEY>" \
-H "Message-Date: <TIMESTAMP>" \
-H "Message-Hash: <HMAC_SIGNATURE>" \
-H "Content-Type: application/json" \
-d '{
"blockchain": "SOLANA",
"send": "150.00",
"send_currency": "USDC",
"target_country": "MX",
"target_currency": "MXN"
}'

Respuesta (201 Created)

{
"id": "01952d8f-8da1-7f4b-bb36-cfba8a3be829",
"blockchain": "SOLANA",
"send": "150.00",
"send_currency": "USDC",
"target_country": "MX",
"target_currency": "MXN",
"calculated_order_price": "2895.00",
"calculated_order_price_currency": "MXN",
"expires": "2030-01-01T11:05:00Z"
}
tip

Guarda el id de la cotización. Lo usarás en la creación de la orden foreign.


2) Crear Orden de Retiro Foreign

Cuando tu usuario acepte la cotización, crea la orden de pay-out foreign usando el quote.

Endpoint: POST /merchants/orders/pay-out/

Campos de Request

CampoTipoRequeridoDescripción
order_typeStringDebe ser ForeignCurrencyOrder.
quoteUUIDID de la cotización creada previamente.
descriptionStringDescripción de la transacción.
merchant_order_idStringID único de tu sistema por Comercio.
notify_urlURLURL para notificaciones de estado.
return_urlURLURL de retorno.
expiryDateTimeExpiración de la orden (ISO 8601).
consumer_emailStringCondicionalRequerido si no envías teléfono.
consumer_phone_numberStringCondicionalRequerido si no envías email.
walletStringWallet que firmará la transacción on-chain.

Ejemplo de Request

curl -X POST "https://api.dev.pago46.io/api/v1/merchants/orders/pay-out/" \
-H "Merchant-Key: <TU_MERCHANT_KEY>" \
-H "Message-Date: <TIMESTAMP>" \
-H "Message-Hash: <HMAC_SIGNATURE>" \
-H "Content-Type: application/json" \
-d '{
"quote": "01952d8f-8da1-7f4b-bb36-cfba8a3be829",
"description": "Retiro cash desde balance USDC",
"merchant_order_id": "FX-PO-2026-0001",
"notify_url": "https://tu-comercio.com/webhooks/pago46",
"return_url": "https://tu-comercio.com/retiro/volver",
"consumer_email": "usuario@ejemplo.com",
"expiry": "2030-01-01T12:05:00Z",
"wallet": "7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV",
"order_type": "ForeignCurrencyOrder"
}'
Importante

La respuesta de este POST retorna 202 Accepted:

  • La orden ha sido creada, pero NO INCLUYE la transacción blockchain por firmar.
  • Pago46 genera la transacción de forma asíncrona.
  • Cuando la transacción on-chain esté lista, recibirás un webhook de actualización de la orden: el status seguirá siendo CREATED, pero ahora el payload incluirá el campo transaction con los datos para firmar.
  • Es decir, puedes recibir múltiples webhooks con el mismo status (CREATED) pero con distinto contenido; considera este webhook como el evento de "transaction ready".
  • ¡No intentes firmar ni mostrar datos de blockchain al usuario hasta recibir este webhook!

Después de crear la orden y recibir el 202 Accepted, tu integración debe esperar la notificación asincrónica por webhook. Solo cuando llegue el webhook con la transacción, el usuario podrá firmar on-chain.

Respuesta inmediata del POST (sin transacción):

{
"id": "01952d91-a0ff-7f57-8f4e-68d95be01122",
"direction": "PAY_OUT",
"country": "MX",
"price": "2895.00",
"price_currency": "MXN",
"description": "Retiro cash desde balance USDC",
"merchant_order_id": "FX-PO-2026-0001",
"status": "CREATED",
"notify_url": "https://tu-comercio.com/webhooks/pago46",
"redirect_url": "https://checkout.dev.pago46.io/01952d91-a0ff-7f57-8f4e-68d95be01122",
"return_url": "https://tu-comercio.com/retiro/volver",
"consumer_email": "usuario@ejemplo.com",
"consumer_phone_number": "",
"expiry": "2030-01-01T12:05:00Z",
"paid": null,
"quote": "01952d8f-8da1-7f4b-bb36-cfba8a3be829",
"wallet": "7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV",
"order_type": "ForeignCurrencyOrder"
}

Ejemplo de webhook: aquí la orden sí incluye el campo transaction:

{
"id": "01952d91-a0ff-7f57-8f4e-68d95be01122",
"order_type": "ForeignCurrencyOrder",
"country": "MX",
"price": "2895.00",
"price_currency": "MXN",
"description": "Retiro cash desde balance USDC",
"merchant_order_id": "FX-PO-2026-0001",
"status": "CREATED",
"notify_url": "https://tu-comercio.com/webhooks/pago46",
"redirect_url": "https://checkout.dev.pago46.io/01952d91-a0ff-7f57-8f4e-68d95be01122",
"return_url": "https://tu-comercio.com/retiro/volver",
"consumer_email": "usuario@ejemplo.com",
"consumer_phone_number": "",
"expiry": "2030-01-01T12:05:00Z",
"paid": null,
"quote": "01952d8f-8da1-7f4b-bb36-cfba8a3be829",
"transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyTBSt8EsV++3pX0uVJVEfDjDp8mnxoqBQocHmFw2xTf62jiq5VGtOhOY4yZH7evGRh3UonSpGQKHYTU0EVXkCgAIBBxJXN/S1MQpq3laWmAefYKQbtIFHc3dbFnEnnIO8+VCswgaIfmL5OVR6yf1DpJxY0nPEwFUxZnKSpVis0mLyYvB+CadUk1OGINWUunRSHPvVZsHS9SxcAzkMV3l0YrJa87VfpoD7lSKyS7KXhZdFjn4tDD9PM7ZkSXL+bJrJU6WMj2H0hZpDLnPhzU1d1RhBedKdDIuLnQj09NPzfpJAUTubj9Njqmepn7FPWB/pRxyBJLcCwVALhYefbQnfHrKVYlqZDYlyLNK33Q83kGZK7y8fZH3WFOPQax4GGUN64gOvfJ3zTDIAyZPrGSRcP4/Qj+sgg0V135Yr0S5moofrpJa7uYWuPLoIHj1rtPdLNX3+MqAowL1C3mfnKmBZ/gHZOU2/2TY6lXGwBdMPZ/X4ph/o4AGrpI1iulm/FEsovQG37vM5zLFxniH7ltpr8uBf04yhJRTUvdC/74e97kFxMjiNAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAEedVb8jHAbu50xW7OaBUH/bGy3qP0jlECsc2iVrwTjwVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKkG3fbh7nWP3hhCXbzkbM3athr8TYO5DSf+vfko2KGL/LQ/+if11/ZKdMCbHylYed5LCas238ndUUsyGqezjOXo4vh36D2uxoiPQ6u1rnsxG7eMNJYIl/zlp7gsFuIP8ZcyjRWyhzKZjkXq5kHeRVDaKaLEEPfSWQM7V8ohwWOR/wYNABhBWnljbytLbWRnbTNZZFN4Q1Z5SnFBPT0OBAYYCQAKDEBCDwAAAAAABgsABQLAXBUACwAJAwQXAQAAAAAADB0OEQEJCAcEGBcMDxAMFg8ODRETFxgHEggUAgMKFSbBIJszQdacgQABAAAALwAAZAABQEIPAAAAAADskeQAAAAAABQAAA8EBBcFAQoM7vXjAAAAAAAGAWdhe29wATESFFYXVPJ+3KgjZOfKxNroQxcYyDV2rOPsBJVakZgDllyS",
"wallet": "7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV"
}

3) Consultar Orden

Puedes consultar la orden de retiro cuando necesites verificar su estado.

Endpoint: GET /merchants/orders/pay-out/{id}/

curl -X GET "https://api.dev.pago46.io/api/v1/merchants/orders/pay-out/01952d91-a0ff-7f57-8f4e-68d95be01122/" \
-H "Merchant-Key: <TU_MERCHANT_KEY>" \
-H "Message-Date: <TIMESTAMP>" \
-H "Message-Hash: <HMAC_SIGNATURE>"

Estados de la Orden (Foreign Pay-Out)

EstadoDescripción¿Qué significa para el comercio?
CREATEDOrden creada exitosamenteLa orden se ha registrado y está pendiente de asignación a un proveedor
READYFondos validados; orden lista para ser procesadaLa recepción de fondos fue validada; la orden puede ser tomada por un proveedor para el retiro
PAYMENT_STARTEDPago en procesoUn proveedor ha bloqueado la orden y está procesando el retiro
COMPLETEDCompletadaEl retiro se completó exitosamente. El beneficiario recibió el efectivo
CANCELLEDCanceladaLa orden fue cancelada y no se procesará
EXPIREDExpiradaLa orden expiró y no se procesará

Diagrama de Transición de Estados


Buenas Prácticas de Integración

  • Usa merchant_order_id idempotente por operación de negocio.
  • Maneja cambios de estado de forma tolerante a reintentos.
  • No asumas COMPLETED inmediatamente después de crear la orden.
  • Presenta al usuario una cuenta regresiva según la ventana de cotización.
  • Después del POST, mantén un estado "Esperando transacción" hasta recibir el webhook con el campo transaction.
  • Almacena el id de la orden devuelta para correlacionar el POST inicial y el webhook subsiguiente.
  • Ante errores de validación, solicita una nueva cotización antes de reintentar. Consulta la sección Manejo de errores comunes para más detalles sobre el formato de los mensajes de error devueltos por la API.

Si necesitas soporte para nuevos pares (por ejemplo, activos de origen o países adicionales), contacta a tu representante de Pago46.