API Technical Docs

Mantente al día con las innovaciones tecnológicas que están transformando el mercado.

Webhooks, callbacks y entregas

Mensajería remota del ciclo de Payment Order

Diseño objetivo del módulo. Su propósito es permitir que un sistema externo siga remotamente una Payment Order desde su creación hasta su resultado terminal. El lifecycle canónico pertenece a la Payment Order; el Checkout Web es el canal o sesión que la envuelve.

Estado de implementación: payment_order.created, payment_order.presented y payment_order.terminal están implementados y certificados como callbacks productivos del Web Checkout QR.

Contrato productivo actual

Para Web Checkout QR, los callbacks externos productivos y certificados son:

payment_order.created
payment_order.presented
payment_order.terminal

payment_order.terminal usa únicamente result = pagado | cancelado | timeout. failed no es un cuarto resultado comercial terminal público.

Las entregas se firman con HMAC-SHA256 usando X-YUPY-Certification-Timestamp y X-YUPY-Certification-Signature. El receptor debe verificar el cuerpo crudo, deduplicar por event_id y responder HTTP 2xx rápidamente.

YUPY realiza hasta cinco intentos de entrega: inmediato, +30 s, +120 s, +600 s y +1800 s. Timeout, errores de conexión, HTTP 408, 425, 429 y 5xx son reintentables.

Importante: las rutas de administración de receptores o deliveries que en esta página estén marcadas como propuestas no deben interpretarse como endpoints productivos públicos hasta que su propia documentación figure como implementada y verificada.

1. payment_order.created

  • created — creada correctamente.
  • rejected — rechazada por validación o regla de negocio.
  • duplicate — operación equivalente ya existente por idempotencia.
  • Si la creación no puede completarse, la API devuelve un error HTTP y no se emite un resultado comercial terminal failed.
{
  "event": "payment_order.created",
  "result": "created",
  "message": "Payment Order created successfully.",
  "external_transaction_id": "TX-12345",
  "payment_order_uid": "po_...",
  "checkout_uid": "chk_...",
  "amount": "125.50",
  "currency": "PEN",
  "payment_method": "qr",
  "channel": "web",
  "occurred_at": "2026-08-28T03:39:50Z"
}

2. payment_order.presented

  • presented — presentado correctamente.
  • presentation_failed — no pudo presentarse.
  • expired_before_presentation — expiró antes de presentarse.
  • cancelled_before_presentation — fue cancelada antes de presentarse.
{
  "event": "payment_order.presented",
  "result": "presented",
  "message": "Payment method presented to customer.",
  "external_transaction_id": "TX-12345",
  "payment_order_uid": "po_...",
  "payment_method": "qr",
  "channel": "web",
  "presented_at": "2026-08-28T03:40:02Z",
  "occurred_at": "2026-08-28T03:40:02Z"
}

3. payment_order.terminal

  • pagado — pago confirmado.
  • cancelado — operación cancelada.
  • timeout — venció sin pago confirmado.
  • No existe failed como cuarto resultado comercial terminal público.
  • rejected — reservado para medios futuros que expongan rechazo terminal explícito.
{
  "event": "payment_order.terminal",
  "result": "pagado",
  "message": "Payment confirmed.",
  "external_transaction_id": "TX-12345",
  "payment_order_uid": "po_...",
  "amount": "125.50",
  "currency": "PEN",
  "payment_method": "qr",
  "channel": "web",
  "presented_at": "2026-08-28T03:40:02Z",
  "paid_at": "2026-08-28T03:41:18Z",
  "occurred_at": "2026-08-28T03:41:18Z"
}

Datos comunes de correlación

Los mensajes deben incluir, cuando corresponda, external_transaction_id, payment_order_uid, checkout_uid, amount, currency, payment_method, channel y occurred_at. Según el evento también pueden incluir checkout_created_at, presented_at, paid_at, timeout_seconds, result y message.

Flujo conceptual: payment_order.created → payment_order.presented → payment_order.terminal.

Webhooks, callbacks y entregas

Estado documental: Contrato propuesto. Las rutas, campos, límites y tiempos pasan a estado confirmado solo después de su implementación y verificación.

Objetivo: Documentar el registro de callbacks, sus entregas, firma, reintentos y eventos cliente dentro del contrato público Payment Order / API Engine.

Endpoints receptores

La empresa registra previamente uno o varios endpoints HTTPS. Las Payment Orders no aceptan URLs arbitrarias sin autorización.

Audiencia Método Ruta propuesta Uso Idempotencia Eventos o callbacks relacionados
Integración POST /v1/webhook-endpoints Registrar receptor. Obligatoria webhook.endpoint_created
Integración GET /v1/webhook-endpoints Listar receptores. No Ninguno
Integración GET /v1/webhook-endpoints/{id} Consultar receptor. No Ninguno
Integración PATCH /v1/webhook-endpoints/{id} Modificar URL, eventos o estado. Obligatoria webhook.endpoint_updated
Integración DELETE /v1/webhook-endpoints/{id} Desactivar o eliminar. Obligatoria webhook.endpoint_deleted
Integración POST /v1/webhook-endpoints/{id}/test Enviar evento de prueba. Obligatoria webhook.test_sent
Integración POST /v1/webhook-endpoints/{id}/rotate-secret Rotar secreto. Obligatoria webhook.secret_rotated
Integración POST /v1/webhook-endpoints/{id}/pause Pausar entregas. Obligatoria webhook.endpoint_paused
Integración POST /v1/webhook-endpoints/{id}/resume Reanudar. Obligatoria webhook.endpoint_resumed

Ejemplo: registrar receptor

POST /v1/webhook-endpoints
Idempotency-Key: 0846d8ad-a8a3-49bc-a7e8-f9d8f839783b
{
  "url": "https://api.cliente.com/webhooks/yupy",
  "events": [
    "payment_instruction.presented",
    "payment.reconciled",
    "payment.amount_difference",
    "payment.late_detected"
  ],
  "active": true
}
{
  "webhook_endpoint_id": "whe_01JXYZ",
  "url": "https://api.cliente.com/webhooks/yupy",
  "secret": "<SHOWN_ONCE>",
  "status": "active",
  "request_id": "req_01JXYZ"
}

Referencia opcional desde una Payment Order

{
  "webhook_endpoint_id": "whe_01JXYZ"
}

El ID debe pertenecer a la empresa y estar autorizado. No se acepta una URL arbitraria en cada operación.

Entregas y reintentos

Audiencia Método Ruta propuesta Uso Idempotencia Eventos o callbacks relacionados
Integración GET /v1/webhook-deliveries Listar intentos. No Ninguno
Integración GET /v1/webhook-deliveries/{delivery_id} Consultar intento. No Ninguno
Integración POST /v1/webhook-deliveries/{delivery_id}/retry Reintentar intento fallido. Obligatoria webhook.delivery_retried
Integración POST /v1/webhook-events/{event_id}/redeliver Reenviar evento a receptores seleccionados. Obligatoria webhook.event_redelivered

Solicitud enviada por YUPY

POST /webhooks/yupy HTTP/1.1
Content-Type: application/json
Yupy-Event-Id: evt_01JXYZ
Yupy-Timestamp: 1784567890
Yupy-Signature: v1=<HEX_SIGNATURE>
{
  "event_id": "evt_01JXYZ",
  "event_type": "payment.reconciled",
  "event_version": "1.0",
  "created_at": "2026-08-09T20:18:42-05:00",
  "data": {
    "payment_order_uid": "pay_01JXYZ",
    "external_transaction_id": "ORDER-10482",
    "status": "confirmed",
    "confirmed_at": "2026-08-09T20:18:42-05:00",
    "closed_at": "2026-08-09T20:18:42-05:00"
  }
}

payment_order_uid es la identidad canónica YUPY de la Payment Order y external_transaction_id conserva la correlación comercial con el sistema origen. payment.reconciled representa confirmación financiera normalizada por Reconciliation; por eso el ejemplo muestra una Payment Order terminal confirmed con confirmed_at y closed_at.

Eventos como payment.reported, payment.evidence_received o resultados de OCR son señales operativas/evidencia y no deben interpretarse como confirmación financiera por sí solos.

Evento de presentación de instrucciones

payment_instruction.presented registra que una instrucción de pago fue efectivamente presentada en el canal aplicable. No debe inferirse únicamente porque una entrega quedó encolada, enviada o recibida.

{
  "event_id": "evt_01JPRESENTED",
  "event_type": "payment_instruction.presented",
  "event_version": "1.0",
  "created_at": "2026-08-09T20:16:03-05:00",
  "data": {
    "payment_order_uid": "pay_01JXYZ",
    "external_transaction_id": "ORDER-10482",
    "presented_at": "2026-08-09T20:16:02-05:00",
    "delivery_channel": "web_checkout",
    "ack_type": "checkout_rendered",
    "external_reference": "ycs_01JXYZ"
  }
}

El catálogo público de webhooks no tiene que reproducir uno a uno todos los eventos del Event Log interno de YUPY. El Event Log puede ser más rico; únicamente los eventos definidos como públicos forman parte de este contrato de webhook.

Respuesta esperada

HTTP/1.1 200 OK
{
  "received": true
}

Firma propuesta

HMAC-SHA256(
  webhook_secret,
  timestamp + "." + raw_body
)

La firma se valida sobre el cuerpo original. Los nombres de headers y la tolerancia temporal permanecen propuestos hasta implementación.

Idempotencia de recepción

event_id ya procesado
→ no repetir efectos comerciales
→ responder 200

El receptor debe deduplicar por event_id. Un reintento o redelivery del mismo evento no debe ejecutar dos veces el efecto comercial asociado.

Catálogo inicial de eventos

payment_instruction.presented
payment.reported
payment.evidence_received
payment.evidence_processed
payment.detected
payment.reconciled
payment.amount_difference
payment.ambiguous
payment.late_detected
payment.review_required
payment.cancelled
payment.supplemental_order_created
checkout.created
checkout.opened
checkout.expired
checkout.revoked
shift.opened
shift.expiring
shift.closed
shift.auto_closed
delivery.queued
delivery.sent
delivery.delivered
delivery.failed
claim.created
claim.evidence_received
claim.resolved
case.created
case.resolved
refund.identified
refund.requested
refund.approved
refund.rejected
refund.pending_execution
refund.execution_failed
refund.completed
refund.cancelled
report.queued
report.ready
report.failed

Callbacks relacionados con endpoints principales

Operación Eventos posibles
POST /v1/payment-orders payment.*, payment_instruction.presented, checkout.created, delivery.*
POST /v1/payment-orders/{id}/payment-reported payment.reported
POST /v1/payment-orders/{id}/evidence payment.evidence_received, payment.evidence_processed
POST /v1/payment-orders/{id}/cancel payment.cancelled
POST /v1/shifts shift.opened
POST /v1/shifts/{id}/close shift.closed
POST /v1/report-jobs report.queued, report.ready, report.failed
POST /v1/refund-cases/{id}/execution-attempts refund.completed o refund.execution_failed

Errores principales

HTTP Código Descripción
404 webhook_endpoint_not_found Receptor inexistente.
401 webhook_signature_invalid Firma inválida en el receptor.
401 webhook_timestamp_invalid Timestamp fuera de tolerancia.
404 webhook_delivery_not_found Intento inexistente.
409 webhook_retry_not_allowed El intento no puede repetirse.
422 webhook_url_invalid URL no válida o no autorizada.

Changelog — Payment Order / API Engine

2026-08-09 — Payment Order / API Engine v1.0: el payload de payment.reconciled pasó de la identidad histórica yupy_transaction_id/ypt_... a payment_order_uid/pay_...; se retiró el objeto histórico state.operational/financial del payload activo y se documentó la Payment Order terminal confirmed con confirmed_at y closed_at; se aclaró que payment.reported, evidencia y OCR no son confirmación financiera; se incorporó el evento público payment_instruction.presented con presented_at, delivery_channel, ack_type y external_reference; y se explicitó que el catálogo público de webhooks puede ser un subconjunto del Event Log interno.