Ir al contenido

Generar un pago

Ver .md

Este es el primer paso de cualquier cobro por API: le dices a Efipay qué vas a cobrar y cuánto, y te devolvemos con qué seguir.

Lo que recibes depende de payment.checkout_type:

Opcionalmente puedes activar idempotencia con el header X-Idempotency-Enabled y advanced_options.references para evitar pagos duplicados ante reintentos. Ver Idempotencia.

POST /api/v1/payment/generate-payment

Cada payment_id que devuelve este endpoint admite una sola transacción, tanto si el cobro es redirect como si es api. El estado de esa transacción no importa: aprobada, rechazada, pendiente o expirada, el cobro ya no acepta otro intento.

Un cobro (payment_id) y una transacción no son lo mismo. Este endpoint crea el cobro. La transacción nace después, cuando el pagador usa la URL de checkout o cuando llamas a Checkout.

A partir de ese primer intento el payment_id queda consumido. Si el pago falla y quieres volver a intentar (otra tarjeta, otro medio, el mismo pagador), genera un cobro nuevo: vuelve a llamar a /api/v1/payment/generate-payment y usa el nuevo payment_id (y el nuevo token o url).

Sí consume el intento

  • Cualquier transacción creada: tarjeta, PSE, efectivo, Bre-B, 3DS iniciado o abandono del checkout.
  • Da igual el estado final: Aprobada, Rechazada, Pendiente o expirada.

No consume el intento

  • Un 422 de validación (el body está mal y aún no se creó transacción).

El cuerpo de generate-payment y de transaction-checkout no cambia. El flujo 3DS (/api/v1/payment/3ds/...) sigue sobre la transacción ya creada: eso no es un segundo cobro.

redirect api
Quién captura el medio de pago Nosotros Tú
Qué recibes url token
Peticiones para cobrar 1 2
Requiere certificación PCI DSS No Sí
Diseño del checkout El nuestro, con tu logo El tuyo
Medios de pago Todos los que tengas habilitados Los que implementes
Nombre del campo Descripción Reglas
payment Objeto con los datos del cobro ['required']
payment.description Qué estás cobrando. Tu cliente lo ve en el checkout y en el comprobante ['required', 'string', 'min:4', 'max:191']
payment.amount Valor a cobrar, en la unidad de la moneda (no en centavos), con hasta 2 decimales. El máximo depende de la moneda: 999999999999.99 en COP y 200000000.99 en USD/EUR ['required', 'numeric', 'min:1', 'max:999999999999.99', 'decimal:0,2']
payment.currency_type Moneda del cobro. Ver monedas ['required', 'string', 'in:COP,USD,EUR']
payment.checkout_type redirect (te damos un link) o api (cobras tú). Ver tipos de checkout ['required', 'string', 'in:redirect,api']
payment.selected_taxes Ids de tus impuestos a aplicar. No se puede usar junto con tax_amount ['nullable', 'array', 'missing_with:payment.tax_amount']
payment.selected_taxes.* Cada id debe corresponder a un impuesto activo ['required', 'exists:taxes,id']
payment.tax_amount Valor del impuesto ya calculado por ti. No se puede usar junto con selected_taxes ['nullable', 'numeric', 'decimal:0,2', 'min:0', 'max:<payment.amount>', 'missing_with:payment.selected_taxes']
payment.metadata Tus propios pares clave-valor. Ver Metadata ['sometimes', 'nullable', 'metadata']
payment.checkout_template_id Plantilla de checkout que decide qué campos se le piden al cliente ['nullable', 'exists:checkout_templates,id']
office Sucursal a la que pertenece el cobro. Debe ser una de tus sucursales ['required', 'exists:offices,id']

Todo lo de advanced_options es opcional y sirve para personalizar el cobro: hasta cuándo se puede pagar, a dónde vuelve el cliente, qué medios de pago ofreces, si hay descuento o envío.

Nombre del campo Descripción Reglas
advanced_options Objeto con todo lo que sigue ['nullable']
advanced_options.picture URL de una imagen a mostrar en el checkout. En este endpoint es una URL, no un archivo ['nullable', 'string', 'url', 'ends_with:.jpg,.png,.jpeg']
advanced_options.limit_date Hasta cuándo se puede pagar. Acepta Y-m-d o Y-m-d H:i:s ['nullable', 'date', 'after_or_equal:today']
advanced_options.limit_payments Cuántas transacciones aprobadas admite el cobro ['nullable', 'integer']
advanced_options.references Tus referencias para identificar el cobro. Hasta 3. Si activas idempotencia, son la llave para no crear un pago duplicado ['nullable', 'array', 'max:3']. Con X-Idempotency-Enabled: true: ['required', 'array', 'min:1', 'max:3']
advanced_options.references.* Cada referencia. El conjunto completo es la llave de idempotencia ['required', 'string', 'max:50']
advanced_options.result_urls A dónde vuelve el cliente y a dónde te notificamos ['nullable', 'array']
advanced_options.result_urls.approved Retorno de una transacción aprobada. También se acepta la clave Aprobada ['nullable', 'url']
advanced_options.result_urls.rejected Retorno de una transacción rechazada. También se acepta la clave Rechazada ['nullable', 'url']
advanced_options.result_urls.pending Retorno de una transacción pendiente. También se acepta la clave Pendiente ['nullable', 'url']
advanced_options.result_urls.webhook A dónde te notificamos cada cambio de estado. Debe aceptar POST. Ver más ['nullable', 'url']
advanced_options.delivery_service Servicio de envío ['nullable']
advanced_options.delivery_service.type Gratis o Con Valor. Ver enumeraciones ['required_with:advanced_options.delivery_service', 'in:Gratis,Con Valor']
advanced_options.delivery_service.value Valor del envío, que se suma al monto. Obligatorio cuando el tipo es Con Valor ['required_with:advanced_options.delivery_service', 'required_if:advanced_options.delivery_service.type,Con Valor', 'numeric', 'decimal:0,2']
advanced_options.request_address_delivery Pedirle la dirección de envío al cliente en el checkout ['nullable', 'boolean']
advanced_options.has_all_payment_methods true para ofrecer todos los medios habilitados en tu comercio, sin listarlos ['nullable', 'boolean']
advanced_options.payment_methods Qué medios de pago ofreces. Debe traer al menos uno, y todos deben estar habilitados en tu comercio. Ver métodos de pago ['sometimes', 'bail']
advanced_options.payment_methods.credit Franquicias de tarjeta a aceptar ['sometimes', 'nullable', 'array']
advanced_options.payment_methods.debit Medios débito a aceptar ['sometimes', 'nullable', 'array']
advanced_options.payment_methods.pse Bancos PSE a aceptar ['sometimes', 'nullable', 'array']
advanced_options.payment_methods.cash Puntos de recaudo en efectivo a aceptar ['sometimes', 'nullable', 'array']
advanced_options.discount Descuento sobre el monto ['nullable']
advanced_options.discount.before_on Hasta qué fecha aplica el descuento ['required_with:advanced_options.discount', 'date', 'after_or_equal:today']
advanced_options.discount.type value o percentage. Ver enumeraciones ['required_with:advanced_options.discount', 'in:value,percentage']
advanced_options.discount.value Valor del descuento, según el tipo. Un porcentaje no puede pasar de 100, ni un valor superar el monto ['required_with:advanced_options.discount', 'numeric', 'decimal:0,2']
advanced_options.cash_expired_period Cuánto dura el cupón de pago en efectivo, junto con cash_expired_interval ['nullable', 'required_with:advanced_options.cash_expired_interval', 'integer', 'between:1,60']
advanced_options.cash_expired_interval Unidad de esa duración. Ver frecuencias ['nullable', 'required_with:advanced_options.cash_expired_period', 'in:minute,hour,day,week,month,year']
advanced_options.has_comments Pedirle un comentario al cliente en el checkout ['nullable', 'boolean']
advanced_options.comments_label Qué texto acompaña ese campo de comentario ['nullable', 'string', 'max:100']
advanced_options.credibanco_gateway Tus propios códigos de terminal Credibanco, si no operas por agregador ['nullable', 'array']
advanced_options.credibanco_gateway.code Código único de comercio en Credibanco ['required_with:advanced_options.credibanco_gateway', 'string', 'min:3', 'max:15']
advanced_options.credibanco_gateway.terminal Código de terminal en Credibanco ['required_with:advanced_options.credibanco_gateway', 'string', 'min:3', 'max:15']
advanced_options.redeban_gateway Tus propios códigos de terminal Redeban ['nullable', 'array']
advanced_options.redeban_gateway.code Código único de comercio en Redeban ['required_with:advanced_options.redeban_gateway', 'string', 'min:3', 'max:15']
advanced_options.redeban_gateway.terminal Código de terminal en Redeban ['required_with:advanced_options.redeban_gateway', 'string', 'min:3', 'max:15']
advanced_options.pse_gateway Tus propios códigos PSE ['nullable', 'array']
advanced_options.pse_gateway.code Código único de comercio en PSE ['required_with:advanced_options.pse_gateway', 'string', 'min:3', 'max:15']
advanced_options.pse_gateway.nit NIT de tu comercio ['required_with:advanced_options.pse_gateway', 'string', 'min:8', 'max:11']

Objeto opcional que solo aplica cuando payment.checkout_type es redirect. Si lo envías, los datos del pagador llegan precargados en el checkout y el pagador puede modificarlos antes de pagar. Si no lo envías, el checkout pide los datos en blanco. Si lo envías junto a checkout_type: api la solicitud es rechazada.

Todos los campos son opcionales: puedes enviar solo los que tengas (por ejemplo únicamente name y email). Estos pares se exigen juntos: identification_type con id_number, dialling_code con cellphone y country con state.

Nombre del campo Descripción Reglas
customer_information Datos del pagador para precargar el checkout. Prohibido cuando checkout_type es api ['nullable', 'array', 'prohibited_unless:payment.checkout_type,redirect']
customer_information.name Nombre completo del pagador. No puede ser un número de tarjeta ['nullable', 'string', 'min:5', 'max:255']
customer_information.email Correo del pagador ['nullable', 'email:rfc,strict', 'max:255']
customer_information.identification_type Tipo de documento. Ver enumeraciones ['nullable', 'required_with:customer_information.id_number', 'in:CC,CE,TI,PPT,DNI,NIT,Pasaporte,Otro']
customer_information.id_number Número de documento. El formato depende del tipo: CC 6–10 dígitos, TI 10–11, CE alfanumérico 6–15, PPT 7–15 dígitos, DNI alfanumérico 6–20, NIT 9–10 dígitos, Pasaporte alfanumérico 6–20, Otro máximo 30 ['nullable', 'required_with:customer_information.identification_type']
customer_information.dialling_code Indicativo del país, con + ['nullable', 'required_with:customer_information.cellphone', 'regex:/^\+\d{1,3}$/i']
customer_information.cellphone Celular, solo dígitos ['nullable', 'required_with:customer_information.dialling_code', 'numeric', 'digits_between:5,15']
customer_information.country País en ISO3. Ver lista de países ['nullable', 'required_with:customer_information.state', 'string', 'in:COL,USA,MEX,...']
customer_information.state Departamento. Si country es COL debe estar en la lista de departamentos; en otros países es texto libre ['nullable', 'string', 'max:100']
customer_information.city Ciudad. Usa el nombre exacto de la lista de ciudades para que coincida con el checkout ['nullable', 'string', 'max:100']
customer_information.address_1 Dirección de residencia. No puede ser un número de tarjeta ['nullable', 'string', 'min:5', 'max:100']

payment.metadata es un objeto de pares clave-valor donde guardas tus propias referencias (id de pedido, de usuario, canal…), al estilo de Stripe. No lo usamos para nada: te lo devolvemos.

Límite Valor
Claves Hasta 50
Formato de la clave 1 a 40 caracteres, [A-Za-z0-9_-]
Valor Texto o número, hasta 500 caracteres. Se guarda como texto (42 vuelve como "42")
{
"payment": {
"description": "Orden 12345",
"amount": 20000,
"currency_type": "COP",
"checkout_type": "redirect",
"metadata": { "order_id": "ORD-12345", "user_id": 42 }
},
"office": 1
}

Lo recibes de vuelta en el webhook de la transacción, en checkout.payment_referenceable.metadata. Un valor vacío ("" o null) no se guarda.

Si no cumple los límites, la respuesta es un 422 con error.code: "validation_failed" y error.param: "payment.metadata".

La idempotencia es opcional. Si no envías el header, el endpoint se comporta igual que antes.

Sirve para que, si por un timeout, un doble clic o un reintento automático vuelves a llamar generate-payment con las mismas referencias, la API no cree otro pago. En su lugar responde con el pago ya generado.

Header Descripción Reglas
X-Idempotency-Enabled Activa la búsqueda de un pago previo con las mismas referencias Opcional. Valores aceptados: true, 1, yes, on
  1. Envía X-Idempotency-Enabled: true.
  2. Envía advanced_options.references con al menos una referencia (máximo 3).
  3. La API busca, en el mismo comercio y ambiente (pruebas o producción), un pago generado en las últimas 24 horas con exactamente las mismas referencias y en el mismo orden.
  4. Si lo encuentra, responde ese mismo payment_id (y url si el checkout es redirect).
  5. Si no lo encuentra, crea el pago normalmente.
checkout_type Primera respuesta Reintento con la misma llave
redirect saved, payment_id, url Mismo payment_id y misma url
api saved, payment_id, token Solo saved y payment_id (el token original no se vuelve a devolver; guárdalo en la primera respuesta)

Si otra solicitud con las mismas referencias se está procesando al mismo tiempo, la API puede responder 429 para que reintentes unos segundos después.

Ventana de terminal
curl -X POST\
"/api/v1/payment/generate-payment"\
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H "Content-type: application/json" \
-H "X-Idempotency-Enabled: true" \
-d '{
"payment": {
"description": "Orden 12345",
"amount": 20000,
"currency_type": "COP",
"checkout_type": "api"
},
"advanced_options": {
"references": [
"ORD-12345",
"FAC-67890"
]
},
"office": 1
}'
POSThttps://sag.efipay.co/api/v1/payment/generate-payment
Ventana de terminal
curl -X POST\
"/api/v1/payment/generate-payment"\
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H "Content-type: application/json" \
-d '{
"payment" : {
"description": "Prueba Efipay",
"amount": 20000,
"currency_type": "COP",
"checkout_type": "redirect"
},
"advanced_options": {
"picture": "https://mi-tienda.com/img/producto.png",
"limit_date": "2030-12-24",
"references": [
"123455678",
"1234556789",
"1234556780"
],
"result_urls": {
"approved": "https://mi-tienda.com/gracias",
"rejected": "https://mi-tienda.com/error",
"pending": "https://mi-tienda.com/procesando"
},
"delivery_service": {
"type": "Con Valor",
"value": 2000
},
"request_address_delivery": true,
"discount": {
"before_on": "2030-12-07",
"type": "value",
"value": "2000"
},
"has_comments": true,
"comments_label": "Aqui tu comentario",
"redeban_gateway": {
"code": "12349876",
"terminal": "DRA12335"
}
},
"customer_information": {
"name": "Juan Pérez",
"email": "juan@correo.com",
"identification_type": "CC",
"id_number": "1020304050",
"dialling_code": "+57",
"cellphone": "3001234567",
"country": "COL",
"state": "Antioquia",
"city": "Medellín",
"address_1": "Calle 10 #43-25"
},
"office": 1
}'

Ejemplo de solicitud por api:

POSThttps://sag.efipay.co/api/v1/payment/generate-payment
Ventana de terminal
curl -X POST\
"/api/v1/payment/generate-payment"\
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H "Content-type: application/json" \
-d '{
"payment" : {
"description": "Ejemplo generar payment",
"amount": 20000,
"currency_type": "COP",
"checkout_type": "api"
},
"advanced_options": {
"picture": "https://mi-tienda.com/img/producto.png",
"limit_date": "2030-12-24",
"references": [
"123455678",
"1234556789",
"1234556780"
],
"result_urls": {
"approved": "https://mi-tienda.com/gracias",
"rejected": "https://mi-tienda.com/error",
"pending": "https://mi-tienda.com/procesando"
},
"delivery_service": {
"type": "Con Valor",
"value": 2000
},
"request_address_delivery": true,
"discount": {
"before_on": "2030-12-07",
"type": "value",
"value": "2000"
},
"has_comments": true,
"comments_label": "Aqui tu comentario",
"redeban_gateway": {
"code": "12349876",
"terminal": "DRA12335"
}
},
"office": 1
}'
200OK
{
"saved": true,
"payment_id": "9dc12b03-5833-496a-83e6-4dfb8eb2570b",
"url": "https://sag.efipay.co/Checkout/PaymentGateway/9dc12b03-5833-496a-83e6-4dfb8eb2570b?signature=e7e33380957f87b98dab2353ccb7b3c5aed4387c44297fdefe03594b2ae17d79"
}

Redirige a tu cliente a url. La firma va incluida: no la modifiques ni le agregues parámetros, o el link deja de ser válido. Si enviaste advanced_options.limit_date, el link expira en esa fecha.

200OK
{
"saved": true,
"payment_id": "9dc12b26-dc55-474c-8602-5d9e00af129e",
"token": "ZQZ82Ifn5fAuzKL"
}

No hay url: el par payment_id + token es lo que usas para procesar el pago desde tu checkout.

422Unprocessable Entity
{
"payment.currency_type": ["El campo payment.currency_type es obligatorio."],
"errors": {
"payment.currency_type": ["El campo payment.currency_type es obligatorio."]
},
"message": "El campo payment.currency_type es obligatorio.",
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "El campo payment.currency_type es obligatorio.",
"param": "payment.currency_type"
}
}
429Too Many Requests
{
"message": "Otra solicitud con las mismas referencias está siendo procesada, por favor intenta de nuevo.",
"error": {
"type": "rate_limit_error",
"code": "too_many_requests",
"message": "Otra solicitud con las mismas referencias está siendo procesada, por favor intenta de nuevo.",
"param": null
}
}

Última actualización: