Modo test y sandbox#
El modo test no es un entorno aparte. Las claves pk_test_ y sk_test_ operan contra la misma
https://api.apipay.io, con el mismo código y los mismos endpoints. Lo que cambia es la partición de
los datos: todo lo que crea una clave de test nace con livemode: false y vive separado de lo real.
| Modo test | Modo live | |
|---|---|---|
| Claves | pk_test_… / sk_test_… | pk_live_… / sk_live_… |
| Base de la API | https://api.apipay.io | https://api.apipay.io |
livemode de los recursos | false | true |
| Pasarelas disponibles | las configuradas, más sandbox | solo las configuradas |
| Dinero | ninguno se mueve | se mueve de verdad |
| Endpoints de webhook | los de modo test | los de modo live |
Cómo saber en qué modo estás#
Tres señales, en orden de fiabilidad:
- El prefijo de la clave:
sk_test_frente ask_live_. - El campo
livemodede cualquier recurso que devuelva la API. - El campo
livemodedel envelope de cada webhook.
La pasarela sandbox#
sandbox es una implementación de pasarela que no llama a ningún proveedor externo: resultados
deterministas, inmediatos y gratuitos. Está en el catálogo como cualquier otra y se usa igual, con
gateway_id: "sandbox".
Escenarios por los dos últimos dígitos de amount_minor#
El comportamiento se elige con los dos últimos dígitos del monto. No hay datos mágicos adicionales, ni cabeceras especiales, ni tarjetas de prueba: cualquier SDK reproduce cualquier escenario eligiendo el número.
amount_minor termina en | Qué simula | Recorrido del intent |
|---|---|---|
00 (y cualquier otro no listado) | Aprobación inmediata | CREATED → PROCESSING → SUCCEEDED |
05 | Fondos insuficientes: el confirm devuelve 402 card_declined | CREATED → PROCESSING → FAILED |
13 | Timeout de pasarela: el confirm excede el timeout y un webhook simulado resuelve a los 60 s | CREATED → PROCESSING → FAILED |
42 | Requiere acción: redirect_url a una página del propio sandbox donde apruebas o rechazas | CREATED → REQUIRES_ACTION → PROCESSING → SUCCEEDED o FAILED |
En CLP, que tiene exponente 0, los dos últimos dígitos son pesos:
| Monto | Se lee | Escenario |
|---|---|---|
1499000 | $1.499.000 | 00 → aprueba |
1499005 | $1.499.005 | 05 → 402 card_declined |
1499013 | $1.499.013 | 13 → timeout, resuelve por webhook |
1499042 | $1.499.042 | 42 → REQUIRES_ACTION |
En una divisa con exponente 2 los dos últimos dígitos son los centavos: 105000 en USD son
$1050.00 y termina en 00, así que aprueba; 105005 son $1050.05 y se rechaza.
// Un escenario por monto. La misma llamada, distinto desenlace.
const escenarios = {
aprueba: 1499000,
rechaza: 1499005,
timeout: 1499013,
requiereAccion: 1499042,
} as const;
const created = await apipay.paymentIntents.create({
amount_minor: escenarios.timeout,
currency: 'CLP',
gateway_id: 'sandbox',
metadata: { escenario: 'gateway_timeout' },
});
const intent = await apipay.paymentIntents.confirm(created.id);
// intent.status === 'PROCESSING': el desenlace llega por webhook a los 60 s.Cómo reproducir cada error del catálogo#
| Quieres provocar | Cómo |
|---|---|
402 card_declined | monto acabado en 05 con gateway_id: "sandbox" |
409 invalid_state_transition | cancel sobre un intent ya SUCCEEDED |
409 idempotency_key_reuse | repetir una Idempotency-Key con un cuerpo distinto |
422 amount_exceeds_refundable | reembolsar más que el saldo del intent |
422 currency_not_supported | pedir una divisa que la pasarela no tiene habilitada para tu tenant |
401 invalid_api_key | una clave revocada, o una sk_live_ en el entorno de test |
404 resource_not_found | un pi_ de la partición contraria |
400 validation_error | gateway_id: "sandbox" con una clave sk_live_ |
El catálogo completo, con qué hacer ante cada uno, está en manejo de errores.
Disparar eventos de prueba desde el backoffice#
Desde admin.apipay.io, un TENANT_ADMIN puede enviar cualquier evento del catálogo
(payment_intent.succeeded, refund.failed, …) contra un endpoint de webhook de modo test.
Lo importante es que reutiliza el pipeline real: el evento se inserta en la bandeja de salida, viaja
por el mismo bus y lo entrega el mismo dispatcher, con firma ApiPay-Signature auténtica y
livemode: false en el envelope. No es una simulación de la entrega: es la entrega.
Sirve para validar de extremo a extremo, sin crear un pago:
- que tu verificación de firma funciona con el secreto que tienes desplegado,
- que tu deduplicación por
evt_aguanta la misma entrega dos veces, - que tu handler responde
2xxen el tiempo que debe, - que un
typeque tu código no conoce se ignora sin romper nada.
Tarjetas y datos de prueba de las pasarelas reales#
Cuando pruebes contra el ambiente de integración de una pasarela de verdad, los datos de prueba los publica el proveedor. Este portal no los copia, a propósito: esas tablas cambian y una copia desactualizada es peor que un enlace.
| Pasarela | Documentación oficial de datos de prueba |
|---|---|
| Transbank (Webpay Plus) | Cómo empezar · Transbank Developers (se abre en una pestaña nueva) — ambiente de integración y tarjetas |
| MercadoPago | Cuentas de prueba · MercadoPago Developers (se abre en una pestaña nueva) — usuarios de prueba y sandbox |
La única tabla de escenarios que ApiPay mantiene como propia es la de sandbox, que está más arriba.
Cada guía por pasarela explica lo específico de su ambiente de integración: Webpay, MercadoPago.
Colección Postman#
El portal publica una colección Postman generada en CI desde
contracts/openapi/payment-api.v1.yaml, con las variables baseUrl y apiKey ya definidas. Nunca se
edita a mano: se regenera con cada cambio del contrato, así que no puede quedar desalineada con la
referencia de API.
Antes de salir a live#
- Las claves salen de configuración de entorno, nunca del código ni del bundle del frontend.
- El proceso de producción usa
sk_live_y el de pruebassk_test_, y no hay forma de confundirlos: variables con nombres distintos, no un flag. -
gateway_id: "sandbox"no aparece en ninguna ruta de código que se ejecute en live. - Hay un endpoint de webhook por modo, cada uno con su propio
whsec_. - El handler de webhooks pasó las cuatro pruebas de la guía de webhooks: cuerpo
crudo, firma, deduplicación y
2xxrápido. - Probaste el escenario
13: tu integración no depende de que elconfirmdé el resultado. - Probaste
05y muestras un mensaje útil al pagador antecard_declined. - Persistes la
Idempotency-Keyde cadaPOSTde cobro y de reembolso. - Tienes un job de conciliación para intents que llevan demasiado tiempo en
PROCESSINGo enREQUIRES_ACTION. - La pasarela real está configurada en el tenant, con credenciales de producción y sus divisas habilitadas.
- Registras el
X-Request-Idde las respuestas de error: es lo que pide soporte.
Siguientes pasos#
- Webhooks: la guía que hay que leer antes de salir a live.
- Manejo de errores: los 17
codey qué hacer con cada uno. - Payment intents: la matriz de transiciones que siguen los escenarios.
- Quickstart: el recorrido completo en modo test, de cero a pago aprobado.