Ir al contenido

Convenciones de la API

Ver .md

https://sag.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.

  • 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.

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

{
"data": [ "..." ],
"links": {
"first": "https://sag.efipay.co/api/v1/...?page=1",
"last": "https://sag.efipay.co/api/v1/...?page=8",
"prev": null,
"next": "https://sag.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

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

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 (created_at, approved_at…) ISO 8601 en UTC 2026-07-31T14:32:10.000000Z
Fechas en los webhooks Hora de Colombia 2026-07-31 09:32:10
Fechas legadas de suscripciones (ends_at, canceled_at…) Y-m-d H:i:s, hora de Colombia 2026-10-28 11:28:00
Día de cobro de suscripciones (next_transaction, next_renew_at) Y-m-d, día en Colombia 2026-10-28
Instantes nuevos de suscripciones (ends_at_iso, next_charge_at, charge_scheduled_at, cancel_at) ISO 8601 con offset explícito 2026-10-28T19:00:00-05:00

Todo error de la API v1 (4xx) trae, además de message (y errors en un 422), un objeto error con la misma forma:

{
"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"
}
}

Decide con error.code, que es estable; el texto de message puede cambiar. El catálogo de tipos y códigos está en Códigos de error.

Suscripciones, suscriptores, planes y cobros generados aceptan un objeto metadata de pares clave-valor para guardar tus propias referencias, al estilo de Stripe: hasta 50 claves de 1 a 40 caracteres ([A-Za-z0-9_-]) y valores de texto o número de hasta 500 caracteres, que se guardan como texto. Te lo devolvemos en las consultas y en los webhooks.

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ó.

Tipo Aspecto Dónde
UUID 9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f Cobros, transacciones, planes, suscriptores, cupones, reservas, eventos de webhook (meta.event_id)
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.

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
Ventana de terminal
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.

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, error.code: payment_in_progress 10 segundos
Otro pago en efectivo del mismo cobro en curso 429, error.code: payment_in_progress 5 segundos
Otra operación con la misma Idempotency-Key en curso 409 Hasta que la primera termine
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ó.

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
  • 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.

Última actualización: