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.
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.
| 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 |
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 |
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
descriptiony elerror.actionpiden lo mismo: puedes mostrar ladescriptiontal cual y decidir conactionsin que se contradigan.error.messagenombra la causa para tu log, no para el cliente.
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: nully ladescription«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
}
}'
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.
| 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 |
api. Retienen fondos reales; no hay simulación.
Responden MIT_PRODUCTION_KEY_REQUIRED. Ver
reserva de cupo.Antes de cambiar el token, comprueba que probaste lo que va a pasar de verdad:
Pendiente: que no lo trates como rechazo. Es el error más caro.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.