HelppiuPayDocs

Documentación

Todo lo necesario para integrar la API REST de HelppiuPay: autenticación, modo prueba, estados, webhooks firmados, idempotencia y errores.

Introducción

La API de HelppiuPay es REST, recibe y responde JSON y usa una sola URL base para pruebas y producción.

https://helppiupay.com/api/v1

Hay tres formas de integrar, según cuánto quieras construir:

CaminoCuándo usarloEndpoints
Checkout hospedadoQuieres cobrar sin construir el formulario de pago. Creas una sesión, rediriges al comprador a la URL que devuelve la API y HelppiuPay se encarga de los métodos de pago y de 3-D Secure.POST /checkout-sessions
Cobro directoQuieres controlar toda la experiencia de pago desde tu servidor (server-to-server).POST /tokens, POST /charges
Payouts Bre-BNecesitas enviar dinero desde el saldo de tu bolsillo a llaves Bre-B autorizadas.POST /payouts

En los tres casos recibes los cambios de estado por webhooks firmados y puedes consultar cada operación por su identificador.

Primeros pasos

En unos minutos puedes crear tu primer cobro de prueba.

  1. Crea tus llaves de API. En el panel de tu comercio, entra a Llaves de API y genera una llave secreta de prueba (hp_sk_test_…). Desde ahí también puedes revocarlas.
  2. Crea una sesión de checkout. Envía el siguiente request desde tu servidor, con tu llave en el formato key_id:secret.
  3. Abre el checkout. La respuesta trae el campo url. Ábrelo en el navegador para ver el checkout hospedado.
  4. Recibe el resultado. Registra un endpoint de webhooks para enterarte cuando el pago cambie de estado.
curl https://helppiupay.com/api/v1/checkout-sessions \
  -H "Authorization: Bearer hp_sk_test_…:sk_…" \
  -H "Idempotency-Key: 6f1c2b8e-4d1a-4c55-9f0e-2a7b1d3e9c10" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "ORDER-1001",
    "amount": 50000,
    "currency": "COP",
    "payment_method_types": ["card", "pse", "nequi"],
    "customer_phone": "3001234567",
    "success_url": "https://tutienda.com/ok",
    "cancel_url": "https://tutienda.com/cancel"
  }'
const res = await fetch('https://helppiupay.com/api/v1/checkout-sessions', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.HELPPIU_KEY_ID}:${process.env.HELPPIU_SECRET}`,
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    reference: 'ORDER-1001',
    amount: 50000,
    currency: 'COP',
    payment_method_types: ['card', 'pse', 'nequi'],
    customer_phone: '3001234567',
    success_url: 'https://tutienda.com/ok',
    cancel_url: 'https://tutienda.com/cancel',
  }),
});
const session = await res.json();
// Redirige al comprador a session.url
$ch = curl_init('https://helppiupay.com/api/v1/checkout-sessions');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('HELPPIU_KEY_ID') . ':' . getenv('HELPPIU_SECRET'),
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'reference' => 'ORDER-1001',
        'amount' => 50000,
        'currency' => 'COP',
        'payment_method_types' => ['card', 'pse', 'nequi'],
        'customer_phone' => '3001234567',
        'success_url' => 'https://tutienda.com/ok',
        'cancel_url' => 'https://tutienda.com/cancel',
    ]),
]);
$session = json_decode(curl_exec($ch), true);
// Redirige al comprador a $session['url']

reference, amount, success_url y cancel_url son obligatorios. customer_phone lo es cuando ofreces PSE, Nequi, Daviplata, Bre-B o QR. La respuesta es 201 con la sesión creada.

Autenticación y llaves

Cada request se autentica con el header Authorization de tipo Bearer. El valor es el identificador de la llave y su secreto, separados por dos puntos:

Authorization: Bearer <key_id>:<secret>

Si falta el separador, la API responde 401 con Invalid API key format. Expected key_id:secret.

Tipos de llave

PrefijoTipoUso
hp_sk_test_ · hp_sk_live_SecretaTodas las llamadas desde tu servidor. Nunca la expongas en el navegador ni en una app.
hp_pk_test_ · hp_pk_live_PublicablePara el navegador del comprador: úsala solo para tokenizar la tarjeta con POST /tokens. Todo lo demás, con la llave secreta desde tu servidor.

Los endpoints de cobros (/charges), bancos PSE (/banks/pse) y tarjetas guardadas (/saved-cards) rechazan las llaves publicables con 403. Usa siempre la llave secreta para las llamadas de servidor.

Buenas prácticas

  • Guarda el secreto en variables de entorno o en un gestor de secretos, nunca en el código ni en el repositorio.
  • Usa llaves distintas para prueba y producción, y revoca desde el panel cualquier llave expuesta.
  • Si tu comercio está suspendido, la llave sigue siendo válida pero la API responde 403.

Modo prueba y producción

No hay un servidor separado de pruebas. El ambiente lo define la llave, no la URL: todas las llamadas van a https://helppiupay.com/api/v1.

AmbienteLlavesResultado
Pruebahp_*_test_*Las operaciones se crean con environment: "test".
Producciónhp_*_live_*Las operaciones se crean con environment: "live" y mueven dinero real.

Tarjeta de prueba con 3-D Secure

Para probar el desafío 3-D Secure usa la tarjeta 4970110000001003, CVV 123 y cualquier fecha de vencimiento futura. Otras tarjetas de prueba válidas se aprueban sin desafío.

El comportamiento de cada método de pago en modo prueba puede variar. Si necesitas simular un caso específico, escríbenos a soporte@helppiupay.com.

Conceptos y estados

Objetos principales

  • Checkout session: una página de pago hospedada por HelppiuPay para un monto y una referencia. Tiene su propio url y una fecha de expiración.
  • Cobro (charge) y transacción: el intento de pago concreto. Un cobro directo crea una transacción; una checkout session también la crea cuando el comprador paga. Ambos comparten los mismos estados.
  • Payout: un envío de dinero desde el saldo de tu bolsillo a una llave Bre-B autorizada.

Estados de un cobro

EstadoSignificadoPuede pasar a
createdCreado, aún sin procesar.processing, pending, approved, declined, error, expired
processingEn proceso con el medio de pago.pending, approved, declined, error, expired
pendingEsperando una acción del comprador o la confirmación del medio de pago.approved, declined, reversed, expired
approvedPago aprobado.reversed, partially_refunded
declinedRechazado.approved
errorError técnico al procesar.approved, declined
expiredEl comprador no completó el pago a tiempo.approved, declined
reversedReversado o anulado.—
partially_refundedReembolsado en parte.—

declined, expired y error no siempre son definitivos. Un pago puede aprobarse después; por ejemplo, un pago Bre-B que el comprador completa cuando la llave ya había expirado. Toma como fuente de verdad el último evento que recibas, no el primero.

Estados de una checkout session

open (esperando el pago), completed (pagada), expired (venció o la expiraste con POST /checkout-sessions/{uuid}/expire) y cancelled.

Estados de un payout

pending, processing, completed, failed y cancelled.

Webhooks

HelppiuPay te avisa de cada cambio de estado con un POST HTTP firmado a la URL que registres. Puedes registrarla en el panel, en Configuración › Webhooks, o con POST /webhook-endpoints. La URL debe ser HTTPS y pública; para pruebas locales usa un túnel.

Eventos

EventoCuándo se envía
transaction.approvedPago aprobado (alias: transaction.paid).
transaction.declinedPago rechazado.
transaction.failedError técnico al procesar.
transaction.reversedReverso o anulación.
transaction.expiredLa transacción expiró sin completarse.
transaction.updatedCambio de estado intermedio.
payout.createdPayout Bre-B creado.
payout.completedPayout Bre-B liquidado en el destino.
payout.failedPayout Bre-B fallido.

Suscríbete a * para recibir todos. Ignora los eventos que no reconozcas en lugar de responder con error.

Headers y payload

POST /webhooks/helppiu
Content-Type: application/json
X-Helppiu-Event: transaction.approved
X-Helppiu-Signature: 9f3a7c1e…

{
  "event": "transaction.approved",
  "created_at": "2026-05-09T19:14:55-05:00",
  "data": {
    "transaction_id": "70a24661-7fbd-4d71-bd5d-7b5a534d5e2d",
    "reference": "ORDER-1001",
    "checkout_session_reference": "cs_abc123",
    "amount": 50000,
    "currency": "COP",
    "status": "approved",
    "payment_method": "pse",
    "customer_email": "cliente@example.com",
    "paid_at": "2026-05-09T19:03:10-05:00"
  }
}

Verificar la firma

X-Helppiu-Signature es el HMAC-SHA256 en hexadecimal del cuerpo crudo del request, calculado con el secreto del endpoint (whsec_…). Ese secreto se entrega una sola vez, al crear el endpoint. Compara con una función de tiempo constante y rechaza la entrega si no coincide.

const crypto = require('crypto');

// Usa el cuerpo crudo, antes de parsear el JSON
const expected = crypto
  .createHmac('sha256', process.env.HELPPIU_WEBHOOK_SECRET)
  .update(req.rawBody)
  .digest('hex');
const received = req.headers['x-helppiu-signature'] || '';

if (expected.length !== received.length ||
    !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) {
  return res.sendStatus(401);
}
res.sendStatus(200); // responde rápido y procesa después
$raw      = file_get_contents('php://input');
$expected = hash_hmac('sha256', $raw, getenv('HELPPIU_WEBHOOK_SECRET'));
$received = $_SERVER['HTTP_X_HELPPIU_SIGNATURE'] ?? '';

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}
$event = json_decode($raw, true);
http_response_code(200); // responde rápido y procesa después

Reintentos

Tu endpoint debe responder con un código 2xx en menos de 10 segundos. Si no, HelppiuPay vuelve a intentar la entrega. En total son hasta 5 intentos: el original y 4 reintentos, a los 10 segundos, 1 minuto, 5 minutos y 30 minutos. Después, la entrega queda como fallida y puedes reenviarla manualmente desde el panel.

Procesamiento seguro

  • El mismo evento puede llegar más de una vez. Deduplica con data.transaction_id.
  • Responde primero y procesa en segundo plano para no superar los 10 segundos.
  • Guarda el estado del último evento recibido: un pago rechazado o expirado puede aprobarse después.

Idempotencia

Para reintentar un POST sin riesgo de crear dos cobros o dos payouts, envía el header Idempotency-Key con un valor único, por ejemplo un UUID.

Idempotency-Key: 6f1c2b8e-4d1a-4c55-9f0e-2a7b1d3e9c10
  • La llave se guarda 24 horas por comercio. Si repites un request con la misma llave, recibes la misma respuesta y el header X-Idempotency-Replayed: true.
  • También se guardan las respuestas de error 4xx: si un request falló por validación, corrige los datos y usa una llave nueva.
  • La llave no depende del endpoint ni del cuerpo: usa una llave nueva para cada operación y nunca la reutilices entre endpoints distintos.
  • Aplica a todos los endpoints autenticados, salvo POST /tokens.

Errores y paginación

Los errores responden con un código HTTP y un cuerpo JSON con el mensaje en error:

{
  "error": "Saldo insuficiente."
}
CódigoCuándo ocurre
201Recurso creado.
202El payout necesita un código OTP para continuar (requires_otp: true).
401Falta la llave, es inválida o no tiene el formato key_id:secret.
403Llave publicable en un endpoint que exige la secreta, comercio suspendido u OTP inválido.
404El recurso no existe.
422Datos inválidos, cobro declinado o saldo insuficiente. El cuerpo indica el detalle.

Hoy los errores no traen un código interno estable: usa el código HTTP para decidir y registra el mensaje para soporte.

Paginación

Los listados (GET /charges, GET /transactions, GET /payouts…) reciben el parámetro page y devuelven los resultados en data y la paginación en meta. El tamaño de página es fijo: 20 en cobros y 25 en el resto.

{
  "data": [ … ],
  "meta": { "current_page": 1, "last_page": 4, "per_page": 20, "total": 73 }
}

Glosario

Bre-BEl sistema de pagos inmediatos de Colombia. En la API se identifica como brev (también se acepta breb).
Llave Bre-BEl identificador del destinatario en Bre-B (por ejemplo @maria o un celular).
BolsilloEl saldo de tu comercio en HelppiuPay, desde el que salen los payouts.
WhitelistLa lista de llaves Bre-B autorizadas para recibir payouts de tu comercio.
Payout o dispersiónUn envío de dinero desde tu bolsillo a un tercero.
Checkout hospedadoLa página de pago de HelppiuPay a la que rediriges al comprador.
Cobro directoUn pago creado desde tu servidor con POST /charges, sin pasar por el checkout.
Token de tarjetaEl identificador tok_… que reemplaza los datos de la tarjeta.
3-D SecureLa verificación adicional que algunos bancos exigen al pagar con tarjeta.
IdempotenciaLa garantía de que repetir un request con la misma llave no duplica la operación.
OTPEl código de un solo uso que pueden exigir los payouts en producción.
WebhookLa notificación HTTP que HelppiuPay envía a tu servidor cuando algo cambia.
Soporte de integración