Convenciones de la API


URL base y versión

https://sag-qa.efipay.co/api/v1

La versión va en la ruta. Hoy solo existe v1; cuando exista otra, v1 seguirá respondiendo.

Dentro de una versión solo agregamos: campos nuevos en las respuestas, parámetros opcionales nuevos, valores nuevos en las enumeraciones. Nunca quitamos un campo ni cambiamos el significado de uno existente.

{warning} Por eso tu código no debe romperse si aparece un campo que no conocías, ni si una enumeración trae un valor nuevo. Ignora lo que no uses.

Formato de las peticiones

  • Cuerpo en JSON, con Content-Type: application/json.
  • Header Accept: application/json. Sin él, un error de validación puede llegarte como HTML en lugar de JSON.
  • Autenticación con Authorization: Bearer. Ver Autenticación.
  • Nombres de campo en snake_case en lo que envías.

La única excepción es crear una sucursal con logo o RUT, que va como multipart/form-data porque lleva archivos.

{info} En las respuestas verás dos estilos: snake_case en la mayoría de los endpoints y camelCase en algunos de suscripciones. Cada página muestra el suyo; no lo adivines.

Paginación

Los listados vienen paginados con el sobre estándar de Laravel:

{
    "data": [ "..." ],
    "links": {
        "first": "https://sag-qa.efipay.co/api/v1/...?page=1",
        "last": "https://sag-qa.efipay.co/api/v1/...?page=8",
        "prev": null,
        "next": "https://sag-qa.efipay.co/api/v1/...?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 8,
        "per_page": 15,
        "to": 15,
        "total": 118
    }
}
Parámetro Qué hace Por defecto
page Página a traer 1
per_page Cuántos elementos por página 15 en la mayoría de los endpoints

{danger} Dos excepciones que muerden:

Para recorrer todo, sigue links.next hasta que sea null. No calcules las URLs a mano.

Fechas y horas

Contexto Formato Ejemplo
Filtros de fecha que envías Y-m-d 2026-07-31
Vencimiento de tarjeta Y-m 2030-12
Fecha tope de un plan Y-m-d H:i:s 2026-12-31 23:59:59
Fechas que devolvemos ISO 8601 en UTC 2026-07-31T14:32:10.000000Z
Fechas en los webhooks Hora de Colombia 2026-07-31 09:32:10

{warning} La zona horaria de la operación es America/Bogotá (UTC−5). Un cobro de las 8 p.m. del 31 de julio en Colombia es 2026-08-01T01:00:00Z en UTC: si conviertes mal, te cambia de mes en la conciliación.

Montos y monedas

Los montos van como número decimal en la unidad principal de la moneda, no en centavos: 120000 son ciento veinte mil pesos, y 1200.50 son mil doscientos pesos con cincuenta centavos.

Moneda Código Notas
Peso colombiano COP La moneda de operación. Máximo 999.999.999.999
Dólar USD Se convierte a COP con la TRM del día. Máximo 200.000.000
Euro EUR Igual que USD

En una transacción en moneda extranjera verás amount (moneda original), value_cop (el equivalente en pesos) y currency_rate_conversion con la tasa aplicada. Concilia con value_cop: es lo que efectivamente se movió.

{info} Las reservas de cupo solo operan en COP.

Identificadores

Tipo Aspecto Dónde
UUID 9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f Cobros, transacciones, planes, suscriptores, cupones, reservas
Consecutivo 20481 transaction_id, el número que ve tu operador
Entero 1 Sucursales

Una transacción tiene los dos: id (UUID) y transaction_id (consecutivo). Los endpoints de consulta aceptan cualquiera de los dos; guarda el que le vayas a mostrar a una persona.

{warning} Los ids no se comparten entre ambientes. Un id de prueba da 404 con token de producción, y al revés.

Idempotencia

Las escrituras de suscripciones, pagos y reservas de cupo aceptan el header Idempotency-Key. Si repites la misma llamada con la misma clave y los mismos parámetros, te devolvemos la respuesta original con el header Idempotency-Replayed: true, sin volver a ejecutar el cobro.

Rutas que la aceptan
/api/v1/subscriptions/* Crear, cancelar, cambiar de plan, actualizar la tarjeta, pausar, reanudar
/api/v1/payment/generate-payment Generar el cobro
/api/v1/payment/transaction-checkout/* Checkout por API: tarjeta, efectivo, PSE, Bre-B
/api/v1/payment/refund-transaction Devoluciones
/api/v1/mit/pre-authorizations/* Crear, autorizar, cobrar y liberar reservas

{info} Las consultas no la aceptan, aunque vayan por POST: transaction-status, transaction/{id}, all-transaction-status y el sync de una reserva. Ahí la clave no tendría sentido: se pide justamente el estado más reciente. Los pasos de 3DS tampoco, porque su resultado cambia entre llamadas.

curl -X POST \
'/api/v1/subscriptions/subscription' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-type: application/json' \
-H 'Idempotency-Key: 9b1f0e34-6b2a-4a7e-9d0a-uno-por-operacion' \
-d '{ "...": "..." }'
  • Usa una clave distinta por operación (un UUID sirve). No reutilices la misma clave para dos cobros diferentes.
  • La clave vale 24 horas y su alcance es tu comercio y el usuario del token.
  • La misma clave con parámetros distintos responde 409.
  • La misma clave mientras la primera petición sigue en curso responde 409.
  • Los errores 5xx no se memorizan, para que puedas reintentar un fallo transitorio.

Detalle en Suscripciones.

Límites, tiempos y reintentos

Límite de peticiones

No publicamos hoy un límite de peticiones por minuto. Lo que sí existe es un candado de concurrencia por cobro: no se procesan dos pagos del mismo cobro a la vez.

Situación Respuesta Ventana
Otro pago del mismo cobro en curso (tarjeta, PSE, Bre-B) 429 10 segundos
Otro pago en efectivo del mismo cobro en curso 429 5 segundos
Otra operación con la misma Idempotency-Key en curso 409 Hasta que la primera termine

{warning} Un 429 no significa que hayas excedido una cuota: significa que esa misma operación ya se está procesando. Espera el resultado y consúltalo; no la reenvíes.

Tiempos de respuesta

Operación Espera razonable Nuestro tope contra la red
Catálogos y consultas Menos de 1 s
Pago con tarjeta (sin 3DS) 3 a 10 s 45 s
Pago con tarjeta (con 3DS) Depende del banco y del cliente 45 s por llamada
Reserva de cupo 3 a 10 s 45 s

Pon en tu cliente un timeout mayor a 45 segundos para las operaciones de cobro. Si cortas antes, no cancelas nada: la operación sigue su curso en la red y te quedas sin saber cómo terminó.

Qué es seguro reintentar

Respuesta ¿Reintentar?
5xx, error.retryable: true Sí, con espera creciente
error.retryable: false (fondos, tarjeta vencida, fraude) No. El resultado será el mismo
202, T01, o un timeout de tu lado No a ciegas. Estado indeterminado: consulta primero
409 de idempotencia No: ya hay una operación con esa clave
422 de validación Solo después de corregir la petición

{danger} La regla que evita cobros dobles: ante la duda, consulta antes de reenviar. Con estado de transacción o con la misma Idempotency-Key, que te devuelve la respuesta original en vez de cobrar de nuevo.

Lo que nunca devolvemos

  • El número completo de una tarjeta. Siempre enmascarado: 491617******1313.
  • El CVV. No se guarda.
  • Tokens en claro. El token de un cobro en modalidad api y el token de una tarjeta se devuelven una sola vez, al crearse. De ahí en adelante solo guardamos su hash.

{danger} Si necesitas volver a mostrar «con qué tarjeta pagó», usa el BIN y los últimos cuatro dígitos que ya te devolvemos. No hay forma de recuperar el número completo, y eso es deliberado.