Checkout por API
Overview
Sección titulada «Overview»Este es el segundo paso de la modalidad api: procesar el pago con los datos que
capturaste en tu propio checkout.
Antes tienes que haber
generado el pago con
checkout_type: "api", que te devuelve un payment_id y un token. Ese par autentica
esta llamada.
1. POST /payment/generate-payment → { payment_id, token }2. POST /payment/transaction-checkout/{medio} ← estás aquíHay un endpoint por medio de pago:
| Medio | Endpoint |
|---|---|
| Tarjeta | POST /api/v1/payment/transaction-checkout/card |
| PSE | POST /api/v1/payment/transaction-checkout/pse |
| Bre-B | POST /api/v1/payment/transaction-checkout/bre-b |
| Efectivo | POST /api/v1/payment/transaction-checkout/cash |
Si necesitas probar el alias tal cual, recibe exactamente lo mismo que /card:
Todos los endpoints comparten el bloque payment, un bloque customer_payer y, cuando
tu cobro lo pide, la dirección de envío. Después cada medio agrega el suyo.
Un intento por cobro
Sección titulada «Un intento por cobro»Cada payment_id admite un solo intento de transacción. El body de la petición no
cambia; lo que cambia es que no puedes volver a cobrar el mismo payment_id después de
esa primera transacción.
El payment_id y el token que recibiste en
generate-payment sirven para una
transacción. Aplica a tarjeta, PSE, efectivo y Bre-B. El estado de esa transacción no
abre un segundo intento.
Si el pago es rechazado y quieres reintentar, genera un cobro nuevo con
/api/v1/payment/generate-payment y usa el nuevo payment_id + token.
Decide con error.code, no con el texto ni solo con el HTTP. Todos los errores traen el
objeto error:
| HTTP | error.code |
Cuándo | Qué hacer |
|---|---|---|---|
403 |
payment_already_used |
El cobro ya tiene una transacción (cualquier estado, también si ya se pagó) | Crear un cobro nuevo. No reuses el mismo payment_id |
403 |
payment_already_paid |
El cobro ya fue pagado | No cobrar de nuevo |
403 |
payment_in_progress |
Tiene transacciones en progreso que agotan su límite | Esperar el resultado |
403 |
payment_expired |
Pasó la fecha límite del cobro | Crear un cobro nuevo |
403 |
payment_inactive |
El cobro fue desactivado | Crear un cobro nuevo |
403 |
invalid_payment_credentials |
El payment.id o el payment.token no son válidos. Mismo código en ambos casos, para no revelar qué ids existen |
Revisar el par guardado |
422 |
validation_failed |
Validación: el body está incompleto o inválido | Corregir el body y repetir el mismo cobro |
429 |
payment_in_progress |
Hay otra petición en curso para este cobro | Esperar y repetir el mismo cobro |
Ejemplo de respuesta cuando el cobro ya se usó:
403Forbidden{ "message": "Este cobro ya tiene una transacción y no permite reintentos", "error": { "type": "invalid_request_error", "code": "payment_already_used", "message": "Este cobro ya tiene una transacción y no permite reintentos", "param": "payment.id" }}Parámetros del pago
Sección titulada «Parámetros del pago»| Nombre del campo | Descripción | Reglas |
|---|---|---|
| payment | Objeto con las credenciales del pago generado en modalidad api |
['required'] |
| payment.id | El payment_id que devolvió generar el pago |
['required', 'string'] |
| payment.token | El token que devolvió generar el pago. Solo se muestra una vez |
['required', 'string'] |
Parámetros del cliente
Sección titulada «Parámetros del cliente»| Nombre del campo | Descripción | Reglas |
|---|---|---|
| customer_payer | Datos de quien paga | ['required'] |
| customer_payer.name | Nombre de quien paga. En efectivo el mínimo baja a 2 caracteres | ['required', 'string', 'min:5', 'max:255'] |
| customer_payer.email | Correo de quien paga. Solo se aceptan caracteres alfanuméricos | ['required', 'email'] |
Los siguientes solo aplican al pago con tarjeta:
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| customer_payer.address_1 | Dirección principal | ['required', 'string', 'min:5', 'max:100'] |
| customer_payer.address_2 | Dirección secundaria | ['required', 'string', 'min:1', 'max:100'] |
| customer_payer.city | Ciudad | ['required', 'string', 'min:1', 'max:100'] |
| customer_payer.state | Departamento o estado | ['required', 'string', 'min:1', 'max:100'] |
| customer_payer.zip_code | Código postal | ['required', 'numeric', 'digits_between:1,10'] |
| customer_payer.country | País en ISO3. Ver lista de países | ['required', 'string', 'in:COL,USA,MEX,...'] |
| customer_payer.identification_type | Tipo de documento. Ver enumeraciones | ['nullable', 'in:CC,CE,TI,PPT,DNI,NIT,Pasaporte,Otro'] |
| customer_payer.id_number | Número de documento. Con NIT debe llevar dígito de verificación (900123456-7). No puede ser un número de tarjeta |
['nullable', 'digits_between:5,15'] |
| customer_payer.dialling_code | Indicativo telefónico con +. Obligatorio salvo que envíes payment_card.cellphone |
['required', 'regex:/^\+\d{1,3}$/i'] |
| customer_payer.cellphone | Celular, solo dígitos. Obligatorio salvo que envíes payment_card.cellphone |
['required', 'numeric', 'digits_between:5,15'] |
Dirección de envío
Sección titulada «Dirección de envío»Si el pago generado se configuró con “advance_options” y existe request_address_delivery se requerirá la siguiente información, de lo contrario no necesita enviarse.
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| delivery_address | Objeto con la dirección de envío | ['required'] |
| delivery_address.address | Dirección de entrega | ['required_with:delivery_address', 'string', 'min:5', 'max:100'] |
| delivery_address.department_id | Id de la lista de departamentos | ['required_with:delivery_address', 'exists:departments,id'] |
| delivery_address.city_id | Id de la lista de ciudades | ['required_with:delivery_address', 'exists:cities,id'] |
| delivery_address.observations | Indicaciones para la entrega | ['nullable'] |
Pago con tarjeta
Sección titulada «Pago con tarjeta»Parámetros de la tarjeta
Sección titulada «Parámetros de la tarjeta»Adicional a los parámetros anteriores se deben agregar los siguientes:
Puedes pagar de dos formas, y son excluyentes: o envías los datos de la tarjeta, o
envías un token de una tarjeta ya guardada. Si mandas token junto con number,
name, expiration_date o cvv, la petición se rechaza.
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| payment_card | Objeto con los datos de la tarjeta | ['required'] |
| payment_card.token | Token de una tarjeta guardada con el tokenizador. Si lo envías, no envíes ningún otro dato de la tarjeta | ['sometimes', 'missing_with:payment_card.number,payment_card.name,payment_card.expiration_date,payment_card.cvv'] |
| payment_card.number | Número de la tarjeta, sin espacios. La franquicia debe estar habilitada en tu comercio | ['required', 'missing_with:payment_card.token', 'numeric', 'digits_between:14,16'] |
| payment_card.name | Nombre impreso en la tarjeta. Solo letras y espacios | ['required', 'missing_with:payment_card.token', 'string'] |
| payment_card.expiration_date | Vencimiento en formato YYYY-MM, con mes entre 01 y 12. No puede estar vencida |
['required', 'missing_with:payment_card.token', 'date_format:Y-m', 'after_or_equal:<mes actual>'] |
| payment_card.cvv | Código de seguridad de 3 o 4 dígitos | ['required', 'missing_with:payment_card.token', 'regex:/^\d{3,4}$/i'] |
| payment_card.installments | Número de cuotas | ['required', 'integer', 'between:1,60'] |
| payment_card.identification_type | Tipo de documento del tarjetahabiente. Ver enumeraciones | ['nullable', 'in:CC,CE,TI,PPT,DNI,NIT,Pasaporte,Otro'] |
| payment_card.id_number | Número de documento del tarjetahabiente. No puede ser un número de tarjeta | ['nullable', 'numeric', 'digits_between:5,15'] |
| payment_card.dialling_code | Indicativo telefónico con +. Obligatorio salvo que envíes customer_payer.cellphone |
['required', 'regex:/^\+\d{1,3}$/i'] |
| payment_card.cellphone | Celular, solo dígitos. Obligatorio salvo que envíes customer_payer.cellphone |
['required', 'numeric', 'digits_between:5,15'] |
| payment_card.redirect_url | A dónde vuelve el cliente tras el iframe de 3DS. Debe ser una URL que responda | ['nullable', 'url', 'active_url', 'max:500'] |
Información del navegador
Sección titulada «Información del navegador»Puedes enviar datos del navegador de tu cliente. Normalmente son opcionales y sirven
para el antifraude, pero si activas 3D Secure con enable_3ds: true siete de ellos
pasan a ser obligatorios, porque la red los exige para autenticar.
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| enable_3ds | Activa la autenticación 3D Secure para este pago | ['sometimes', 'nullable', 'boolean'] |
| browser_information | Objeto con la información del navegador del cliente | ['required_if:enable_3ds,true'] |
| browser_information.colorDepth | Profundidad de color de la pantalla, por ejemplo "24" |
['required_if:enable_3ds,true', 'string', 'max:5'] |
| browser_information.language | Idioma del navegador, por ejemplo "es-CO" |
['required_if:enable_3ds,true', 'string', 'max:10'] |
| browser_information.screenHeight | Alto de la pantalla en píxeles | ['required_if:enable_3ds,true', 'numeric'] |
| browser_information.screenWidth | Ancho de la pantalla en píxeles | ['required_if:enable_3ds,true', 'numeric'] |
| browser_information.timeDifference | Diferencia horaria con UTC en minutos, la que devuelve getTimezoneOffset() |
['required_if:enable_3ds,true', 'numeric'] |
| browser_information.javaScriptEnabled | Si el navegador tiene JavaScript activo | ['required_if:enable_3ds,true', 'boolean'] |
| browser_information.javaEnabled | Si el navegador tiene Java activo | ['required_if:enable_3ds,true', 'boolean'] |
| browser_information.acceptLanguage | Preferencias de idioma del navegador, por ejemplo "en-US" |
['nullable', 'string', 'max:10'] |
| browser_information.ipAddress | IP del cliente que hace la solicitud | ['nullable', 'ip'] |
| browser_information.sessionId | Identificador único de la sesión del usuario | ['nullable', 'string', 'max:255'] |
| browser_information.userAgent | Navegador y sistema operativo del usuario | ['nullable', 'string', 'max:255'] |
Ejemplo y respuesta
Sección titulada «Ejemplo y respuesta»Ejemplo de solicitud sin token:
curl -X POST \"/api/v1/payment/transaction-checkout" \-H 'Authorization: Bearer ACCESS_TOKEN' \-H "Content-type: application/json" \-d '{ "payment": { "id": "9a6f8166-644e-4680-bc37-66535e591ea5", "token": "1rV9zc9DApoOw3a" }, "customer_payer": { "name": "Efipay", "email": "efipay@gmail.com" }, "payment_card": { "number": "5249314023340339", "name": "efipay", "expiration_date": "2025-05", "cvv": "478", "identification_type": "CC", "id_number": "342343243", "installments": "1", "dialling_code": "57", "cellphone": "3004564884" }, "browser_information": { "acceptLanguage": "es-ES", "ipAddress": "190.150.0.1", "sessionId": "dfds54fds534sd534dsds", "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" }}'Ejemplo de solicitud con token:
curl -X POST\'/api/v1/payment/transaction-checkout/card'\-H 'Authorization: Bearer ACCESS_TOKEN' \-H "Content-type: application/json" \-d '{ "payment": { "id": "9abca90d-978d-4722-891f-b41b6ebbae1e", "token": "quSOdCbSljI31wT" }, "customer_payer": { "name": "Efipay", "email": "email@email.com" }, "payment_card": { "token": "eyJpdiI6IkdzaG44RFV5dE5GNlE2MWRSM2lBTGc9PSIsInZhbHVlIjoiZWxyRzkyYTE4THNtY2VseCs5VzlKbW5pa0NicCtiRWhGNWQ5ZTBwTGM1VXF0UXlEemtVWEJyY21ueVIwZ2U5cHNGS2FvdFg1SHVTcmtiQ0phQWNia1JsTUZtQjU3OFpCR0p3bVVlTy9OVVMwM3hJNnJOWGZTbitwL3dlVmtmRStRN2xBZ3paWHI4bDFS N0lBVHhRa2hBPT0iLCJtYWMiOiJlNDY0NmM4YThhNWMzMDYyOGMxNDAxMjA5MmVlMjNjYjNiYWEyMjczNjA5ZGNkMzM0NmMxMzg0YjZhYjgyY2ZhIiwidGFnIjoiIn0=", "identification_type": "CC", "id_number": "342343243", "installments": "1", "dialling_code": "57", "cellphone": "3004564884" }}'Respuestas
Sección titulada «Respuestas»{ "transaction_id": 20481, "status": "Aprobada", "status_key": "approved", "response_code": "00", "error": null, "amount": 50000, "currency_type": "COP", "value_cop": 50000, "tax": 7983, "payment_method": "credit", "payment_method_source": "Visa", "card": { "franchise": "Visa", "bin": "453210", "last_four": "7890" }, "authorization_code": "005077", "trazability_id": "320000303129", "url_response": "https://sag.efipay.co/Checkout/Transaction/9af329f1-e96a-40ab-b466-94a412f12c4a/Response", "approved_at": "2026-07-31T14:32:10.000000Z", "description": "Aprobada", "save": true, "payment_id": "9af329f1-e96a-40ab-b466-94a412f12c4a", "transaction": { "…": "mismos campos de la raíz" }}{ "transaction_id": 20482, "status": "Rechazada", "status_key": "rejected", "response_code": "51", "error": { "code": "51", "message": "Transacción declinada. Fondos insuficientes", "retryable": false, "action": "contact_issuer" }, "amount": 50000, "payment_method": "credit", "payment_method_source": "Visa", "card": { "franchise": "Visa", "bin": "453210", "last_four": "7890" }, "authorization_code": null, "description": "Transacción declinada. Fondos insuficientes", "save": true, "payment_id": "9af329f1-e96a-40ab-b466-94a412f12c4a", "transaction": { "…": "mismos campos de la raíz" }}Cómo decidir sobre la respuesta
Sección titulada «Cómo decidir sobre la respuesta»| Campo | Tipo | Para qué |
|---|---|---|
status |
string | Estado en español (Aprobada, Rechazada, Pendiente…). Para mostrar |
status_key |
string | Clave estable en inglés. Para decidir en tu código |
response_code |
string | null | Código crudo de la red (00, 05, 51, M12…). Es el que hay que citarnos en un soporte |
error |
objeto | null | null si se aprobó. Si no, {code, message, retryable, action} |
error.retryable |
bool | Si tiene sentido volver a intentar. false en fondos insuficientes, tarjeta vencida y fraude |
tax |
número | null | Impuesto de la transacción, para cuadrar tu factura |
card |
objeto | null | {franchise, bin, last_four}, ya separados |
payment_id |
uuid | El cobro al que pertenece. Sirve de correlación si falta transaction_id |
Valores de status_key: approved, rejected, failed, pending, started,
for_pay, cancelled, reversed, escalated_reversal, authorized.
{ "message": "El campo payment_card.cvv es obligatorio.", "errors": { "payment_card.cvv": ["El campo payment_card.cvv es obligatorio."] }, "error": { "type": "invalid_request_error", "code": "validation_failed", "message": "El campo payment_card.cvv es obligatorio.", "param": "payment_card.cvv" }}{ "message": "El id o el token del cobro no son válidos.", "error": { "type": "authorization_error", "code": "invalid_payment_credentials", "message": "El id o el token del cobro no son válidos.", "param": "payment.token" }}Si el par es válido pero el cobro ya no admite pagos, el error.code dice por qué
(payment_already_used, payment_expired…). Ver
Un intento por cobro.
Si activaste 3D Secure, la respuesta no es ninguna de estas: es la instrucción para continuar la autenticación. Sigue con 3D Secure.
3D Secure
Sección titulada «3D Secure»Para implementar el flujo de 3Ds mediante api se requiere que el comercio realice el desarrollo del flujo para estos casos. Como aclaración se debe tener en cuenta que se tienen dos implementaciones diferentes según la franquicia que de la tarjeta, a continuación se explicaran con detalle ambos casos.
Para habilitar 3Ds en transacciones con Visa y Mastercard adiciona el atributo enable_3ds, y junto a él la información del navegador del cliente en browser_information.
Ver flujo 3Ds
Los campos exactos y sus reglas están en
Información del navegador: con enable_3ds: true, siete campos de
browser_information pasan a ser obligatorios.
Par obtener la información del navegador puedes usar esta función para javascript
function getBrowserInformation() { // Get color depth const colorDepth = window.screen.colorDepth; // Check if JavaScript is enabled (if this runs, JavaScript is enabled) const jsEnabled = true; let javaEnabled = false; try { javaEnabled = navigator.javaEnabled(); } catch (error) { const javaEnabled = false; } // Get browser language const language = navigator.language || navigator.userLanguage; // Get screen height and width const screenHeight = window.innerHeight; const screenWidth = window.innerWidth; // Calculate time difference from UTC (in hours) const timeDifference = new Date().getTimezoneOffset();
return { colorDepth, language, screenHeight, screenWidth, timeDifference, javaScriptEnabled: jsEnabled, javaEnabled, }}Ejemplo compra con 3Ds habilitado
curl -X POST\'/api/v1/payment/transaction-checkout'\-H 'Authorization: Bearer ACCESS_TOKEN' \-H "Content-type: application/json" \-d '{ "payment": { "id": "9a6f8166-644e-4680-bc37-66535e591ea5", "token": "1rV9zc9DApoOw3a" }, "customer_payer": { "name": "Efipay", "email": "efipay@gmail.com" }, "payment_card": { "number": "5249314023340339", "name": "efipay", "expiration_date": "2025-05", "cvv": "478", "identification_type": "CC", "id_number": "342343243", "installments": "1", "dialling_code": "57", "cellphone": "3004564884" }, "browser_information": { "colorDepth": "24", "language": "es-ES", "screenHeight": 726, "screenWidth": 2133, "timeDifference": 300, "javaScriptEnabled": true, "javaEnabled": false }, "enable_3ds": true}'Flujo Visa (Credibanco)
Sección titulada «Flujo Visa (Credibanco)»1. Inicio de la autenticación 3DS
Sección titulada «1. Inicio de la autenticación 3DS»Al iniciar la trx se responderá con un objeto con información para continuar con el flujo de 3ds, el cual tendrá el nombre de la implementación, un código html para agregar en el navegador del cliente y una url para validar el éxito de la operación, en caso de que el objeto 3Ds no sea devuelto se devolverá el objeto con la transacción con su información del estado de la misma.
Ejemplo respuesta 3Ds para continuar con la autenticación.
{ "transaction_id": 1, "amount": 100000, "currency_type": "COP", "status": "Pendiente", "status_key": "pending", "response_code": null, "error": null, "description": "Transacción en proceso: Recolectando Data", "…": "resto de campos de la transacción, iguales a los de `transaction`", "save": true, "payment_id": "9e84d84b-e1e6-4a6a-a0eb-53becc71c359", "transaction": { "transaction_id": 1, "amount": 100000, "currency_type": "COP", "value_cop": 100000, "payment_method": "credit", "payment_method_source": "Credibanco", "trazability_id": null, "authorization_code": null, "transaction_details": { "name": "Efipay", "identification_type": "CC", "identification_number": "123456789", "email": "efipay@efipay.com", "country": "+57", "phone": "3001234567", "number_card": "123456******1234", "installments": "1", "franchise": "Credibanco", "status_message": "Transacción en proceso: Recolectando Data" }, "status": "Pendiente", "url_response": "https://sag.efipay.co/Checkout/Transaction/9e84d84b-e1e6-4a6a-a0eb-53becc71c359/Response", "approved_at": null, "production": true, "created_at": "2025-03-25 15:20:17", "customer_payer": { "name": "Efipay", "email": "efipay@efipay.com", "country": "COL", "zip_code": "0000", "state": "Bogota", "city": "Bogota", "address_2": "Cr 23", "address_1": "Apto 1A", "created_at": "2024-11-07 18:39:40", "updated_at": "2024-11-07 18:39:40" }, "currency_rate_conversion": { "id": 1, "usd_to_cop": 4288.58, "eur_to_cop": 4640.617049, "trm_for_cop": 1, "active": 1, "created_at": "2024-10-21T16:20:23.000000Z", "updated_at": "2024-10-21T16:20:23.000000Z", "deleted_at": null }, "description": "Transacción en proceso: Recolectando Data" }, "3Ds": { "implementation" : "credibanco", "browser_response" : "<div>...</div>", "centinelapistag" : "https://centinelapistag..." }}Recibida esta respuesta con la transacción pendiente y el objeto de 3Ds puedes tomar el siguiente ejemplo para implementar en tu navegador.
const setup3DsIframe = (browserResponse, centinelapistag) => { const wrappedElement = document.getElementById("hidden3ds"); wrappedElement.innerHTML = iframe;
const ddcForm = document.querySelector('#ddc-form'); if (ddcForm) { console.log('ddcForm', ddcForm); ddcForm.submit(); } let eventMessage3ds = false; const threeDsTimeOut = setTimeout(() => { if (!eventMessage3ds) { //rechazar transacción console.log('Error red demasiado tiempo esperando mensaje 3ds'); } }, 50000);
window.addEventListener("message", (event) => { eventMessage3ds = true; clearTimeout(threeDsTimeOut) if (event.origin === centinelapistag) { let data = JSON.parse(event.data); console.log('Merchant received a message:', data); if (data !== undefined && data.Status) { console.log('Songbird ran DF successfully'); enrollTransaction(); // Continuar con -> 2. Consumir el enroll 3Ds } else { //rechazar transacción console.log('Error evento de mensaje front status 3ds'); } } }, false);}2. Consumir el enroll 3DS
Sección titulada «2. Consumir el enroll 3DS»Cuando se obtenga la repuesta satisfactoria del evento se puede continuar con el consumo del enroll, aquí se pueden presentar dos casos, el primero en donde 3Ds determine la autenticación exitosa y se pueda procesar la transacción sin mas pasos, la segunda donde 3Ds determine hacer una validación adicional con un challenge para autenticar al tarjetahabiente
Para el primer caso se devolverá la transacción con su estado correspondiente a como es costumbre.
Para el caso donde se solicite el challenge se responderá con un nuevo objeto 3Ds así:
Recuerde que este flujo puede presentarse un challenge del banco que redirige al cliente a una nueva ventana para que el cliente pase el challenge por lo que si desea volver a ser redirigido automáticamente a una pagina de tu integración deberás configurar las opciones avanzadas con result_urls, adicional puede usar el webhook para obtener la respuesta en paralelo a su integración.
Request
POST /api/v1/payment/3ds/enroll/{transaction_id}
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| payment_card | Datos de la tarjeta a autenticar | ['required'] |
| payment_card.number | Número de la tarjeta, sin espacios | ['required', 'numeric', 'digits_between:12,20'] |
| payment_card.name | Nombre impreso en la tarjeta. Solo letras y espacios | ['required', 'string'] |
| payment_card.expiration_date | Vencimiento en formato YYYY-MM. No puede estar vencida |
['required', 'date'] |
| payment_card.cvv | Código de seguridad de 3 o 4 dígitos | ['required', 'numeric', 'digits_between:3,4'] |
| browser_information | Datos del navegador del cliente | ['required'] |
| browser_information.colorDepth | Profundidad de color de la pantalla | ['required', 'integer'] |
| browser_information.javaScriptEnabled | Si el navegador tiene JavaScript activo | ['required', 'boolean'] |
| browser_information.language | Idioma del navegador | ['required', 'string'] |
| browser_information.screenHeight | Alto de la pantalla en píxeles | ['required', 'numeric'] |
| browser_information.screenWidth | Ancho de la pantalla en píxeles | ['required', 'numeric'] |
| browser_information.timeDifference | Diferencia horaria con UTC en minutos | ['required', 'numeric'] |
| browser_information.ipAddress | IP del cliente | ['nullable', 'ip'] |
| browser_information.sessionId | Identificador de la sesión | ['nullable', 'string', 'max:255'] |
| browser_information.userAgent | Navegador y sistema operativo | ['nullable', 'string', 'max:255'] |
Cuerpo de ejemplo:
{ "payment_card": { "number": "4000000000001091", "name": "Efipay", "expiration_date": "2025-12", "cvv": "123" }, "browser_information": { "colorDepth": "24", "language": "es-ES", "screenHeight": 726, "screenWidth": 2133, "timeDifference": 300, "javaScriptEnabled": true }
}Response
{ "transaction": { "transaction_id": 20481, "status": "Pendiente" }, "3Ds": { "implementation": "credibanco", "browser_response": "<div id=\"3ds-form\">...</div>" }}transaction trae la transacción completa, igual que en un pago normal, pero en estado
Pendiente. Lo que tienes que usar es 3Ds.browser_response: es HTML que debes
insertar en tu página para que el banco muestre su reto al cliente.
Ejemplo cliente
const setup3dsChallenge = browserResponse => { const wrappedElement = document.getElementById("challenge3ds"); wrappedElement.innerHTML = iframe;
var stepUpForm = document.querySelector('#step-up-form'); if (stepUpForm) { stepUpForm.submit(); }}Tarjetas de prueba de 3DS
Sección titulada «Tarjetas de prueba de 3DS»| Versión de 3DS Tarjetas | Tarjetas Visa |
|---|---|
| “AUTHENTICATION_SUCCESSFUL” | 400000 00 0000 2701 |
| “AUTHENTICATION_FAILED” | 400000 00 0000 2925 |
| “PENDING_AUTHENTICATION” | 400000 00 0000 2503 |
PENDING_AUTHENTICATION “AUTHENTICATION_FAILED” |
400000 00 0000 2370 |
Flujo Mastercard (Redeban)
Sección titulada «Flujo Mastercard (Redeban)»1. Inicio de la autenticación 3DS
Sección titulada «1. Inicio de la autenticación 3DS»Al iniciar la trx se responderá con un objeto con información para continuar con el flujo de 3ds, el cual tendrá el nombre de la implementación, un código html para agregar en el navegador del cliente, en caso de que el objeto 3Ds no sea devuelto se devolverá el objeto con la transacción con su información del estado de la misma.
Ejemplo respuesta 3Ds para continuar con la autenticación.
{ "transaction_id": 1, "amount": 100000, "currency_type": "COP", "status": "Pendiente", "status_key": "pending", "response_code": null, "error": null, "description": "Transacción en proceso: Recolectando Data", "…": "resto de campos de la transacción, iguales a los de `transaction`", "save": true, "payment_id": "9e84d84b-e1e6-4a6a-a0eb-53becc71c359", "transaction": { "transaction_id": 1, "amount": 100000, "currency_type": "COP", "value_cop": 100000, "payment_method": "credit", "payment_method_source": "Credibanco", "trazability_id": null, "authorization_code": null, "transaction_details": { "name": "Efipay", "identification_type": "CC", "identification_number": "123456789", "email": "efipay@efipay.com", "country": "+57", "phone": "3001234567", "number_card": "123456******1234", "installments": "1", "franchise": "Credibanco", "status_message": "Transacción en proceso: Recolectando Data" }, "status": "Pendiente", "url_response": "https://sag.efipay.co/Checkout/Transaction/9e84d84b-e1e6-4a6a-a0eb-53becc71c359/Response", "approved_at": null, "production": true, "created_at": "2025-03-25 15:20:17", "customer_payer": { "name": "Efipay", "email": "efipay@efipay.com", "country": "COL", "zip_code": "0000", "state": "Bogota", "city": "Bogota", "address_2": "Cr 23", "address_1": "Apto 1A", "created_at": "2024-11-07 18:39:40", "updated_at": "2024-11-07 18:39:40" }, "currency_rate_conversion": { "id": 1, "usd_to_cop": 4288.58, "eur_to_cop": 4640.617049, "trm_for_cop": 1, "active": 1, "created_at": "2024-10-21T16:20:23.000000Z", "updated_at": "2024-10-21T16:20:23.000000Z", "deleted_at": null }, "description": "Transacción en proceso: Recolectando Data" }, "3Ds": { "implementation" : "redeban", "browser_response" : "<div>...</div>" }}Recibida esta respuesta con la transacción pendiente y el objeto de 3Ds puedes tomar el siguiente ejemplo para implementar en tu navegador.
const setup3DsIframe = iframe => { const wrappedElement = document.getElementById("hidden3ds"); wrappedElement.innerHTML = iframe; Array.from(wrappedElement.querySelectorAll("script")) .forEach( oldScriptEl => { const newScriptEl = document.createElement("script");
Array.from(oldScriptEl.attributes).forEach( attr => { newScriptEl.setAttribute(attr.name, attr.value) });
const scriptText = document.createTextNode(oldScriptEl.innerHTML); newScriptEl.appendChild(scriptText);
oldScriptEl.parentNode.replaceChild(newScriptEl, oldScriptEl); }); setTimeout(() => { console.log("run timeout 5sec"); authContinueTransaction();// Continuar con -> 2. Consumir el auth continue 3Ds }, 5000);}2. Consumir el auth continue 3DS
Sección titulada «2. Consumir el auth continue 3DS»Cuando se obtenga la repuesta satisfactoria del evento se puede continuar con el consumo del enroll, aquí se pueden presentar dos casos, el primero en donde 3Ds determine la autenticación exitosa y se pueda procesar la transacción sin mas pasos, la segunda donde 3Ds determine hacer una validación adicional con un challenge para autenticar al tarjetahabiente
Para el primer caso se devolverá la transacción con su estado correspondiente a como es costumbre.
Para el caso donde se solicite el challenge se responderá con un nuevo objeto 3Ds así:
Request
POST /api/v1/payment/3ds/auth-continue/{transaction_id}
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| payment_card | Datos de la tarjeta a autenticar | ['required'] |
| payment_card.number | Número de la tarjeta, sin espacios | ['required', 'numeric', 'digits_between:12,20'] |
| payment_card.name | Nombre impreso en la tarjeta. Solo letras y espacios | ['required', 'string'] |
| payment_card.expiration_date | Vencimiento en formato YYYY-MM, con mes entre 01 y 12. No puede estar vencida |
['required', 'date_format:Y-m', 'after_or_equal:<mes actual>'] |
| payment_card.cvv | Código de seguridad de 3 o 4 dígitos | ['required', 'numeric', 'digits_between:3,4'] |
Cuerpo de ejemplo:
{ "payment_card": { "number": "4000000000001091", "name": "Efipay", "expiration_date": "2025-12", "cvv": "123" }, "browser_information": { "colorDepth": "24", "language": "es-ES", "screenHeight": 726, "screenWidth": 2133, "timeDifference": 300, "javaScriptEnabled": true }
}Response
{ "transaction": { "transaction_id": 20481, "status": "Pendiente" }, "3Ds": { "implementation": "redeban", "browser_response": { "challenge_request": "iframe" } }}En Mastercard browser_response es un objeto y no HTML: te indica cómo montar el reto.
Ejemplo cliente
const setup3dsChallenge = browserResponse => { const wrappedElement = document.getElementById("challenge3ds"); wrappedElement.innerHTML = iframe;
Array.from(wrappedElement.querySelectorAll("script")) .forEach( oldScriptEl => { const newScriptEl = document.createElement("script");
Array.from(oldScriptEl.attributes).forEach( attr => { newScriptEl.setAttribute(attr.name, attr.value) });
const scriptText = document.createTextNode(oldScriptEl.innerHTML); newScriptEl.appendChild(scriptText);
oldScriptEl.parentNode.replaceChild(newScriptEl, oldScriptEl); });}| tarjeta | descripción | monto |
|---|---|---|
| 2221008123677736 | 3DS Challenge | 151 |
Abandonar la autenticación
Sección titulada «Abandonar la autenticación»POST /api/v1/payment/3ds/reject/{transaction}
Tu cliente puede cerrar el reto 3DS sin completarlo. Cuando eso pasa, la transacción se
queda en Pendiente y tu pedido queda colgado esperando algo que ya no va a llegar.
Llama a este endpoint para cerrarla como rechazada. El parámetro es el
transaction_id (el consecutivo) de la transacción que quedó pendiente.
curl -X POST \'/api/v1/payment/3ds/reject/20481' \-H 'Authorization: Bearer ACCESS_TOKEN' \-H "Content-type: application/json"{ "save": true, "transaction": { "transaction_id": 20481, "status": "Rechazada", "description": "Pago rechazado por el usuario en el proceso 3DS" }}Pago con PSE
Sección titulada «Pago con PSE»Parámetros de PSE
Sección titulada «Parámetros de PSE»Cuando realizes la petición recibirás una url a la cual deberás redireccionar al usuario para que pueda realizar el pago, cuando el usuario realize el pago en su banco y regrese al comercio sera redireccionado a uno de las siguientes opciones; a la url si agregaste el custom_redirect_url en este checkout si no al checkout de respuesta de efipay.
La validación del pago lo podrás hacer a través de nuestro webhook o consultando el status al ser redireccionado a una de tus url personalizadas de redirección.
Consulta la lista de bancos disponibles aquí. Consulta la lista de datos del formulario para pse aquí.
Adicional a los parámetros anteriores se deben agregar los siguientes:
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| pse | Objeto con los datos del pago PSE | ['required'] |
| pse.financialInstitutionCode | Código del banco, de la lista de bancos. El código 0 no es un banco válido, es el placeholder «Selecciona tu banco» |
['required', 'not_in:0', 'in:<códigos de la lista de bancos>'] |
| pse.userType | Tipo de usuario: natural o jurídico. Ver opciones disponibles | ['required', 'in:<tipos de usuario PSE>'] |
| pse.identificationType | Tipo de documento. Las opciones válidas dependen del userType que hayas enviado. Ver opciones disponibles |
['required', 'in:<tipos de identificación del userType>'] |
| pse.identificationNumber | Número de documento. No puede ser un número de tarjeta | ['required', 'numeric', 'digits_between:5,15'] |
| pse.fullName | Nombre de quien paga | ['required', 'string', 'min:5', 'max:64'] |
| pse.cellphoneNumber | Celular, exactamente 10 dígitos | ['required', 'numeric', 'digits:10'] |
| pse.address | Dirección de quien paga | ['required', 'string', 'min:5', 'max:64'] |
| pse.email | Correo de quien paga. Solo caracteres alfanuméricos | ['required', 'email', 'max:110'] |
| pse.redirect | A dónde vuelve el cliente después de pagar en su banco. Debe ser una URL que responda | ['nullable', 'url', 'active_url', 'max:191'] |
Ejemplo para PSE
Sección titulada «Ejemplo para PSE»curl -X POST\"/api/v1/payment/transaction-checkout/pse"\-H 'Authorization: Bearer ACCESS_TOKEN' \-H "Content-type: application/json" \-d '{ "payment": { "id": "generated_payment_id", //9a6f8166-644e-4680-bc37-66535e591ea5 "token": "token_payment" //1rV9zc9DApoOw3a }, "customer_payer": { "name": "Pepito perez", "email": "pepito@email.com" }, "pse": { "financialInstitutionCode": "0000", "userType": "person", "identificationType": "CedulaDeCiudadania", "identificationNumber": "123456789", "fullName": "Pepito Perez", "cellphoneNumber": "3123456789", "address": "calle 93 # 32", "email": "pepito@email.com", "redirect": "https://efipay.co/" }}'Pago con Bre-B
Sección titulada «Pago con Bre-B»Parámetros de Bre-B
Sección titulada «Parámetros de Bre-B»Iniciar una transacción con bre-b del pago generado con /generate-payment el cual creará un QR disponible por 30 minutos para que el usuario pueda concluir la trasacción en su aplicación bancaria
Es necesario implementar el webhook para recibir el resultado final de la transacción una vez se concluya, adicionalmete podra hacer uso del api de status para consultar el estado de la transacción.
Adicional a los parámetros anteriores se deben agregar los siguientes:
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| breb | Objeto con los datos del pago Bre-B | ['required'] |
| breb.cellphone_number | Celular de quien paga, exactamente 10 dígitos | ['required', 'numeric', 'digits:10'] |
Ejemplo para Bre-B
Sección titulada «Ejemplo para Bre-B»curl -X POST\"/api/v1/payment/transaction-checkout/bre-b"\-H 'Authorization: Bearer ACCESS_TOKEN' \-H "Content-type: application/json" \-d '{ "payment": { "id": "generated_payment_id", //9a6f8166-644e-4680-bc37-66535e591ea5 "token": "token_payment" //1rV9zc9DApoOw3a }, "customer_payer": { "name": "Pepito perez", "email": "pepito@email.com" }, "breb": { "cellphone_number": "3123456789", }}'Respuesta
{ "transaction_id": 20481, "status": "Pendiente", "status_key": "pending", "…": "resto de campos de la transacción", "save": true, "payment_id": "9a6f8166-644e-4680-bc37-66535e591ea5", "transaction": { "…": "mismos campos de la raíz" }, "qr_breb": { "qr_code_data": "00020101021226580014CO.COM.BREB...", "qr_code_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", "expiration_date": "2026-04-23 10:43:42" }}| Campo | Qué es |
|---|---|
| qr_code_data | La cadena del QR. Genera tú la imagen, o imprímela |
| qr_code_image | La misma imagen ya generada, en base64, si prefieres mostrarla directo |
| expiration_date | El QR vence a los 30 minutos. Después hay que generar otro |
Pago en efectivo
Sección titulada «Pago en efectivo»Parámetros de efectivo
Sección titulada «Parámetros de efectivo»Ten presente que al usar este checkout para pagos en efectivos al realizar la petición todas las transacciones darán como respuesta el estado por pagar, y la información del cupón para que tu usuario realize el pago en la sucursal de efectivo correspondiente.
Para poder validar el pago de este tipo de transacciones te ofrecemos dos opciones; la primera y más sencilla usar nuestro webhook para notificarte la nueva información sobre las transacciones y la segunda es que realices una consulta del estado del pago después del tiempo de expiración que también te proporcionamos en la respuesta.
Podrás consultar la lista de efectivos disponibles para ti aquí
Adicional a los parámetros anteriores se deben agregar los siguientes:
| Nombre del campo | Descripción | Reglas |
|---|---|---|
| cash.franchise | Nombre del punto de recaudo, de la lista de efectivos. Debe estar habilitado en tu comercio | ['required', 'string'] |
| cash.cellphone_number | Celular de quien paga, entre 6 y 10 dígitos | ['required', 'numeric', 'min_digits:6', 'max_digits:10'] |
| cash.identification_number | Número de documento de quien paga. No puede ser un número de tarjeta | ['required', 'numeric', 'digits_between:5,15'] |
Ejemplo para efectivo
Sección titulada «Ejemplo para efectivo»curl -X POST\"/api/v1/payment/transaction-checkout/cash" \-H 'Authorization: Bearer ACCESS_TOKEN' \-H 'Content-type: application/json' \-d '{ 'payment': { 'id': 'generated_payment_id', 'token': 'token_payment' }, 'customer_payer': { 'name': 'Pepito peres', 'email': 'pepito@gmail.com' }, "cash" : { "franchise": "Efecty", "cellphone_number": "3123456789", "identification_number": "123456789" }}'