Saltar al contenido principal

Preautorización & Captura

Preautorización

La preautorización, también conocida como "autorización previa" o "bloqueo de fondos", es una etapa crucial en el procesamiento de transacciones. Durante esta fase, se verifica la disponibilidad de fondos en la cuenta del titular de la tarjeta antes de completar la transacción. Su objetivo principal es reservar una cierta cantidad de fondos en la cuenta del titular para asegurarse de que haya suficiente saldo disponible para cubrir la transacción futura.

La preautorización se utiliza ampliamente en situaciones en las que es necesario garantizar la disponibilidad de fondos antes de entregar un producto o servicio. Por ejemplo, en el comercio electrónico, se puede utilizar para asegurarse de que el saldo de la tarjeta sea suficiente antes de realizar un envío o realizar una reserva.

Implementación de la Preautorización

Requisitos previos

Antes de comenzar con la implementación de la preautorización, asegúrate de contar con los siguientes requisitos:

Paso 1. Genera un token de aceptación.

Paso 2. Tokeniza el medio de pago (Tarjeta).

Paso 3. Antes de crear la preautorización, tener en cuenta lo siguiente:

  1. Podemos crear una fuente de pago para que los datos del tarjetahabiente queden listos para preautorizaciones o pagos futuros. Ver proceso.

  2. Omitir la creación de la fuente de pago e ir directamente a crear la preautorización. Ver proceso.

Paso 4. Recuerda que para crear la preautorizacion se requiere el uso de tu llave privada el cual debes enviar como Bearer token:

  1. Si quieres crear una preautorización con una fuente de pago, debes generar nuevamente un token de aceptación y hacer una petición POST /payment_sources con el siguiente cuerpo JSON:
{
"type": "CARD",
"payment_source_id": 297, // ID de la fuente de pago
"customer_email": "prueba@test.com", // Email del tarjetahabiente
"financial_operation": "PREAUTHORIZATION",
"acceptance_token": "acceptance_token", // Token de aceptación
"data": {
"amount_in_cents": 100, // Monto de la preautorización
"currency": "USD"
}
}
  1. Si por el contrario quieres crear una preautorización directamente deberás hacer una petición POST /payment_sources con el siguiente cuerpo JSON:
{
"type": "CARD",
"customer_email": "prueba@test.com", // Email del tarjetahabiente
"financial_operation": "PREAUTHORIZATION",
"token": "token_card", // ID de la tarjeta que tokenizaste
"acceptance_token": "acceptance_token", // Token de aceptacion
"data": {
"amount_in_cents": 100, // Monto de la preautorización
"currency": "USD"
}
}

Obtendremos de vuelta el siguiente JSON:

{
"data": {
"id": 335,
"public_data": {
"type": "CARD",
"financial_operation": "PREAUTHORIZATION",
"amount_in_cents": 100,
"number_of_installments": 1,
"currency": "USD"
},
"token": "tok_devtest_196_8A7308f20c2d236f42252972390b4eb1",
"type": "CARD",
"status": "PROCESSING",
"customer_email": "prueba@test.com"
}
}

⚠️ IMPORTANTE: El status PROCESSING significa que Wompi está preparando el flujo 3DS. No es un estado final. Se debe iniciar polling inmediatamente. El status cambiará a PENDING únicamente cuando la transacción entra en el flujo de autenticación 3DS (es decir, cuando Wompi tiene lista la data del iframe para que el frontend la renderice).

Flujo de estados de la preautorización
  • PROCESSING → Wompi está preparando 3DS. Iniciar polling.
  • PENDING + three_ds_auth → Hay un iframe 3DS que renderizar (ver Paso 6).
  • AVAILABLE → Preautorización exitosa, lista para captura.
  • DECLINED / ERROR → Preautorización fallida.

Paso 5. Realizar consultas periódicas para verificar el estado de la preautorización y asegurarnos de su correcta ejecución:

Para consultar la preautorización debemos hacer una petición GET /payment_sources/:id sin olvidarnos de enviar la llave privada como Bearer token.

Hacer polling cada 3 segundos. Cuando el status cambia a PENDING, la respuesta incluye la data de 3DS.

A continuación, te brindamos ejemplos de cómo implementar la lógica de long polling para preautorizaciones:

Cargando ejemplos...


Tendremos de vuelta el siguiente JSON:

{
"data": {
"id": 335,
"public_data": {
"type": "CARD",
"financial_operation": "PREAUTHORIZATION",
"amount_in_cents": 100,
"number_of_installments": 1,
"currency": "USD"
},
"token": "tok_devtest_196_8A7308f20c2d236f42252972390b4eb1",
"type": "CARD",
"status": "PENDING",
"customer_email": "jmtm141097@gmail.com",
"extra": {
"three_ds_auth": {
"current_step": "BROWSER_INFO", // Hace referencia al tipo de autenticación: (BROWSER_INFO - CHALLENGE)
"current_step_status": "PENDING",
"three_ds_method_data": "<iframe id="tdsMmethodTgtFrame" name="tdsMmethodTgtFrame" style="visibility: hidden; width: 1px; height: 1px;" xmlns="http://www.w3.org/1999/xhtml"><!--.--></iframe><form id="tdsMmethodForm" name="tdsMmethodForm" action="https://api-sandbox.pa.dev.wompi.dev/v1/webhook_events/acs_response?order_id=PAYMENT_SOURCE-335" method="post" target="tdsMmethodTgtFrame" xmlns="http://www.w3.org/1999/xhtml"><input type="hidden" name="operation" value="CHALLENGE_IFRAME_BIN" /><script type="text/javascript">document.getElementById("tdsMmethodForm").submit();</script></form>"
}
}
}
}

Paso 6. Renderizar el IFRAME para continuar con el proceso de autenticación:

Observaremos que en la preautorizacion, la clave extra contiene información adicional relevante. Específicamente, nos centraremos en la clave three_ds_method_data, que incluye un fragmento de código HTML. Este es un bloque IFRAME que debe ser integrado y mostrado en la página para llevar a cabo de manera segura el proceso de autenticación de la tarjeta. Además, también encontraremos la clave current_step, que indica el estado actual de la autenticación y puede hacer referencia al tipo específico de autenticación necesario para verificar la identidad del titular de la tarjeta.

Tipos de autenticación 3DS

El campo current_step indica qué tipo de autenticación se está realizando:

StepDescripciónDestinoAcción
BROWSER_INFORecopilación de datos del navegador. El formulario HTML contenido en three_ds_method_data incluye un script que ejecuta .submit() automáticamente.Wompi APIiframe oculto (1x1px)
FINGERPRINTDevice fingerprint del tarjetahabienteACS + Wompi APIiframe oculto (1x1px)
CHALLENGEVerificación interactiva del emisor. El contenido HTML requiere que el usuario realice una acción (hacer clic en "Sí", ingresar un OTP, etc.)ACS + Wompi APIiframe visible (modal)

BROWSER_INFO: Renderiza el HTML en un iframe oculto. El formulario se auto-envía y el proceso continúa automáticamente. No necesitas mostrar nada al usuario.

CHALLENGE: Renderiza el HTML en un iframe visible para que el usuario pueda interactuar con el formulario del banco emisor (aprobar la transacción, ingresar código OTP, etc.).

Ejemplo de manejo en JavaScript:

// Detectar el tipo de autenticación 3DS
const threeDsData = response.data.extra.three_ds_auth.three_ds_method_data;
const currentStep = response.data.extra.three_ds_auth.current_step;

if (currentStep === 'BROWSER_INFO') {
// Renderizar en iframe OCULTO — se auto-envía
const hiddenIframe = document.createElement('iframe');
hiddenIframe.style.display = 'none';
hiddenIframe.srcdoc = threeDsData;
document.body.appendChild(hiddenIframe);
} else if (currentStep === 'CHALLENGE') {
// Renderizar en iframe VISIBLE — requiere interacción del usuario
const container = document.getElementById('iframe-3ds-container');
container.style.display = 'block';
container.innerHTML = threeDsData;
}

Paso 7. No te olvides de realizar consultas periódicas de la preautorización hasta alcanzar un estado final.

tip

Los ejemplos de código del Paso 5 ya implementan el polling completo, incluyendo el manejo del iframe 3DS y la espera hasta el estado final (AVAILABLE, DECLINED o ERROR). No necesitas implementar lógica adicional — los ejemplos cubren todo el ciclo de vida.

Así luce una preautorización exitosa y lista para ser capturada:

{
"data": {
"id": 335,
"public_data": {
"type": "CARD",
"financial_operation": "PREAUTHORIZATION",
"amount_in_cents": 100,
"number_of_installments": 1,
"currency": "USD"
},
"token": "tok_devtest_196_8A7308f20c2d236f42252972390b4eb1",
"type": "CARD",
"status": "AVAILABLE",
"customer_email": "jmtm141097@gmail.com",
"extra": {
"three_ds_auth": {
"current_step": "AUTHENTICATION",
"current_step_status": "COMPLETED"
}
}
}
}

Captura

Es la etapa en la que se realiza el cobro o la transferencia final de los fondos reservados durante la preautorización. Una vez que se completa la transacción o se cumple la condición acordada, se envía una solicitud de captura para obtener los fondos reservados durante la preautorización. Esto resulta en la transferencia de los fondos desde la cuenta del titular de la tarjeta al comerciante o proveedor de servicios. La captura es fundamental para finalizar la transacción y asegurar que el comerciante reciba el pago correspondiente.

Implementación de la Captura

Requisitos previos

Antes de realizar una captura, asegúrate de contar con los siguientes requisitos:

Paso 1. Crea una transacción.

Para avanzar con el proceso de captura, debemos enviar una solicitud POST /transactions. En los headers, debemos incluir la llave privada de nuestro comercio como un Bearer token. Además, debemos enviar el siguiente JSON como cuerpo de la solicitud:

{
"amount_in_cents": 100, // Monto de la captura (no debe superar el monto preautorizado)
"public_key": "pub_prod_ffhas23932", // Llave pública del comercio
"currency": "USD",
"customer_email": "prueba@test.com",
"reference": "TEST34502", // Referencia única de la transacción
"payment_source_id": 298, // ID de la fuente de pago (preautorización)
"payment_method": {
"installments": 1 // Número de cuotas (requerido para Panamá)
},
"signature": "a1b2c3d4..." // Firma de integridad SHA-256 (ver cálculo abajo)
}
Campos requeridos para Panamá

Los siguientes campos son obligatorios en transacciones de Panamá y generan error de validación si se omiten:

  • public_key: Llave pública del comercio en el body de la transacción.
  • payment_method.installments: Número de cuotas (mínimo 1 para pago de contado).
  • signature: Firma de integridad para validar que los datos no han sido alterados.

Cálculo de la firma de integridad:

La firma se calcula concatenando los valores sin separadores y aplicando SHA-256:

SHA-256( reference + amount_in_cents + currency + integrity_key )

Ejemplo:

// JavaScript
const data = `${reference}${amountInCents}${currency}${integrityKey}`;
const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(data));
const signature = Array.from(new Uint8Array(hashBuffer))
.map(b => b.toString(16).padStart(2, '0')).join('');
# Ruby
data = "{amount_in_cents}{integrity_key}"
signature = OpenSSL::Digest::SHA256.hexdigest(data)

Paso 2. Realizar consultas periódicas de la transacción para verificar el estado y asegurarnos de su correcta ejecución.

Así luce una captura que se ha realizado exitosamente:

{
"data": {
"id": "1196-1689602000-65841",
"created_at": "2023-07-17T13:53:24.308Z",
"amount_in_cents": 100,
"reference": "TEST34502",
"currency": "USD",
"payment_method_type": "CARD",
"payment_method": {
"type": "CARD",
"extra": {
"name": "VISA-0031",
"type": "CAPTURE", // Indica que la transacción es de tipo captura
"brand": "VISA",
"last_four": "0031",
"is_three_ds": false,
"three_ds_auth": null,
"external_identifier": "QtcGZjh9nX",
"processor_response_code": "00"
}
},
"redirect_url": null,
"status": "APPROVED", // Estado final de la transacción
"status_message": null,
"merchant": {
"name": "Pruebas SandBox",
"legal_name": "Pruebas SandBox",
"contact_name": "Pepito Perez",
"phone_number": "+50732345634",
"logo_url": null,
"legal_id_type": "RUC",
"email": "prueba@test.com",
"legal_id": "2452345-5"
},
"taxes": []
}
}

Cobros Recurrentes (Sin 3DS)

Una vez completada la primera captura exitosamente, se pueden realizar cobros recurrentes usando el mismo payment_source_id sin necesidad de repetir el proceso 3DS.

¿Por qué no se requiere 3DS en cobros recurrentes?

Cuando se crea un payment source con financial_operation: "PREAUTHORIZATION", la tarjeta pasa por el proceso completo de autenticación 3D Secure (BROWSER_INFO + CHALLENGE). Una vez que el payment source alcanza el estado AVAILABLE, queda autenticado permanentemente.

Cualquier transacción posterior que utilice el mismo payment_source_id no necesita re-autenticación 3DS, lo que permite:

  • Cobros recurrentes automáticos (suscripciones)
  • Cobros por montos diferentes al preautorizado
  • Múltiples capturas sin fricción para el usuario

Implementación del cobro recurrente

Paso 1. Crear una nueva transacción usando el mismo payment_source_id

Enviar una solicitud POST /transactions con el mismo payment_source_id de la preautorización:

{
"amount_in_cents": 100,
"public_key": "pub_prod_ffhas23932",
"currency": "USD",
"customer_email": "prueba@test.com",
"reference": "RECURRING-001", // Nueva referencia única
"payment_source_id": 298, // Mismo ID de la preautorización
"payment_method": {
"installments": 1
},
"signature": "f6e5d4c3..." // Nueva firma calculada con la nueva referencia y monto
}
Importante
  • El payment_source_id es el mismo que se usó en la captura original.
  • Se requiere una nueva referencia única para cada cobro recurrente.
  • Se requiere una nueva firma de integridad calculada con la nueva referencia y monto.
  • No habrá flujo 3DS — la transacción se aprobará sin intervención del usuario.

Paso 2. Realizar consultas periódicas de la transacción

El cobro recurrente sigue el mismo patrón de polling que la captura. La transacción alcanzará un estado final (APPROVED, DECLINED, etc.) sin pasar por 3DS.

Así luce un cobro recurrente aprobado:

{
"data": {
"id": "1196-1689700000-78923",
"created_at": "2023-07-18T17:06:40.000Z",
"amount_in_cents": 100,
"reference": "RECURRING-001",
"currency": "USD",
"payment_method_type": "CARD",
"payment_method": {
"type": "CARD",
"extra": {
"name": "VISA-0057",
"type": "CAPTURE",
"brand": "VISA",
"last_four": "0057",
"is_three_ds": false,
"three_ds_auth": null,
"external_identifier": "RcTg7Hj2Xk",
"processor_response_code": "00"
},
"installments": 1
},
"status": "APPROVED",
"status_message": null
}
}

Nota que is_three_ds es false y three_ds_auth es null — confirmando que no se requirió autenticación 3DS para este cobro.

Diagrama del flujo completo

El siguiente diagrama muestra las 3 etapas del flujo y cómo se relacionan:

EtapaAcciónEndpoint3DS
1. PreautorizaciónCrear payment sourcePOST /payment_sources
2. Polling + 3DSConsultar estadoGET /payment_sources/{id}✅ Requerido (BROWSER_INFO, FINGERPRINT y CHALLENGE)
3. CapturaCobrar fondosPOST /transactions❌ No requerido
4. RecurrenteCobro posteriorPOST /transactions❌ No requerido
¿Por qué los cobros recurrentes no requieren 3DS?

El payment_source_id fue autenticado con 3DS durante la preautorización (etapa 2). Todas las transacciones posteriores con ese mismo ID omiten re-autenticación, permitiendo cobros automáticos sin intervención del usuario.