Skip to main content

Un endpoint, múltiples métodos de pago

Todos los débitos automáticos se ejecutan con POST /charges. Lo que cambia es cómo capturas y autorizas el método de pago antes de cobrar.
MétodoCapturaProcesamientoInteracción del cliente
Tarjeta de crédito/débitoSDK Elements (recomendado) o API directaInmediatoSolo al registrar la tarjeta
Cuenta bancaria (ACH)API con número de cuentaSiguiente día hábilSolo al autorizar la cuenta
NequiAPI + autorización en appInmediatoAutoriza en la app Nequi cada vinculación
DaviplataAPI + código OTP por SMSInmediatoIngresa OTP recibido por SMS
Todos los métodos requieren authorization: true al momento de registrar el medio de pago. Sin esto, no podrás crear cargos.

Débito con tarjeta de crédito/débito

Hay dos formas de capturar los datos de la tarjeta:

Opción A: SDK Elements (recomendado)

El SDK Elements captura los datos sensibles en un iframe seguro y te devuelve un card_token. Tu servidor nunca toca los datos de la tarjeta, lo que simplifica el cumplimiento PCI DSS. Paso 1: Tokenizar en el frontend Integra el SDK Elements en tu página de captura. Consulta la guía de integración para el setup completo. Paso 2: Registrar la tarjeta tokenizada
curl https://api.onepay.la/v1/cards/tokenized \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: card-token-001" \
  -d '{
    "card_token": "TOKEN_DEL_SDK",
    "customer_id": "CUSTOMER_ID",
    "authorization": true
  }'
Paso 3: Crear el cargo
curl https://api.onepay.la/v1/charges \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: cargo-tarjeta-001" \
  -d '{
    "title": "Mensualidad Enero",
    "customer_id": "CUSTOMER_ID",
    "amount": 85000,
    "card_id": "CARD_ID"
  }'

Opción B: API directa (requiere PCI DSS)

Si tu empresa cumple con PCI DSS, puedes enviar los datos de tarjeta directamente a la API.
Este endpoint usa un dominio diferente: https://cards.onepay.la/v1/cards. Esto se implementa mediante un proxy para garantizar el cumplimiento PCI DSS.
curl https://cards.onepay.la/v1/cards \
  -X POST \
  -H "Authorization: Bearer pk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: card-directa-001" \
  -d '{
    "card_number": "4111111111111111",
    "expiration_year": "29",
    "expiration_month": "12",
    "ccv": "123",
    "holder_name": "MARIA LOPEZ",
    "customer_id": "CUSTOMER_ID",
    "authorization": true
  }'
Luego crea el cargo con POST /charges igual que en la Opción A.

Respuesta de la tarjeta

{
  "id": "9e01eeae-2868-4564-9d04-84d1d1d027d2",
  "brand": "Mastercard",
  "last_four": "8099",
  "card_name": "MARIA LOPEZ",
  "type": "credit_card",
  "cvc_check": true,
  "verified": true,
  "action": {
    "action": "NULL",
    "next": null
  }
}
Si action.action no es "NULL", la tarjeta requiere autenticación 3D Secure. Redirige al cliente a la URL en action.next para completar la verificación.

Débito con cuenta bancaria (ACH)

Los débitos a cuentas bancarias se procesan mediante ACH (Cámara de Compensación Automatizada). El procesamiento no es inmediato: los fondos se acreditan el siguiente día hábil.

Tiempos de procesamiento

Tipo de cuentaProcesamientoHorario de corte
Ahorros / Corriente (ACH)Siguiente día hábilAntes de las 4:00 PM
NequiInmediato24/7
DaviplataInmediato24/7
Los cargos ACH enviados después del horario de corte se procesan al segundo día hábil siguiente. Los fines de semana y festivos no cuentan como días hábiles.

Flujo completo

Paso 1: Consultar bancos disponibles
curl https://api.onepay.la/v1/accounts/banks \
  -H "Authorization: Bearer sk_test_xxx"
Paso 2: Registrar la cuenta bancaria
curl https://api.onepay.la/v1/accounts \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: cuenta-ach-001" \
  -d '{
    "customer_id": "CUSTOMER_ID",
    "bank_id": "BANK_ID",
    "subtype": "SAVINGS",
    "account_number": "123456789",
    "authorization": true
  }'
Tipos de cuenta (subtype):
ValorDescripción
SAVINGSCuenta de ahorros
CHECKINGCuenta corriente
ELECTRONIC_DEPOSITDepósito electrónico (Nequi, Daviplata)
Paso 3: Crear el cargo
curl https://api.onepay.la/v1/charges \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: cargo-ach-001" \
  -d '{
    "title": "Cuota mensual",
    "customer_id": "CUSTOMER_ID",
    "amount": 200000,
    "account_id": "ACCOUNT_ID"
  }'
Paso 4: Esperar confirmación El cargo queda en estado pending hasta que ACH procese el débito. Recibirás un webhook con el resultado:
{
  "charge": {
    "id": "9e02966f-2ddf-4ee7-a391-5b5b7653e232",
    "status": "succeeded",
    "amount": 200000
  },
  "event": {
    "type": "charge.succeeded",
    "timestamp": 1689262934,
    "environment": "production"
  }
}

Débito con billeteras digitales (Nequi / Daviplata)

Las billeteras digitales requieren que el cliente autorice la vinculación desde su app bancaria antes de poder debitar. A diferencia de ACH, el procesamiento es inmediato.
El cliente debe tener la app de Nequi o Daviplata instalada y activa. Si no completa la autorización, la cuenta quedará en estado PENDING y no podrás crear cargos.

Nequi: Autorización en la app

El cliente debe aprobar la vinculación directamente en la app de Nequi. No se requiere OTP.
1

Crear la cuenta Nequi

curl https://api.onepay.la/v1/accounts \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: nequi-001" \
  -d '{
    "customer_id": "CUSTOMER_ID",
    "bank_id": "9957817d-239b-4032-8dca-bc508a76579c",
    "subtype": "ELECTRONIC_DEPOSIT",
    "account_number": "3201112233",
    "authorization": true
  }'
El account_number es el número de celular registrado en Nequi (sin prefijo +57).
2

El cliente autoriza en Nequi

Muestra instrucciones al cliente:
  1. Abre la app de Nequi
  2. Busca la notificación de autorización de débito automático
  3. Aprueba la vinculación
El cliente recibirá una notificación push en la app de Nequi.
3

Validar la cuenta

Una vez que el cliente autoriza en Nequi, valida la cuenta. Para Nequi no se requiere OTP.
curl https://api.onepay.la/v1/accounts/ACCOUNT_ID/validate \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: validar-nequi-001"
4

Crear el cargo

Con la cuenta en estado ACTIVE, puedes debitar:
curl https://api.onepay.la/v1/charges \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: cargo-nequi-001" \
  -d '{
    "title": "Suscripción mensual",
    "customer_id": "CUSTOMER_ID",
    "amount": 45000,
    "account_id": "ACCOUNT_ID"
  }'

Daviplata: Validación con OTP

Daviplata requiere que el cliente ingrese un código OTP recibido por SMS para completar la vinculación.
1

Crear la cuenta Daviplata

curl https://api.onepay.la/v1/accounts \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: daviplata-001" \
  -d '{
    "customer_id": "CUSTOMER_ID",
    "bank_id": "9957817d-26b5-456d-bc49-4a8ba1bc021b",
    "subtype": "ELECTRONIC_DEPOSIT",
    "account_number": "3109998877",
    "authorization": true
  }'
El account_number es el número de celular registrado en Daviplata (sin prefijo +57).
2

El cliente recibe el OTP

Daviplata envía un SMS con un código de 6 dígitos al número del cliente. Muestra un campo en tu interfaz para que el cliente ingrese el código.
3

Validar la cuenta con OTP

curl https://api.onepay.la/v1/accounts/ACCOUNT_ID/validate \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: validar-daviplata-001" \
  -d '{
    "otp": "123456"
  }'
4

Crear el cargo

Con la cuenta validada, puedes debitar:
curl https://api.onepay.la/v1/charges \
  -X POST \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "x-idempotency: cargo-daviplata-001" \
  -d '{
    "title": "Pago de servicio",
    "customer_id": "CUSTOMER_ID",
    "amount": 30000,
    "account_id": "ACCOUNT_ID"
  }'

Estados de la cuenta

Después de crear una cuenta, pasa por estos estados antes de poder debitar:
EstadoDescripción
PENDINGCuenta creada, esperando autorización del cliente
VALIDATINGValidación en progreso (Daviplata con OTP)
ACTIVELista para débitos
REJECTEDAutorización rechazada por el cliente o el banco
INACTIVECuenta desactivada

Comparación rápida

TarjetaCuenta ACHNequiDaviplata
CapturaSDK Elements o API directaNúmero de cuenta + bancoCelularCelular
AutorizaciónAl registrar la tarjetaAl crear la cuentaApp Nequi (push)OTP por SMS
Validación extra3DS (si aplica)NoPOST /accounts/{id}/validatePOST /accounts/{id}/validate con OTP
ProcesamientoInmediatoSiguiente día hábilInmediatoInmediato
Webhook resultadocharge.succeededcharge.succeededcharge.succeededcharge.succeeded

Errores comunes

ErrorCausaSolución
ACCOUNT_IS_NOT_AUTHORIZEDLa cuenta no tiene authorization: trueCrea la cuenta con authorization: true
INSUFFICIENT_FUNDSFondos insuficientesNotifica al cliente y reintenta
CARD_EXPIREDTarjeta expiradaSolicita al cliente que actualice la tarjeta
invalid_otpOTP incorrecto o expirado (Daviplata)Solicita un nuevo OTP al cliente
validation_errorFalta customer_id o método de pagoVerifica que envías card_id o account_id

Webhooks relevantes