Checkout hospedado y links de pago
Cobra sin construir un formulario de pago: creas una sesión, rediriges al comprador y HelppiuPay se encarga de los métodos de pago y de 3-D Secure.
Antes de empezar
- Una llave secreta (
hp_sk_test_…para probar). Ver Autenticación. - Las URLs de tu sitio a las que vuelve el comprador al pagar o cancelar.
- Un endpoint de webhooks registrado para confirmar el pago (ver la guía de webhooks).
Pasos
- Crea la sesión desde tu servidor. Obligatorios:
reference(hasta 64 caracteres),amount,success_urlycancel_url. Conpayment_method_typeseliges qué métodos ver; si lo omites, se usa la configuración de tu comercio.cardincluye todas las marcas de tarjeta habilitadas. - Redirige al comprador al
urlde la respuesta. También puedes enviar ese enlace por correo o chat como link de pago. - Espera el webhook. Al volver a tu
success_url, no des el pedido por pagado solo por la redirección: confirma con el eventotransaction.approvedo consultando la sesión. - Expira la sesión si ya no aplica (por ejemplo, si el comprador canceló el pedido en tu tienda) con
POST /checkout-sessions/{uuid}/expire.
curl https://helppiupay.com/api/v1/checkout-sessions \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 0d6c3f1a-2b77-4e1b-a4f2-5c9e8b7d6a21" \
-H "Content-Type: application/json" \
-d '{
"reference": "ORDER-2002",
"amount": 75000,
"currency": "COP",
"description": "Compra en Tu Tienda",
"payment_method_types": ["card", "pse", "nequi", "brev"],
"customer_name": "Laura Vargas",
"customer_email": "laura@example.com",
"customer_phone": "3001234567",
"success_url": "https://tutienda.com/ok",
"cancel_url": "https://tutienda.com/cancel",
"metadata": { "order_id": "2002" }
}'{
"id": "9b2f6c1e-…",
"url": "https://helppiupay.com/…",
"status": "open",
"environment": "test",
"expires_at": "2026-11-14T10:30:00-05:00",
"reference": "ORDER-2002",
"amount": 75000,
"currency": "COP",
"payment_method_types": ["card", "pse", "nequi", "brev"],
"metadata": { "order_id": "2002" },
"transaction": null
}Mostrar el checkout dentro de tu sitio
El checkout también funciona dentro de un iframe, con 3-D Secure incluido. Para habilitarlo, pide al equipo de HelppiuPay que autorice tu dominio; el checkout te avisa de lo que pasa con eventos postMessage que empiezan por helppiupay:. Los detalles están en la referencia API.
Errores comunes
| Respuesta | Causa |
|---|---|
401 | La llave no lleva el formato key_id:secret o es inválida. |
422 | Falta reference, amount, success_url o cancel_url. |
422 | Ofreces PSE, Nequi, Daviplata, Bre-B o QR y customer_phone no es un celular de 10 dígitos que empiece por 3. |
Cobro directo con PSE
Cobra con débito desde la cuenta bancaria del comprador, creando el pago desde tu servidor.
Antes de empezar
- Una llave secreta: los cobros directos no aceptan la llave publicable.
- PSE habilitado en tu comercio.
Pasos
- Lista los bancos con
GET /banks/psey muéstralos al comprador. Cada banco traeidyname; elides elbank_codedel cobro. - Crea el cobro con
payment_method.type: "pse"y elbank_codeelegido.customer.nameycustomer.emailson obligatorios. - Si la respuesta trae
next_action, redirige al comprador anext_action.redirect_urlen una navegación de página completa. - Confirma el resultado con el webhook o con
GET /charges/{uuid}.
curl https://helppiupay.com/api/v1/charges \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 3c8e1f2a-9d4b-4a6e-b0c7-1e2f3a4b5c6d" \
-H "Content-Type: application/json" \
-d '{
"reference": "ORDER-3003",
"amount": 120000,
"currency": "COP",
"customer": {
"name": "Pedro Ruiz",
"email": "pedro@example.com",
"document": "1020304050"
},
"payment_method": {
"type": "pse",
"bank_code": "1007",
"person_type": "0",
"document_type": "CC"
}
}'person_type es 0 o 1, y document_type uno de CC, CE, TI, PA, NIT, RCN, TE o DIE.
{
"id": "ch_8f3…",
"object": "charge",
"reference": "ORDER-3003",
"amount": 120000,
"currency": "COP",
"status": "pending",
"payment_method": "pse",
"environment": "test",
"created_at": "2026-11-13T15:02:11-05:00"
}Estados y errores
- El cobro suele quedar en
pendingmientras el comprador termina en su banco. El resultado llega por webhook. 422si faltabank_codeo un dato del comprador; también si el cobro es declinado.403si usas la llave publicable.
Nequi, Daviplata, Bre-B y cripto
El mismo endpoint de cobros sirve para billeteras, Bre-B y criptomonedas: cambia el payment_method.type.
| Método | payment_method.type | Qué enviar |
|---|---|---|
| Nequi | nequi | Incluye customer.phone con el celular del comprador. |
| Daviplata | daviplata | Incluye customer.phone con el celular del comprador. |
| Bre-B | brev (también breb) | Incluye customer.phone. |
| Cripto | crypto | payment_method.pay_currency es obligatorio; por ejemplo USDTTRC20. |
curl https://helppiupay.com/api/v1/charges \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 7a1b2c3d-4e5f-4a6b-8c9d-0e1f2a3b4c5d" \
-H "Content-Type: application/json" \
-d '{
"reference": "ORDER-4004",
"amount": 45000,
"currency": "COP",
"customer": {
"name": "Camila Rojas",
"email": "camila@example.com",
"phone": "3001234567"
},
"payment_method": { "type": "nequi" }
}'
curl https://helppiupay.com/api/v1/charges \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 5e4d3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b" \
-H "Content-Type: application/json" \
-d '{
"reference": "ORDER-4005",
"amount": 100,
"currency": "USD",
"customer": { "name": "Alice", "email": "alice@example.com" },
"payment_method": { "type": "crypto", "pay_currency": "USDTTRC20" }
}'Qué esperar
- Estos pagos se completan fuera de tu sitio (en la app del comprador o en su billetera), así que el cobro queda en
pendinghasta que se confirme. Si la respuesta traenext_action, síguelo. - El resultado llega por webhook. En Bre-B un pago puede aprobarse incluso después de marcado como
expired: guarda siempre el último estado. - Qué métodos tienes activos depende de la configuración de tu comercio.
Cobro con tarjeta y 3-D Secure
Tokeniza la tarjeta en el navegador y cobra el token desde tu servidor. Si el banco pide 3-D Secure, rediriges al comprador y vuelve a tu sitio con el resultado.
- Tokeniza en el navegador con tu llave publicable y
POST /tokens. El tokentok_…dura 30 minutos y los datos de la tarjeta no pasan por tu servidor. - Cobra el token desde tu servidor con la llave secreta:
payment_method.type: "card",tokeneinstallments(1 a 48). Envíareturn_urlpor si hay desafío 3-D Secure. - Si el cobro queda
pendingconnext_action, redirige la página completa anext_action.redirect_url. No lo abras en uniframe: el desafío solo funciona como navegación completa. - El comprador vuelve a tu
return_urlcon?helppiu_3ds=successofailedy eltransaction_id. Confirma el estado final con el webhook.
// Llave publicable: solo sirve para tokenizar
const res = await fetch('https://helppiupay.com/api/v1/tokens', {
method: 'POST',
headers: {
'Authorization': 'Bearer hp_pk_test_…:sk_…',
'Content-Type': 'application/json',
},
body: JSON.stringify({
card_number: '4970110000001003',
card_cvv: '123',
card_exp_month: '12',
card_exp_year: '30',
card_holder_name: 'JUAN PEREZ',
}),
});
const { id } = await res.json(); // "tok_…" → envíalo a tu servidor
curl https://helppiupay.com/api/v1/charges \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 2f1e0d9c-8b7a-4c6d-9e5f-4a3b2c1d0e9f" \
-H "Content-Type: application/json" \
-d '{
"reference": "ORDER-1001",
"amount": 50000,
"currency": "COP",
"customer": { "name": "María Gómez", "email": "maria@example.com" },
"payment_method": { "type": "card", "token": "tok_abc123def456", "installments": 1 },
"return_url": "https://tutienda.com/pago/resultado"
}'
{
"id": "ch_8f3…",
"status": "pending",
"next_action": {
"type": "redirect_to_url",
"redirect_url": "https://helppiupay.com/charges/ch_8f3…/3ds"
}
}En modo prueba, la tarjeta 4970110000001003 fuerza el desafío 3-D Secure. Otras tarjetas de prueba válidas se aprueban sin desafío.
Recibir webhooks y conciliar
Registra tu endpoint, verifica cada entrega y mantén tus pedidos al día con el estado real de cada pago.
- Registra el endpoint en el panel o con
POST /webhook-endpoints. La URL debe ser HTTPS pública. Guarda elsecret(whsec_…): solo se muestra en esta respuesta. - Verifica la firma de cada entrega con el HMAC-SHA256 del cuerpo crudo y el header
X-Helppiu-Signature. Ver el ejemplo en Node.js y PHP. - Responde
2xxen menos de 10 segundos y procesa después. Si no, se reintenta hasta completar 5 intentos. - Actualiza tu pedido con
data.referencey eldata.statusdel último evento. Deduplica condata.transaction_id.
curl https://helppiupay.com/api/v1/webhook-endpoints \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 8d7c6b5a-4f3e-4d2c-9b1a-0f9e8d7c6b5a" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tutienda.com/webhooks/helppiu",
"events": [
"transaction.approved",
"transaction.declined",
"transaction.expired",
"payout.completed"
]
}'Conciliar
Los webhooks son la vía principal, pero conviene una conciliación periódica por si alguna entrega falló:
GET /transactionslista tus transacciones paginadas (25 por página) yGET /transactions/{uuid}trae una en detalle.GET /charges?status=approvedfiltra los cobros directos por estado.- Cada cobro trae
fee_amountynet_amountpara cuadrar lo cobrado con lo que recibes.
Si una entrega falló, puedes reenviarla desde el panel, en el historial de entregas de webhooks.
Payouts por Bre-B
Requiere habilitación
Envía dinero desde el saldo de tu bolsillo a llaves Bre-B autorizadas, con verificación del titular y código OTP en producción.
Los payouts por API se activan por comercio. Antes de integrarlos, confirma con el equipo de HelppiuPay que estén disponibles para tu cuenta. Hoy se envían solo a llaves Bre-B, de a un pago por request: no hay payouts a cuentas bancarias, en cripto ni por lote.
- Verifica al titular (opcional) con
POST /wallet/whitelist/verify: te dice a nombre de quién está la llave y en qué entidad, sin registrarla. Envía el documento del titular de la llave. - Autoriza la llave con
POST /wallet/whitelist(label,brev_key,cellphoneydoc_number). Si la llave no existe en Bre-B, responde422y no se registra. - Revisa tu saldo con
GET /wallet/balance. - Crea el payout con
POST /payouts. En producción, según el monto, la primera respuesta puede ser202conrequires_otp: true: repite el request con elotp_codede 6 dígitos. - Sigue el estado con los eventos
payout.created,payout.completedypayout.failed, o conGET /payouts/{uuid}.
curl https://helppiupay.com/api/v1/payouts \
-H "Authorization: Bearer hp_sk_test_…:sk_…" \
-H "Idempotency-Key: 1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e" \
-H "Content-Type: application/json" \
-d '{ "amount": 50000, "brev_key": "@maria", "notes": "Pago a proveedor" }'
{
"id": "…",
"reference": "…",
"status": "processing",
"gross_amount": 50000,
"cashout_fee": 800,
"net_amount": 49200,
"brev_key": "@maria",
"triggered_by": "api"
}
{
"requires_otp": true,
"message": "…"
}- En modo prueba basta con que la llave esté en la whitelist de prueba; no se pide OTP.
cashout_feees la comisión de cash-out configurada para tu comercio y se descuenta del monto.- Errores:
422por saldo insuficiente o validación;403si falla la validación de seguridad o el OTP es inválido.