Reserva de cupo


Overview

Una reserva de cupo retiene fondos en la tarjeta de tu cliente sin cobrarlos todavía. Después decides cuánto cobrar de verdad —hasta el valor reservado— o liberas la retención para que el cliente recupere su cupo.

Sirve cuando no conoces el valor final en el momento de la compra:

Caso Reservas Cobras
Hotel El valor de la estadía más un margen por consumos Al hacer el check-out, con el consumo real
Rent a car El alquiler más el depósito de garantía Al devolver el vehículo, descontando lo que aplique
Delivery por peso o por consumo Un estimado del pedido Con el valor pesado o consumido
Suscripción con periodo de prueba El valor del plan Cuando termina la prueba y el cliente sigue

El ciclo son tres momentos:

   1. Crear la reserva  ─────►  2. El cliente autoriza  ─────►  3a. Cobro final
                                   (retención activa)           3b. Liberar la reserva

{info} En la jerga de las redes de pago esto se llama MIT (Merchant Initiated Transaction) o pre-autorización. En esta documentación usamos «reserva de cupo», «cobro final» y «liberar la reserva».

Una reserva es una transacción de tu comercio. Aparece en tu reporte de transacciones desde que el cliente la autoriza, con el estado Autorizada. No se abona a tu cuenta virtual mientras esté solo reservada: el abono ocurre cuando aplicas el cobro final, y por el valor cobrado, no por el reservado.

Elige tu integración

Igual que en el resto de nuestra API, tienes dos modalidades. La eliges con el campo checkout_type al crear la reserva.

redirect (por defecto) api
Quién captura la tarjeta Nosotros, en el checkout de Efipay Tú, en tu propio checkout
Qué recibes al crear checkout_url token
Peticiones para autorizar 1 (creas y rediriges) 2 (creas y autorizas)
Requiere certificación PCI DSS No
3DS Lo gestionamos nosotros Lo gestionas tú y nos envías el resultado
Llave de API Prueba o producción Solo producción

Flujo redirect:

POST /v1/mit/pre-authorizations          →  { checkout_url, id }
rediriges al cliente a checkout_url      →  el cliente ingresa su tarjeta
webhook mit.pre_authorized               →  el cupo quedó reservado
POST /v1/mit/pre-authorizations/{id}/confirm  ó  /void

Flujo api:

POST /v1/mit/pre-authorizations                    →  { id, token }
POST /v1/mit/pre-authorizations/{id}/authorize     →  el cupo quedó reservado
POST /v1/mit/pre-authorizations/{id}/confirm  ó  /void

{warning} La modalidad api recibe el número de tarjeta y el CVV en tu servidor. Solo úsala si tu plataforma está certificada en PCI DSS. Si no lo está, usa redirect: es igual de completa y el dato sensible nunca pasa por tu sistema.

Estados de una reserva

status Etiqueta Qué significa
Iniciada Esperando al cliente La reserva existe pero el cliente aún no autorizó
Pre-autorizada Cupo reservado Hay fondos retenidos. Puedes cobrar o liberar
Confirmada Cobrada El cobro final se aplicó. El dinero entra a tu cuenta virtual
Anulada Reserva liberada El cliente recuperó su cupo. No hubo cobro
Vencida Reserva vencida Pasó la vigencia sin cobro. El cupo se libera solo
Rechazada Rechazada La red no aprobó la reserva
Fallida Fallida No se pudo procesar
Indeterminada Verificando No recibimos respuesta de la red. No reintentes: estamos verificando si el cupo quedó reservado

Puedes consultar este catálogo en GET /api/v1/resources/mit/status-enum.


1. Crear la reserva

POST /api/v1/mit/pre-authorizations

Parámetros

Nombre del campo Descripción Reglas
description Qué se está reservando. El cliente lo ve en el checkout y tú en tu reporte ['required', 'string', 'max:255']
estimated_amount Valor a reservar. Es el techo del cobro final: no podrás cobrar más que esto ['required', 'numeric', 'gt:0', 'max:99999999.99']
checkout_type redirect (por defecto) o api. Ver enumeraciones ['nullable', 'string', 'in:redirect,api']
tax IVA incluido dentro de estimated_amount. Debe ser menor a estimated_amount ['nullable', 'numeric', 'min:0']
references Hasta 5 referencias para identificar la reserva en tus sistemas ['nullable', 'array', 'max:5']
references.*.referenceKey Nombre de la referencia. Solo letras, números y espacios ['required_with:references', 'string', 'regex:/^[\pL\pN ]+$/u', 'max:64']
references.*.referenceDescription Valor de la referencia. Solo letras, números y espacios ['required_with:references', 'string', 'regex:/^[\pL\pN ]+$/u', 'max:22']
customer Datos del cliente, para prellenar el checkout ['nullable', 'array']
customer.name Nombre del cliente ['nullable', 'string', 'max:255']
customer.email Correo del cliente ['nullable', 'email', 'max:255']
webhook_url URL a la que notificaremos los cambios de estado de esta reserva. Si no la envías usamos la de tus opciones avanzadas ['nullable', 'url', 'max:255']
redirect_url A dónde vuelve el cliente después del checkout (modalidad redirect) ['nullable', 'url', 'max:255']
checkout_template_id ID de tu plantilla de checkout ['nullable', 'integer', 'exists:checkout_templates,id']

{danger} Este endpoint no recibe datos de tarjeta. Si envías number, cvv, card_token o similares la petición se rechaza con un 422 explicando por qué. En redirect los ingresa el cliente; en api van en el paso 2.

Respuesta modalidad redirect

curl -X POST \
'/api/v1/mit/pre-authorizations' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H "Content-type: application/json" \
-d '{
    "description": "Reserva habitación 402 - 3 noches",
    "estimated_amount": 850000,
    "checkout_type": "redirect",
    "references": [
        { "referenceKey": "Reserva", "referenceDescription": "HAB402" }
    ],
    "customer": {
        "name": "Ana Gomez",
        "email": "ana@ejemplo.com"
    },
    "webhook_url": "https://mi-hotel.com/webhooks/efipay"
}'

Respuesta 201:

{
    "success": true,
    "pre_authorization": {
        "id": "019fba4a-5a7f-73df-b9a5-ec0ca585fd60",
        "status": "pendiente_autorizacion",
        "checkout_type": "redirect",
        "description": "Reserva habitación 402 - 3 noches",
        "estimated_amount": 850000,
        "currency": "COP",
        "references": [
            { "referenceKey": "Reserva", "referenceDescription": "HAB402" }
        ],
        "expires_at": null,
        "checkout_url": "https://sag-qa.efipay.co/Checkout/019fba4a-5a7f-73df-b9a5-ec0ca585fd60"
    }
}

Redirige al cliente a checkout_url. Cuando autorice te llegará el webhook mit.pre_authorized con la reserva ya vigente.

Respuesta modalidad api

Idéntica, pero cambia checkout_url por token:

{
    "success": true,
    "pre_authorization": {
        "id": "019fba4a-5a7f-73df-b9a5-ec0ca585fd60",
        "status": "pendiente_autorizacion",
        "checkout_type": "api",
        "description": "Reserva habitación 402 - 3 noches",
        "estimated_amount": 850000,
        "currency": "COP",
        "references": [
            { "referenceKey": "Reserva", "referenceDescription": "HAB402" }
        ],
        "expires_at": null,
        "token": "dASpVjbG0AJter1"
    }
}

{warning} El token se devuelve una sola vez: en nuestra base solo queda su hash. Guárdalo junto al id, porque los dos juntos autentican el paso 2. Si lo pierdes, crea una reserva nueva.


2. Autorizar con tarjeta (solo modalidad api)

POST /api/v1/mit/pre-authorizations/{id}/authorize

Este es el paso que retiene los fondos. El par id + token del paso 1 autentica la operación: el id va en la URL y el token en el cuerpo.

Parámetros de la tarjeta

Nombre del campo Descripción Reglas
payment Objeto con el token de la reserva ['required', 'array']
payment.token El token que te devolvió el paso 1 ['required', 'string']
customer_payer Datos de quien paga ['required', 'array']
customer_payer.name Nombre de quien paga ['required', 'string', 'min:5', 'max:255']
customer_payer.email Correo de quien paga. Solo caracteres alfanuméricos ['required', 'email']
customer_payer.address_1 Dirección principal ['required', 'string', 'min:5', 'max:100']
customer_payer.address_2 Dirección secundaria ['nullable', '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.country País en ISO3. Ver lista de países ['required', 'string', 'in:COL,USA,MEX,...']
customer_payer.zip_code Código postal ['required', 'numeric', 'digits_between:1,10']
customer_payer.dialling_code Indicativo telefónico, con + (por ejemplo +57) ['required', 'regex:/^\+\d{1,3}$/i']
customer_payer.cellphone Celular, solo dígitos ['required', 'numeric', 'digits_between:5,15']
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. No puede ser un número de tarjeta ['nullable', 'digits_between:5,15']
payment_card Datos de la tarjeta ['required', 'array']
payment_card.number Número de la tarjeta, sin espacios ['required', 'numeric', 'digits_between:14,16']
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 Obligatorio. Código de seguridad de 3 o 4 dígitos ['required', 'regex:/^\d{3,4}$/i']
payment_card.installments Número de cuotas ['required', 'integer', 'between:1,60']
payment_card.redirect_url A dónde volver si hay una autenticación intermedia ['nullable', 'url', 'max:500']
browser_information Datos del navegador del comprador ['nullable', 'array']
browser_information.ipAddress IP del comprador, para el antifraude ['nullable', 'ipv4']

{danger} El CVV es obligatorio en una reserva de cupo: la red la rechaza sin él. Por eso no se aceptan tarjetas tokenizadas en este endpoint —un token no incluye CVV—. Si envías payment_card.token recibirás un 422 explicándolo. El soporte de tarjetas tokenizadas para reservas está en evaluación con la red.

Autenticación 3DS opcional

Si autenticaste al tarjetahabiente con 3D Secure por tu cuenta, envíanos el resultado en three_ds y lo reenviamos a la red. Cada franquicia usa campos distintos; enviar los de la otra hace que la reserva sea rechazada.

{info} En las reglas verás nullable en todos: Laravel los acepta ausentes, pero después validamos la combinación según la franquicia de la tarjeta. La columna «Descripción» dice cuándo cada uno pasa a ser obligatorio.

Visa — la franquicia se detecta por el BIN. Los tres campos son obligatorios si envías three_ds:

Nombre del campo Descripción Reglas
three_ds.eci Electronic Commerce Indicator. Obligatorio si envías three_ds con una tarjeta Visa ['nullable', 'string', 'size:2', 'in:05,06,07']
three_ds.cavv Cardholder Authentication Verification Value. Obligatorio si envías three_ds con una tarjeta Visa ['nullable', 'string', 'max:28']
three_ds.xid Identificador de la transacción 3DS. Obligatorio si envías three_ds con una tarjeta Visa ['nullable', 'string', 'max:28']

Mastercard — los cuatro campos son obligatorios si envías three_ds:

Nombre del campo Descripción Reglas
three_ds.directory_server_transaction_id Id de la transacción en el directorio, de exactamente 36 caracteres. Obligatorio si envías three_ds con una tarjeta que no sea Visa ['nullable', 'string', 'size:36']
three_ds.ucaf_collection_indicator Indicador UCAF. Obligatorio si envías three_ds con una tarjeta que no sea Visa ['nullable', 'string', 'in:0,1,2,4,6,7']
three_ds.ucaf_authentication_data Dato de autenticación UCAF. Obligatorio si envías three_ds con una tarjeta que no sea Visa ['nullable', 'string', 'max:200']
three_ds.specification_version Versión de la especificación, un solo carácter. Obligatorio si envías three_ds con una tarjeta que no sea Visa ['nullable', 'string', 'max:1']

Si no envías three_ds, la reserva se procesa sin autenticación 3DS.

Ejemplo y respuesta

curl -X POST \
'/api/v1/mit/pre-authorizations/019fba4a-5a7f-73df-b9a5-ec0ca585fd60/authorize' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H "Content-type: application/json" \
-d '{
    "payment": { "token": "dASpVjbG0AJter1" },
    "customer_payer": {
        "name": "Ana Gomez Perez",
        "email": "ana@ejemplo.com",
        "address_1": "Calle 100 # 20-30",
        "city": "Bogota",
        "state": "Cundinamarca",
        "country": "COL",
        "zip_code": "110111",
        "dialling_code": "+57",
        "cellphone": "3001234567"
    },
    "payment_card": {
        "number": "4916170011291313",
        "name": "Ana Gomez",
        "expiration_date": "2028-08",
        "cvv": "200",
        "installments": 1
    },
    "three_ds": {
        "eci": "05",
        "cavv": "AAABCZIhcQAAAABZlyFxAAAAAAA=",
        "xid": "ODUzNTYzOTcwODU5NzQzMjE0NTY="
    }
}'

Respuesta 201 — cupo reservado:

{
    "success": true,
    "pre_authorization": {
        "id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
        "operation": "pre_authorization",
        "status": "Pre-autorizada",
        "status_label": "Cupo reservado",
        "estimated_amount": 850000,
        "authorized_amount": 850000,
        "max_confirmable_amount": 850000,
        "currency": "COP",
        "installments": 1,
        "card": {
            "franchise": "visa",
            "bin": "491617",
            "last_four": "1313"
        },
        "references": [
            { "referenceKey": "Reserva", "referenceDescription": "HAB402" }
        ],
        "network_transaction_id": 320000303129,
        "authorization_code": "005077",
        "response_code": "00",
        "expires_at": "2026-08-07T10:15:00-05:00",
        "confirmable_until": "2026-08-07T10:15:00-05:00",
        "voidable_until": "2026-08-06T10:15:00-05:00",
        "can_confirm": true,
        "can_void": true,
        "blocked_reason": null,
        "checkout_url": null,
        "authorized_at": "2026-07-31T10:15:00-05:00",
        "confirmed_at": null,
        "voided_at": null,
        "created_at": "2026-07-31T10:15:00-05:00",
        "error": null
    }
}

Respuesta 422 — la red rechazó la reserva:

{
    "success": false,
    "pre_authorization": {
        "id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
        "status": "Rechazada",
        "status_label": "Rechazada",
        "response_code": "51",
        "can_confirm": false,
        "can_void": false,
        "error": {
            "code": "51",
            "message": "Fondos insuficientes. Pídele al cliente otra tarjeta.",
            "action": "Reintentar con otro medio de pago"
        }
    }
}

{info} Usa success para decidir, no el código HTTP: siempre te devolvemos el estado completo de la reserva para que sepas exactamente en qué quedó.


3. Cobro final

POST /api/v1/mit/pre-authorizations/{id}/confirm

Cobra el valor real. Este es el momento en que el dinero se mueve y en que la transacción pasa a Aprobada y se abona a tu cuenta virtual, por el valor cobrado.

Nombre del campo Descripción Reglas
amount Valor real a cobrar. No puede superar max_confirmable_amount ['required', 'numeric', 'gt:0', 'max:99999999.99']

Reglas de vigencia:

  • Puedes cobrar hasta la fecha de confirmable_until, que es la vigencia de la reserva: 7 días para Visa y 30 días para Mastercard desde la autorización.
  • Puedes cobrar menos que lo reservado; la diferencia se libera. No puedes cobrar más.
  • Una reserva solo admite un cobro final.

curl -X POST \
'/api/v1/mit/pre-authorizations/019fba50-8d0f-7362-a0b3-029215d91ebb/confirm' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H "Content-type: application/json" \
-d '{ "amount": 620000 }'

Respuesta 200:

{
    "success": true,
    "operation": {
        "id": "019fba55-1c22-70aa-9f10-3d0b21ee7742",
        "operation": "confirmation",
        "status": "Confirmada",
        "status_label": "Cobrada",
        "estimated_amount": 620000,
        "response_code": "00",
        "authorization_code": "005081",
        "network_transaction_id": 320000303188
    },
    "pre_authorization": {
        "id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
        "status": "Confirmada",
        "status_label": "Cobrada",
        "estimated_amount": 850000,
        "authorized_amount": 850000,
        "max_confirmable_amount": 620000,
        "can_confirm": false,
        "can_void": false,
        "confirmed_at": "2026-08-02T18:40:11-05:00"
    }
}

Si la reserva ya no admite cobro, la respuesta llega con success: false y el motivo en pre_authorization.blocked_reason.


4. Liberar la reserva

POST /api/v1/mit/pre-authorizations/{id}/void

Suelta la retención para que el cliente recupere su cupo. No requiere cuerpo.

Reglas de vigencia:

  • Puedes liberar hasta voidable_until, que es 24 horas antes del vencimiento de la reserva. Esa ventana existe porque una liberación pedida sobre el filo del vencimiento puede cruzarse con la liberación automática de la red y quedar en un estado ambiguo.
  • Pasada esa ventana, deja que la reserva venza: el cupo se libera solo, sin cobro. Lo verás con estado Vencida.
  • Como nunca se abonó nada a tu cuenta virtual, liberar no genera ningún movimiento.

Este endpoint no recibe cuerpo.

curl -X POST \
'/api/v1/mit/pre-authorizations/019fba50-8d0f-7362-a0b3-029215d91ebb/void' \
-H 'Authorization: Bearer ACCESS_TOKEN'

Respuesta 200:

{
    "success": true,
    "operation": {
        "operation": "void",
        "status": "Anulada",
        "status_label": "Reserva liberada",
        "response_code": "00"
    },
    "pre_authorization": {
        "id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
        "status": "Anulada",
        "status_label": "Reserva liberada",
        "can_confirm": false,
        "can_void": false,
        "voided_at": "2026-08-01T09:12:44-05:00"
    }
}

Consultar y sincronizar

Una reserva

GET /api/v1/mit/pre-authorizations/{id}

Devuelve la reserva completa, con los mismos campos que ves en la respuesta de crear y autorizar. No recibe parámetros.

curl -X GET \
'/api/v1/mit/pre-authorizations/019fba50-8d0f-7362-a0b3-029215d91ebb' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'

{success} Respuesta satisfactoria code: 200

{
"data": {
"id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
"operation": "pre_authorization",
"status": "Pre-autorizada",
"status_label": "Cupo reservado",
"estimated_amount": 850000,
"authorized_amount": 850000,
"max_confirmable_amount": 850000,
"currency": "COP",
"installments": 1,
"card": {
"franchise": "visa",
"bin": "491617",
"last_four": "1313"
},
"references": [],
"network_transaction_id": 320000303188,
"authorization_code": "005081",
"response_code": "00",
"expires_at": "2026-08-08T18:40:11-05:00",
"confirmable_until": "2026-08-08T18:40:11-05:00",
"voidable_until": "2026-08-07T18:40:11-05:00",
"can_confirm": true,
"can_void": true,
"blocked_reason": null,
"checkout_url": null,
"authorized_at": "2026-08-01T18:40:11-05:00",
"confirmed_at": null,
"voided_at": null,
"created_at": "2026-08-01T18:39:02-05:00",
"error": null
}
}

{danger} No encontramos la reserva code: 404

{
"message": "No encontramos la reserva de cupo."
}

Todas tus reservas

GET /api/v1/mit/pre-authorizations

Paginado, de la más reciente a la más antigua.

Estos parámetros de consulta no se validan en el servidor: un valor inesperado no produce un 422, simplemente no filtra.

Nombre del campo Descripción
status Filtra por estado exacto, por ejemplo Pre-autorizada. Ver estados
pending_confirmation true devuelve solo las que todavía admiten cobro final
per_page Cuántas por página. Por defecto 25
curl -X GET \
'/api/v1/mit/pre-authorizations?status=Pre-autorizada&pending_confirmation=true&per_page=50' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'

{success} Respuesta satisfactoria code: 200

{
"data": [
{
"id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
"operation": "pre_authorization",
"status": "Pre-autorizada",
"status_label": "Cupo reservado",
"estimated_amount": 850000,
"authorized_amount": 850000,
"max_confirmable_amount": 850000,
"currency": "COP",
"can_confirm": true,
"can_void": true,
"confirmable_until": "2026-08-08T18:40:11-05:00",
"created_at": "2026-08-01T18:39:02-05:00"
}
],
"links": {
"first": "https://sag-qa.efipay.co/api/v1/mit/pre-authorizations?page=1",
"last": "https://sag-qa.efipay.co/api/v1/mit/pre-authorizations?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"per_page": 50,
"to": 1,
"total": 1
}
}

Sincronizar contra la red

POST /api/v1/mit/pre-authorizations/{id}/sync

Consulta el estado real en la red y actualiza la reserva. No recibe cuerpo. Úsalo cuando el estado sea Indeterminada —no recibimos respuesta y no sabemos si el cupo quedó reservado— y para obtener la fecha de vencimiento real, que la red solo entrega al consultar.

curl -X POST \
'/api/v1/mit/pre-authorizations/019fba50-8d0f-7362-a0b3-029215d91ebb/sync' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'

{warning} Ante un estado Indeterminada, no reintentes la autorización: podrías reservar el cupo dos veces. Llama a /sync o espera nuestro webhook; nosotros reconciliamos automáticamente.


Webhooks

Te notificamos cada cambio de estado en la URL de webhook_url de la reserva o, si no la enviaste, en el result_urls.webhook de tus opciones avanzadas.

Evento Cuándo llega
mit.pre_authorized El cliente autorizó: hay fondos retenidos
mit.declined La red rechazó la reserva
mit.confirmed Se aplicó el cobro final
mit.voided Se liberó la reserva
mit.expiring_soon La reserva vence pronto y todavía no la cobraste
mit.expired La reserva venció y el cupo se liberó solo

Cuerpo:

{
    "event": "mit.pre_authorized",
    "pre_authorization": {
        "id": "019fba50-8d0f-7362-a0b3-029215d91ebb",
        "operation": "pre_authorization",
        "status": "Pre-autorizada",
        "status_label": "Cupo reservado",
        "estimated_amount": 850000,
        "authorized_amount": 850000,
        "max_confirmable_amount": 850000,
        "currency": "COP",
        "card": { "franchise": "visa", "bin": "491617", "last_four": "1313" },
        "references": [
            { "referenceKey": "Reserva", "referenceDescription": "HAB402" }
        ],
        "network_transaction_id": 320000303129,
        "authorization_code": "005077",
        "expires_at": "2026-08-07T10:15:00-05:00",
        "confirmable_until": "2026-08-07T10:15:00-05:00",
        "voidable_until": "2026-08-06T10:15:00-05:00",
        "can_confirm": true,
        "can_void": true,
        "error": null
    }
}

{info} La ruta debe ser de tipo post.

Enviamos un header Signature con la firma del cuerpo, para que verifiques que no fue manipulado. Se firma con el token de webhooks de tu comercio, que encuentras aquí, usando HMAC-SHA256.

Si tu aplicación no responde 2xx reintentamos a los 10s y luego a los 100s. Después de eso no hay más intentos.

mit.expiring_soon es el que evita que se te pase un cobro: llega mientras la reserva todavía es cobrable, así que puedes cobrarla o dejarla vencer a conciencia.


Códigos de error

Puedes traer el catálogo completo, actualizado, desde GET /api/v1/resources/mit/response-codes. Cada entrada trae code, message, action y retryable, para que manejes los errores sin escribirlos a mano.

Errores propios de la reserva de cupo:

Código HTTP Qué pasó y qué hacer
MIT_PRODUCTION_KEY_REQUIRED 422 Intentaste autorizar con una llave de prueba. Una reserva retiene fondos reales, así que la modalidad api solo funciona con llave de producción
MIT_AMOUNT_EXCEEDS_AUTHORIZED 422 El cobro final supera lo reservado. Ajusta el monto a max_confirmable_amount
MIT_EXPIRED 422 La reserva venció. Debes crear una reserva nueva
MIT_ALREADY_CONFIRMED 409 Esta reserva ya tiene su cobro final aplicado
MIT_VOID_WINDOW_CLOSED 422 Ya cerró la ventana para liberar (24 h antes del vencimiento). Deja que venza
MIT_FRANCHISE_NOT_ENABLED 422 Esa franquicia no está habilitada para reservas en tu comercio. Escríbenos
MIT_INDETERMINATE 202 No recibimos respuesta de la red. No reintentes; estamos verificando
MIT_IN_PROGRESS 429 Ya hay una autorización en curso para esta reserva. Espera el resultado

Códigos de la red más frecuentes (llegan en pre_authorization.error.code):

Código Qué pasó
51 Fondos insuficientes en el cupo del cliente
05 Negada: la tarjeta puede estar bloqueada o el emisor no respondió
54 Tarjeta vencida
M02 La reserva no está en un estado que admita esta operación
M12 El valor del cobro final no corresponde al reservado
309 El tipo de transacción MIT no admite 3DS
310 El ECI enviado no es válido: debe ser 05, 06 o 07
319 / 320 Enviaste el objeto 3DS de la otra franquicia

Límites y notas

  • Moneda: solo COP.
  • Franquicias: Visa y Mastercard. Amex, Diners y Codensa no admiten reserva de cupo.
  • Vigencia: 7 días para Visa, 30 días para Mastercard, contados desde la autorización. La fecha exacta viene en expires_at.
  • Cuotas: de 1 a 60.
  • CVV obligatorio, y por eso todavía no hay soporte de tarjetas tokenizadas para reservas. Está en evaluación con la red.
  • Referencias: solo letras, números y espacios; hasta 22 caracteres cada una. Procura que sean únicas por día: son la forma de identificar la reserva ante la red si hay que investigar una operación.
  • Cuenta virtual: una reserva no abona nada mientras esté solo reservada. El abono ocurre con el cobro final, por el valor cobrado.
  • Reporte de transacciones: la reserva aparece desde que el cliente la autoriza, con estado Autorizada, y pasa a Aprobada al cobrarla.