Ambiente de pruebas


Cómo funciona el modo prueba

Con un token de prueba nada se envía a la red de pagos: el resultado del pago lo decides tú, eligiendo qué tarjeta usas. Todo lo demás se comporta igual que en producción — se crea la transacción, se guarda el detalle, se dispara el webhook, aparece en tu reporte — solo que no hay dinero de por medio.

Eso te deja probar el camino completo, incluido el manejo de rechazos, que es la mitad del trabajo de una integración y la que nadie prueba.

{info} No hay una URL distinta para pruebas. Es la misma API; el token decide el ambiente.

Tarjetas de prueba

El resultado depende del par número + CVV. Si mandas un número de esta lista con otro CVV, la transacción sale como tarjeta no registrada (ver abajo).

Cualquier fecha de vencimiento futura sirve.

Aprueban

Franquicia Número CVV
Mastercard 5249 3140 2334 0339 478
Visa 4485 9021 7887 7927 963
American Express 3402 564352 97046 4405
Diners Club 3013 190041 2377 870

Rechazan (rechazo genérico)

Devuelven response_code: "05", el rechazo genérico del emisor, con error.action: "contact_issuer", retryable: false y la description «Tu banco no autorizó el pago. Comunícate con tu banco o usa otro medio de pago.».

Franquicia Número CVV
Mastercard 5163 8852 8716 0861 705
Visa 4315 8923 8199 8014 950
American Express 3723 190710 51332 7048
Diners Club 3000 614052 3128 725

Rechazan por causal

Para probar cómo reacciona tu integración a cada motivo de rechazo. Todas son Visa, con CVV 123 y cualquier vencimiento futuro, y quedan en estado Rechazada.

Número response_code Causal description retryable action
4000 0000 0000 9995 51 Fondos insuficientes Transacción declinada. Fondos insuficientes false contact_issuer
4000 0000 0000 0069 54 Tarjeta vencida Tu tarjeta está vencida. Usa otra tarjeta. false use_another_card
4000 0000 0000 0127 98 CVV incorrecto El código de seguridad (CVV) es incorrecto. Verifica los datos de la tarjeta. false check_card_data
4000 0000 0000 9987 43 Tarjeta bloqueada por el emisor Esta tarjeta está bloqueada. Usa otra tarjeta. false use_another_card
4000 0000 0000 0119 91 Emisor no disponible (error de red) Tu banco no respondió. Intenta de nuevo en unos minutos. true retry_later

{info} En todas las tarjetas de causal (y en las de rechazo genérico) la description y el error.action piden lo mismo: puedes mostrar la description tal cual y decidir con action sin que se contradigan. error.message nombra la causa para tu log, no para el cliente.

Qué devuelve un rechazo

Un rechazo en pruebas tiene exactamente la forma de producción: status, status_key, response_code, el objeto error y una description pensada para el tarjetahabiente. Así el código que escribes contra el sandbox es el mismo que corre en producción.

{
    "transaction_id": 20482,
    "status": "Rechazada",
    "status_key": "rejected",
    "response_code": "98",
    "error": {
        "code": "98",
        "message": "Transacción declinada. CVV inválido.",
        "retryable": false,
        "action": "check_card_data"
    },
    "description": "El código de seguridad (CVV) es incorrecto. Verifica los datos de la tarjeta.",
    "…": "resto de campos de la transacción",
    "save": true,
    "payment_id": "EL_PAYMENT_ID",
    "transaction": { "…": "mismos campos de la raíz" }
}

Los campos de decisión están en la raíz y también en transaction; lee status_key en la raíz. Ver la respuesta del checkout.

El mismo objeto error llega en los webhooks de transacción y, en suscripciones, dentro de transaction.error del webhook retry. Los valores de action y cuándo retryable es true están en Códigos de error.

{warning} Cualquier otra tarjeta —incluida una tarjeta real— o un número de la lista con otro CVV no se aprueba en modo prueba. Responde status_key: "failed", response_code: null, error: null y la description «Tarjeta no registrada en el ambiente de pruebas». No es un error de tu integración.

Ejemplo de un cobro que aprueba:

curl -X POST \
'/api/v1/payment/transaction-checkout/card' \
-H 'Authorization: Bearer TU_TOKEN_DE_PRUEBA' \
-H 'Content-type: application/json' \
-d '{
    "payment": { "id": "EL_PAYMENT_ID", "token": "EL_TOKEN" },
    "customer_payer": { "...": "..." },
    "payment_card": {
        "number": "4485902178877927",
        "name": "ANA GOMEZ",
        "expiration_date": "2030-12",
        "cvv": "963",
        "installments": 1
    }
}'

3D Secure en pruebas

El flujo de 3D Secure tiene sus propias tarjetas, porque lo que se prueba no es la aprobación sino el resultado de la autenticación: que tu integración sepa qué hacer cuando el banco pide un reto, y cuando el cliente lo abandona.

Están documentadas en la sección de 3DS del checkout.

Otros medios de pago

Medio En modo prueba
Tarjeta Resultado según la tarjeta de la lista
PSE Se genera la redirección; el banco de pruebas te deja elegir el resultado
Efectivo Se genera el cupón. Nadie lo paga, así que la transacción queda en Por Pagar
Bre-B / Nequi / DaviPlata Se genera la solicitud; el pago no se confirma

Qué no se puede probar

  • Reservas de cupo en modalidad api. Retienen fondos reales; no hay simulación. Responden MIT_PRODUCTION_KEY_REQUIRED. Ver reserva de cupo.
  • Abonos a tu cuenta virtual. Una transacción de prueba nunca genera saldo, así que tampoco hay transferencias que consultar.
  • Reversiones y anulaciones reales. Existen contra la red, no contra el simulador.

Lista de verificación antes de producción

Antes de cambiar el token, comprueba que probaste lo que va a pasar de verdad:

  • [ ] Un pago aprobado de punta a punta, con el webhook recibido y procesado.
  • [ ] Un pago rechazado, y que tu sistema no deja el pedido colgado.
  • [ ] El estado Pendiente: que no lo trates como rechazo. Es el error más caro.
  • [ ] La verificación de la firma del webhook, rechazando un cuerpo alterado.
  • [ ] Un webhook repetido: reintentamos, así que tu endpoint tiene que ser idempotente.
  • [ ] La consulta de estado como respaldo, para cuando el webhook no llegue.
  • [ ] Que guardas nuestro transaction_id junto a tu pedido, para poder conciliar.

{success} Cuando cambies al token de producción no tienes que cambiar ninguna URL ni ningún campo: solo el token.