Transacción
El endpoint de Transacción es la culminación del flujo de remesas. Vincula al remitente, el destinatario, la fuente de fondos, la cuenta del destinatario y la cotización para ejecutar un pago transfronterizo.
Creación de una Transacción
Endpoint: POST /organizations/{tenant}/fx/transactions
Autenticación: A nivel de agente (x-api-key + x-agent-id + x-agent-api-key)
Cuerpo de la Solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
senderId | string (UUID) | Sí | El ID de participante del remitente (de POST /people) |
recipientId | string (UUID) | Sí | El ID de participante del destinatario (de POST /people) |
fundingAccountId | string (UUID) | Sí | La fuente de fondos del remitente (de POST /fundingAccounts) |
recipientAccountId | string (UUID) | Sí | La cuenta de payout del destinatario (de POST /recipientAccounts/gateway) |
quoteId | string (UUID) | Sí | La cotización de FX bloqueada (de POST /payout/quotes) |
externalId | string | No | Su ID de referencia interno para conciliación. Devuelto en los webhooks como externalTransactionId. |
deviceData | object | Condicional | Inteligencia de dispositivo para prevención de fraude (vea abajo) |
deviceData.userIpAddress | string | Condicional | La dirección IP del usuario final. Requerido cuando el fingerprinting está habilitado para su tenant (el predeterminado). |
deviceData.fingerprint | string | Condicional | El requestId de la librería de fingerprint del dispositivo. Requerido cuando el fingerprinting está habilitado (el predeterminado). |
deviceData.visitor | string | Recomendado | El visitorId de la librería de fingerprint del dispositivo |
additionalData | object | No | Ubicación legada para fingerprint y visitor (ambos aceptados), más campos específicos por país según el esquema de transacción |
sendingReason | string | No | Propósito de la transferencia (p. ej., "Family support", "Payment for services") |
senderReceiverRelationship | string | No | Relación entre remitente y destinatario (p. ej., "Family member", "Business partner") |
sourceOfFunds | string | No | Origen de los fondos (p. ej., "Salary", "Savings", "Business income") |
Fingerprint del Dispositivo
La mayoría de los tenants tienen el fingerprinting de dispositivos habilitado (es el valor predeterminado de la plataforma). Cuando está habilitado, cada transacción debe incluir un fingerprint y la dirección IP del usuario, o la solicitud es rechazada. Integre una librería de fingerprint de dispositivo en su aplicación cliente — Inyo proporciona las claves de API para el servicio de fingerprint durante el onboarding.
Antes de enviar una transacción, invoque la librería de fingerprint del lado del cliente y pase los resultados:
deviceData.fingerprint— elrequestIdde la librería de fingerprintdeviceData.visitor— elvisitorIdde la librería de fingerprintdeviceData.userIpAddress— la dirección IP del usuario final
Envíe AMBOS:
fingerprintyvisitor. La integración de inteligencia de dispositivo del lado del servidor del gateway de pagos solo se ejecuta cuando ambos valores están presentes. Enviar solo uno elimina silenciosamente el bloque de inteligencia de dispositivo de la llamada al gateway, lo que reduce la precisión de la evaluación de fraude y puede contribuir a rechazos.
fingerprintyvisitortambién se aceptan dentro deadditionalData(formato legado).deviceDataes la ubicación preferida.
Ejemplo de Solicitud
curl --request POST \
--url https://{FQDN}/organizations/$TENANT/fx/transactions \
--header 'Content-Type: application/json' \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY" \
--data '{
"externalId": "your-internal-reference-123",
"senderId": "422a55b2-78c3-4509-8654-16e7375d3e40",
"recipientId": "4b9dcb4e-2e2a-4e96-b2a9-fcd868b2f4ed",
"fundingAccountId": "3fe5f23f-65d3-41b6-b34c-33db3c4d8ef9",
"recipientAccountId": "67203d69-dc48-41d4-b2ac-52682d39b032",
"quoteId": "30bf05d2-b416-4e71-b8e8-1ef158a2b414",
"deviceData": {
"userIpAddress": "200.123.131.112",
"fingerprint": "1727364523875.mchLfB",
"visitor": "jkS9xp4FHlqOSfGR"
},
"sendingReason": "Family support",
"senderReceiverRelationship": "Family member",
"sourceOfFunds": "Salary"
}'
Ejemplo de Respuesta (HTTP 202)
{
"id": "9035ee18-052b-4176-a940-ccfe599a1829",
"sender": {
"id": "ce06773d-6472-4c93-bdf5-8eb68ab01c7f",
"type": "PERSON",
"name": "Rob Dalas",
"phoneNumber": "+1 123 456435"
},
"recipient": {
"id": "156675d5-1d1b-4b4d-997e-5c15ae129b82",
"type": "PERSON",
"name": "Bob Danilo",
"phoneNumber": "+55 71 91234-5678"
},
"tenantId": "master",
"externalId": "your-internal-reference-123",
"agentId": "41f55211-1eea-4747-9a03-68e99f07ede5",
"createdAt": "2025-05-29T17:26:27.264312",
"anchorCurrencyAmount": { "amount": "102.53", "currency": "USD" },
"complianceStatus": "Pending",
"payoutStatus": "Pending",
"paymentStatus": null,
"quoteId": "af2d55d8-1d40-426a-8d4a-7454ccdcbe8a",
"fundingAccountId": "61bc14a1-b3a2-40b4-b395-0496e4f554a1",
"recipientAccountId": "4fbc57a6-f673-44ba-88aa-c6e71eb9181b",
"exchangeRate": "5.571062480000000",
"totalAmount": { "amount": "102.53", "currency": "USD" },
"receivingAmount": { "amount": "571.20", "currency": "BRL" },
"fee": { "amount": "1.54", "currency": "USD" },
"conversionAmount": { "amount": "102.53", "currency": "USD" },
"type": "FX",
"senderId": "ce06773d-6472-4c93-bdf5-8eb68ab01c7f",
"recipientId": "156675d5-1d1b-4b4d-997e-5c15ae129b82",
"sendingReason": "Family support",
"receipt": { "..." : "regulatory disclosures" }
}
Campos de la Respuesta
| Campo | Descripción |
|---|---|
id | ID único de la transacción |
complianceStatus | Resultado actual de la evaluación de cumplimiento (vea el ciclo de vida abajo) |
payoutStatus | Estado actual de la entrega del payout (vea el ciclo de vida abajo) |
paymentStatus | ActionRequired cuando la tarjeta requiere un desafío 3DS, de lo contrario null |
redirectAcsUrl | URL del desafío 3DS — presente solo cuando paymentStatus es ActionRequired |
status.messages | Registro de auditoría de las transiciones de estado con marcas de tiempo |
exchangeRate | La tasa de FX aplicada |
totalAmount | Monto total cobrado al remitente (en la moneda de origen) |
receivingAmount | Monto a recibir por el beneficiario (en la moneda de destino) |
fee | Comisión de la transacción en la moneda de origen |
conversionAmount | Monto que fue convertido (moneda de origen) |
receipt | Divulgaciones regulatorias que deben mostrarse al remitente (vea abajo) |
type | Tipo de transacción — FX |
Errores de Validación
Los fallos de validación devuelven HTTP 400 con un desglose por campo:
{
"errors": [
{ "fieldName": "fingerprint", "error": "A fingerprint is required (deviceData.fingerprint or additionalData.fingerprint)." },
{ "fieldName": "deviceData.userIpAddress", "error": "The device IP address is required." }
]
}
Manejo de 3D Secure (3DS)
Cuando la tarjeta del remitente requiere autenticación 3DS, la respuesta de creación incluye:
{
"paymentStatus": "ActionRequired",
"redirectAcsUrl": "https://..."
}
Flujo:
- Abra
redirectAcsUrlen un WebView o ventana emergente. - El usuario completa la verificación 3DS en la página del emisor.
- Escuche el evento
postMessagede la interfaz de pago para determinar si el desafío tuvo éxito. - Si tuvo éxito: cierre el WebView y sondee
GET /fx/transactions/{id}— la transacción se reanuda automáticamente (integración de payout, revisión de cumplimiento, etc.).paymentStatusvuelve anulluna vez que el desafío se resuelve. - Si falló: cierre el WebView y muestre un error — la transacción pasa a
PaymentDeclined→Cancelled.
Si la tarjeta no recibe un desafío, la transacción procede de inmediato y redirectAcsUrl está ausente. Mientras el desafío está pendiente, la transacción permanece en el estado WaitingChallenge3ds.
Nunca omita el desafío 3DS. Una transacción atascada en
WaitingChallenge3dsno progresará hasta que el desafío se complete o la transacción se cancele.
Ciclo de Vida del Estado de la Transacción
Cada transacción expone dos dimensiones de estado resumidas en GET /fx/transactions/{id}, más un estado interno detallado entregado vía webhooks.
Estado de Cumplimiento
| Estado | Descripción |
|---|---|
Pending | Evaluación aún no completada |
Approved | Pasó las comprobaciones de cumplimiento — la transacción puede proceder |
Rejected | Falló la revisión de cumplimiento — la transacción está bloqueada |
Cancelled | La transacción fue cancelada antes de completarse |
Refunded | La transacción fue reembolsada después de la captura del pago |
Failed | Pago rechazado u ocurrió un error irrecuperable |
Estado de Payout
| Estado | Descripción |
|---|---|
Pending | Transacción aceptada, la etapa de pago aún en progreso |
Processing | Entregada a la red de payout (MSB), a la espera de la entrega |
Completed | Fondos entregados al destinatario |
Cancelled | La transacción fue cancelada |
Failed | Payout rechazado por la red, pago rechazado o error |
Voided | Payout anulado por la red de payout |
Refunded | La transacción fue reembolsada |
Flujos de Estado Detallados
Los estados detallados de abajo se entregan en los webhooks TransactionStatusChanged y en el endpoint de historial de estados.
Tarjeta (con 3DS):
Created → PaymentProcessing → WaitingChallenge3ds → [user completes 3DS] → PaymentAuthorized → ProcessingPayout → PayoutAccepted → ManualReview → ReviewApproved → PaymentCaptured → WaitingPayout → [payout network confirms delivery] → Paid → Completed
Tarjeta (sin 3DS):
Created → PaymentProcessing → PaymentAuthorized → ProcessingPayout → PayoutAccepted → ManualReview → ReviewApproved → PaymentCaptured → WaitingPayout → [payout network confirms delivery] → Paid → Completed
ACH:
Created → PaymentProcessing → PaymentAuthorized → ProcessingPayout → PayoutAccepted → WaitingSettlement → [ACH settles] → PaymentSettled → PaymentCaptured → WaitingPayout → [payout network confirms delivery] → Paid → Completed
Ramas de excepción:
PayoutHold— la red de payout aplicó una retención de cumplimiento; se libera automáticamente o por el equipo de cumplimiento (PayoutHold→PayoutReleased→ el flujo se reanuda)PayoutRejected— la red de payout rechazó la transacción; se cancela y el pago se revierteManualReview→ReviewRejected— el equipo de cumplimiento rechazó el pago; se anulaBlockedPendingReview— una regla de riesgo o una coincidencia en una lista de bloqueo pausó la transacción para revisión de un operador antes de continuarPendingReversalApproval— el payout fue anulado más adelante en la cadena y la reversión está a la espera de la aprobación de un operador (configurable por tenant)CancelRequested— usted solicitó la cancelación; la reversión está siendo procesada
Dependiendo de la configuración de su tenant,
ManualReviewpuede aprobarse automáticamente (todas las transacciones, solo tarjeta o solo ACH), en cuyo caso veráManualReview→ReviewApprovedde forma consecutiva.
Consulta de Transacciones
Obtener Transacción por ID
curl --request GET \
--url https://{FQDN}/organizations/$TENANT/fx/transactions/$TRANSACTION_ID \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY"
Listar Transacciones
curl --request GET \
--url "https://{FQDN}/organizations/$TENANT/fx/transactions?page=0&size=20&senderId=$SENDER_ID" \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY"
Parámetros de Consulta:
| Parámetro | Tipo | Descripción |
|---|---|---|
page | integer | Número de página (indexado desde 0), predeterminado 0 |
size | integer | Resultados por página, predeterminado 20 |
senderId | string (UUID) | Filtrar por participante remitente |
status | string | Filtrar por estado de cumplimiento (p. ej., APPROVED) |
Respuesta: { "total": <count>, "transactions": [ ... ] }, la más reciente primero.
Obtener el Historial de Estados de una Transacción
Devuelve el registro de auditoría completo de los cambios de estado de una transacción, el más reciente primero.
curl --request GET \
--url https://{FQDN}/organizations/$TENANT/fx/transactions/$TRANSACTION_ID/status \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY"
Ejemplo de Respuesta:
[
{
"id": "2f6b3f12-a63f-43f7-9bb4-4e98dfc75fe5",
"complianceStatus": "Approved",
"payoutStatus": "Pending",
"transactionId": "46b4c393-3768-4ba4-b6d2-a6398e17dd78",
"tenantId": "master",
"externalId": "GMT000648512199",
"createdAt": "2024-01-03T12:54:09.455",
"messages": [
{
"id": "0fbbddb8-283d-466d-b2e6-42dcbb3e67de",
"message": "STANDARD - PAYMENT_RECEIVED",
"createdBy": "system",
"createdAt": "2025-11-19T13:29:52.221882",
"type": "SystemUpdate"
}
]
}
]
Cancelación / Reversión de una Transacción
Existe un único endpoint de reversión. Inyo determina la operación de reversión correcta según cuánto haya progresado la transacción:
- Pago solo preautorizado → la autorización se anula (void)
- Pago ya capturado (pero fondos aún no entregados) → el pago se reembolsa
Endpoint: PUT /organizations/{tenant}/fx/transactions/{transactionId}/status/cancel
Autenticación: A nivel de agente
curl --request PUT \
--url https://{FQDN}/organizations/$TENANT/fx/transactions/$TRANSACTION_ID/status/cancel \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY"
La reversión se procesa de forma asíncrona: la transacción pasa a CancelRequested, y luego a Cancelled (anulada) o Refunded una vez que el gateway confirma.
Respuestas:
| Estado | Descripción |
|---|---|
204 | Reversión aceptada y en cola |
404 | Transacción no encontrada |
422 | La transacción no está en un estado reversible |
Una vez que la red de payout ha entregado los fondos al destinatario (
Paid/Completed), la transacción ya no puede revertirse a través de la API — contacte al soporte de Inyo.
Actualización de Metadatos de la Transacción
Adjunte datos arbitrarios de clave-valor a una transacción para su seguimiento interno. Devuelve 204.
Endpoint: PUT /organizations/{tenant}/fx/transactions/{transactionId}/metadata
Autenticación: A nivel de agente
curl --request PUT \
--url https://{FQDN}/organizations/$TENANT/fx/transactions/$TRANSACTION_ID/metadata \
--header 'Content-Type: application/json' \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY" \
--data '{
"internalRef": "INV-2025-001",
"department": "treasury"
}'
Transacciones en Lote
Para casos de uso de alto volumen puede enviar múltiples transacciones en una sola llamada. Cada elemento usa la misma forma que la solicitud de creación individual.
| Operación | Método | Endpoint |
|---|---|---|
| Enviar lote | POST | /organizations/{tenant}/fx/transactions/batch |
| Reintentar un elemento fallido del lote | POST | /organizations/{tenant}/fx/transactions/batch/{transactionId}/retry |
{ "transactions": [ { "senderId": "...", "recipientId": "...", "...": "..." } ] }
Ambos endpoints devuelven 202 Accepted; las transacciones individuales progresan de forma independiente — rastréelas vía webhooks o sondeo.
Límites de Transacción
Antes de ejecutar una transacción, verifique que el remitente no haya excedido sus límites. Los números reportados aquí se calculan con las mismas reglas que aplica el validador de transacciones, así que lo que aparece como available es lo que una transacción puede usar realmente.
Endpoint: GET /organizations/{tenant}/fx/participants/{participantId}/limits
Autenticación: A nivel de agente
curl --request GET \
--url https://{FQDN}/organizations/$TENANT/fx/participants/$SENDER_ID/limits \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY"
Ejemplo de Respuesta:
{
"oneDayLimit": {
"limit": { "amount": "2999.00", "currency": "USD" },
"used": { "amount": "0.00", "currency": "USD" },
"available": { "amount": "2999.00", "currency": "USD" }
},
"thirtyDaysLimit": {
"limit": { "amount": "6000.00", "currency": "USD" },
"used": { "amount": "2959.99", "currency": "USD" },
"available": { "amount": "3040.01", "currency": "USD" }
},
"oneHundredAndEightyDaysLimit": {
"limit": { "amount": "9999.00", "currency": "USD" },
"used": { "amount": "5000.00", "currency": "USD" },
"available": { "amount": "4999.00", "currency": "USD" }
}
}
Para ver qué campos se necesitan para alcanzar el siguiente nivel de cumplimiento (y desbloquear límites más altos), use GET /participants/{id}/complianceLevels — vea Límites por Nivel de Confianza.
Recibos (Requisito Regulatorio)
Como agente de un Money Service Business con licencia, usted está legalmente obligado a emitir un recibo al remitente inmediatamente después del envío de la transacción. La respuesta de la transacción incluye un objeto receipt con divulgaciones regulatorias obligatorias que deben mostrarse textualmente al usuario final.
El recibo debe incluir:
- Tipo de cambio — la tasa bloqueada de la cotización
- Comisiones — comisiones totales cobradas al cliente
- Monto total — monto completo pagado por el remitente
- Monto a recibir — monto exacto a recibir por el beneficiario
- Divulgaciones regulatorias — texto legal dinámico específico del corredor (p. ej., derecho a reembolso, política de cancelación)
No debe alterar los datos financieros ni el texto regulatorio devueltos por la API. Muéstrelos tal cual.
Sandbox: Forzar Transiciones de Estado
En sandbox/staging puede simular eventos externos (callbacks del gateway, notificaciones de payout) para llevar una transacción a través de su ciclo de vida sin movimiento de dinero real. Vea Pruebas en Sandbox.
Respuestas de Error
| Estado HTTP | Causa |
|---|---|
400 | Campos requeridos faltantes, formato de datos inválido, fingerprint/IP faltante o cotización vencida |
403 | Agente no aprobado, o el remitente no cumple los requisitos de cumplimiento |
404 | La transacción/participante/cuenta referenciada no se encontró en su tenant |
422 | Violación de regla de negocio (p. ej., límite excedido, corredor inválido, estado no reversible) |
Todos los Endpoints
| Operación | Método | Endpoint |
|---|---|---|
| Crear transacción | POST | /organizations/{tenant}/fx/transactions |
| Obtener transacción | GET | /organizations/{tenant}/fx/transactions/{transactionId} |
| Listar transacciones | GET | /organizations/{tenant}/fx/transactions |
| Obtener historial de estados | GET | /organizations/{tenant}/fx/transactions/{transactionId}/status |
| Cancelar / revertir transacción | PUT | /organizations/{tenant}/fx/transactions/{transactionId}/status/cancel |
| Actualizar metadatos | PUT | /organizations/{tenant}/fx/transactions/{transactionId}/metadata |
| Enviar lote | POST | /organizations/{tenant}/fx/transactions/batch |
| Reintentar elemento del lote | POST | /organizations/{tenant}/fx/transactions/batch/{transactionId}/retry |
| Consultar límites | GET | /organizations/{tenant}/fx/participants/{participantId}/limits |
| Obtener campos requeridos/opcionales | GET | /organizations/{tenant}/fx/transactions/schema?countryCode={iso2} |
| Forzar cambio de estado (sandbox) | POST | /organizations/{tenant}/fx/transactions/{transactionId}/events |
