Contrato común de entrada y salida
Estado documental: Propuesto. Los nombres de campos y enums están suficientemente definidos para orientar desarrollo, pero pueden cambiar mediante control de versiones antes de la confirmación contractual.
Objetivo
Este contrato define la estructura común de una orden YUPY para crearla, correlacionarla, devolver opciones de pago, consultar su estado, conciliarla, notificar el resultado y auditarla.
Alcance actual
Los tipos de opción previstos para la primera versión son:
yape_qr
plin_qr
bank_transfer
bank_transfer es opcional y solo debe devolverse cuando el perfil de cobro incluya una cuenta autorizada.
Principios
- Una identidad transaccional común para todas las experiencias.
- Perfiles receptores configurados, no datos bancarios libres por solicitud.
- Montos y fechas con tipos predecibles.
- Campos condicionales según experiencia y presentación.
- Metadata auxiliar sin sustituir campos contractuales.
- Compatibilidad y extensibilidad mediante versiones.
Solicitud común propuesta
{
"external_transaction_id": "ORDER-10482",
"created_at": "2026-07-19T14:30:00-05:00",
"amount": "85.50",
"currency": "PEN",
"integration_experience": "direct_api",
"presentation_strategy": "client_managed",
"collection_profile_id": "COLLECTION-PERU-01",
"requested_payment_methods": [
"yape_qr",
"plin_qr",
"bank_transfer"
],
"expires_in_seconds": 900,
"buyer": {
"external_id": "CUSTOMER-883",
"first_name": "María",
"last_name": "Ramos",
"phone": "+51999999999",
"email": "maria@example.com"
},
"context": {
"location_id": "STORE-01",
"seller_id": "SELLER-08",
"shift_id": "SHIFT-20260719-PM",
"terminal_id": "POS-03",
"destination_id": null,
"conversation_id": null,
"channel": "web",
"custom_reference_1": "ROUTE-184",
"custom_reference_2": "COUNTER-03"
},
"metadata": {
"order_type": "sale"
}
}
Campos de primer nivel
external_transaction_id
Tipo: string. Obligatorio: sí.
Identificador único y estable de la operación en el sistema de origen. No debe reutilizarse ni contener secretos.
created_at
Tipo: fecha y hora ISO 8601 con offset. Obligatorio: sí.
2026-07-19T14:30:00-05:00
amount
Tipo: string decimal. Obligatorio: sí.
"amount": "85.50"
Debe ser mayor que cero, sin separadores de miles y con precisión compatible con la moneda. No debe utilizarse un tipo de punto flotante para cálculos financieros.
currency
Tipo: código de moneda. Obligatorio: sí.
"currency": "PEN"
integration_experience
Tipo: enum. Obligatorio: sí.
direct_api
web_checkout
chat_pos
integrated_pos
presentation_strategy
Tipo: enum. Obligatorio: sí.
client_managed
yupy_checkout
yupy_chat_delivery
integrated_pos
En client_managed, YUPY devuelve las opciones y la plataforma de la empresa las presenta.
collection_profile_id
Tipo: string. Obligatorio: sí, salvo perfil predeterminado configurado explícitamente.
Identifica la configuración receptora que contiene QR, cuentas y fuentes de conciliación autorizadas.
requested_payment_methods
Tipo: array de enums. Obligatorio: no.
Limita la respuesta a opciones autorizadas dentro del perfil.
yape_qr
plin_qr
bank_transfer
YUPY no debe devolver una opción no habilitada en el perfil.
expires_in_seconds
Tipo: integer. Obligatorio: no.
Representa la vigencia operativa solicitada. YUPY puede aceptarla, ajustarla o rechazarla según configuración. La respuesta devuelve expires_at.
El vencimiento de la orden no invalida necesariamente un QR fijo ni impide detectar un pago tardío.
Objeto buyer
Es condicional y debe respetar minimización de datos.
{
"external_id": "CUSTOMER-883",
"first_name": "María",
"last_name": "Ramos",
"phone": "+51999999999",
"email": "maria@example.com"
}
Un comprador puede ser anónimo en determinados flujos. El teléfono o correo solo se exige cuando la entrega o el proceso lo necesita.
Objeto context
{
"location_id": "STORE-01",
"seller_id": "SELLER-08",
"shift_id": "SHIFT-20260719-PM",
"terminal_id": "POS-03",
"destination_id": "DESTINATION-01",
"conversation_id": "CONVERSATION-883",
"channel": "whatsapp",
"custom_reference_1": "ROUTE-184",
"custom_reference_2": "SEAT-12A"
}
Campos operativos
location_id: local, agencia, sucursal o punto de atención.seller_id: vendedor, agente o responsable.shift_id: turno operativo.terminal_id: terminal, caja o POS.destination_id: destino conversacional configurado.conversation_id: conversación dentro del canal.channel: canal utilizado.
Referencias flexibles
custom_reference_1custom_reference_2
Son strings opcionales para clientes con procesos particulares. Pueden representar ruta, asiento, mesa, habitación, caja, código de atención, localizador de reserva u otra correlación estable.
No deben contener secretos ni sustituir los campos comunes. Su significado debe documentarse en cada integración.
Objeto metadata
Objeto opcional para información auxiliar.
No debe reemplazar monto, moneda, identificadores, perfil, experiencia, canal ni reglas de conciliación. No debe contener credenciales ni datos personales innecesarios.
Respuesta común propuesta
{
"yupy_transaction_id": "ypt_01JXYZ...",
"external_transaction_id": "ORDER-10482",
"collection_profile_id": "COLLECTION-PERU-01",
"created_at": "2026-07-19T14:30:02-05:00",
"updated_at": "2026-07-19T14:30:02-05:00",
"expires_at": "2026-07-19T14:45:02-05:00",
"amount": "85.50",
"currency": "PEN",
"integration_experience": "direct_api",
"presentation_strategy": "client_managed",
"state": {
"operational": "active",
"financial": "awaiting_payment",
"delivery": "not_applicable"
},
"payment_options": [
{
"payment_option_id": "OPTION-YAPE-01",
"type": "yape_qr",
"label": "Pagar con Yape",
"qr_image_url": "<TEMPORARY_QR_IMAGE_URL>",
"recipient_display_name": "<RECIPIENT_NAME>",
"instructions": "Escanea el QR e ingresa el monto exacto."
}
]
}
Objeto payment_options
Cada opción debe tener un payment_option_id estable que permita registrar qué recurso se presentó y qué fuente debe utilizarse para conciliar.
Yape QR
{
"payment_option_id": "OPTION-YAPE-01",
"type": "yape_qr",
"label": "Pagar con Yape",
"qr_image_url": "<TEMPORARY_QR_IMAGE_URL>",
"recipient_display_name": "<RECIPIENT_NAME>",
"instructions": "Escanea el QR e ingresa el monto exacto."
}
Plin QR
{
"payment_option_id": "OPTION-PLIN-01",
"type": "plin_qr",
"label": "Pagar con Plin",
"qr_image_url": "<TEMPORARY_QR_IMAGE_URL>",
"recipient_display_name": "<RECIPIENT_NAME>",
"instructions": "Escanea el QR e ingresa el monto exacto."
}
Transferencia bancaria
{
"payment_option_id": "OPTION-BANK-01",
"type": "bank_transfer",
"label": "Transferencia bancaria",
"bank_name": "<BANK_NAME>",
"account_type": "<ACCOUNT_TYPE>",
"account_number_display": "<ACCOUNT_NUMBER>",
"cci_display": "<CCI>",
"recipient_display_name": "<RECIPIENT_NAME>"
}
Reglas de presentación
- La plataforma puede mostrar una o varias opciones elegibles.
- Debe mostrar el monto exacto por separado cuando el QR no lo codifique.
- No debe editar QR ni datos bancarios.
- Debe conservar
payment_option_id. - Puede informar posteriormente qué opción seleccionó el comprador.
- No debe marcar la orden como pagada por el solo hecho de mostrar o entregar una opción.
Estados comunes
Operativo
created
active
expired
cancelled
closed
Financiero
awaiting_payment
payment_reported
movement_detected
reconciliation_pending
reconciled
amount_difference
ambiguous
not_found
late_detected
Entrega
not_applicable
pending
sent
delivered
opened
failed
Validaciones mínimas
YUPY debe rechazar solicitudes con campo obligatorio ausente, monto inválido, moneda no soportada, fecha incorrecta, experiencia desconocida, estrategia incompatible, perfil inexistente, medio no habilitado, contexto obligatorio ausente, conflicto de idempotencia o credencial sin permiso.
Error estructurado propuesto
{
"error": {
"code": "validation_error",
"message": "The request contains invalid fields.",
"fields": {
"amount": [
"amount must be greater than zero"
]
},
"request_id": "req_01JXYZ..."
}
}
Correlación y logs
request_id
idempotency_key
external_transaction_id
yupy_transaction_id
payment_option_id
event_id
Los logs deben redactar credenciales, firmas, tokens, datos bancarios sensibles y datos personales no necesarios.
Extensibilidad
Una versión futura podrá añadir tipos como card, google_pay, apple_pay, other_wallet o crypto_asset. Esos valores no forman parte del contrato operativo actual y no deben ser enviados ni interpretados hasta que sean publicados en una versión compatible.
Compatibilidad
Nuevos campos opcionales pueden añadirse de manera compatible si el receptor puede ignorarlos con seguridad. Cambios de significado, tipos, campos obligatorios, estados o reglas requieren nueva versión, migración y pruebas.
Criterios de aceptación
- Campos obligatorios y condicionales aprobados.
- Perfil de cobro obligatorio o predeterminado explícito.
- Tipos actuales limitados a Yape QR, Plin QR y transferencia opcional.
- Múltiples opciones identificables.
- Montos sin
float. - Fechas con zona horaria.
- Idempotencia definida.
- Datos personales minimizados.
- Errores estructurados.
- Referencias flexibles documentadas.
- Extensiones futuras separadas de capacidades actuales.