API de CubaPay
Cobra por Transfermóvil y recibe confirmación automática cuando el pago llega. Sin botones de “ya pagué”: la confirmación se detecta por SMS bancario.
1. Cómo funciona
- Tu servidor crea una orden con el monto en CUP.
- CubaPay devuelve un importe exacto (con centavos únicos) y la cuenta receptora del comercio.
- El cliente transfiere ese importe exacto por Transfermóvil.
- Un terminal recibe el SMS del banco, lo valida y lo reporta firmado.
- CubaPay empareja el pago por cuenta + importe y marca la orden como
paid. - Recibes un webhook firmado y/o consultas el estado de la orden.
2. Autenticación
Todas las llamadas usan tu clave API en el encabezado Authorization. Las claves cbp_live_ son de producción y cbp_test_ de prueba. Nunca las publiques en código del navegador.
Authorization: Bearer cbp_live_tu_clave_secreta3. Integra CubaPay en tu web (paso a paso)
La integración tiene solo tres piezas, igual que servicios como Supabase o Stripe: tu clave secreta vive en tu servidor, tu página muestra el pago, y CubaPay confirma automáticamente. Nunca pongas la clave cbp_live_ en el código del navegador.
Paso 1 — Guarda tu clave en el servidor
Pide tu clave en el panel (sección Claves API) y guárdala como variable de entorno. Así el navegador nunca la ve.
# .env de tu proyecto
CUBAPAY_API_KEY=cbp_live_tu_clave_secreta
CUBAPAY_BASE_URL=https://cubapay-api.comPaso 2 — Crea la orden desde TU backend
Tu página web le pide a tu propio servidor que cree el cobro; tu servidor llama a CubaPay con la clave secreta y te devuelve el importe exacto y la cuenta. Ejemplo con Node/Next.js:
// POST /api/checkout (en TU servidor)
export async function POST(req) {
const { amount, reference } = await req.json()
const r = await fetch(process.env.CUBAPAY_BASE_URL + '/api/v1/orders', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.CUBAPAY_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount, reference }),
})
const order = await r.json()
// Devuelve al navegador SOLO lo necesario (nunca la clave)
return Response.json(order)
}Con PHP o cualquier otro lenguaje es lo mismo: un POST con el encabezado Authorization: Bearer ....
<?php
// checkout.php (en TU servidor)
$body = json_encode(['amount' => 100, 'reference' => 'pedido-123']);
$ch = curl_init(getenv('CUBAPAY_BASE_URL') . '/api/v1/orders');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CUBAPAY_API_KEY'),
'Content-Type: application/json',
],
]);
$order = curl_exec($ch);
header('Content-Type: application/json');
echo $order;Paso 3 — Muestra el pago y espera la confirmación
En el navegador llamas a TU endpoint, muestras el importe exacto y la cuenta, y consultas el estado cada 2–3 segundos hasta que sea paid. No hace falta botón de “ya pagué”: se confirma solo.
// En el navegador (tu página de checkout)
async function iniciarPago() {
// 1. Crear la orden a través de TU backend
const res = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 100, reference: 'pedido-123' }),
})
const order = await res.json()
// 2. Mostrar al cliente cuánto pagar y a qué cuenta
mostrarEnPantalla(
order.payable_amount_cup + ' CUP', // importe EXACTO
order.destination_account // cuenta receptora
)
// 3. Consultar el estado hasta que se pague
const intervalo = setInterval(async () => {
const r = await fetch('/api/checkout/' + order.id) // proxy a GET /api/v1/orders/:id
const estado = await r.json()
if (estado.status === 'paid') {
clearInterval(intervalo)
alert('¡Pago confirmado! ✅')
} else if (estado.status === 'expired') {
clearInterval(intervalo)
alert('La orden expiró, inténtalo de nuevo.')
}
}, 2500)
}El endpoint /api/checkout/:id de tu servidor solo reenvía la consulta a GET /api/v1/orders/:id con tu clave, igual que en el Paso 2.
💡 ¿Prefieres no hacer polling? Configura un webhook (ver más abajo) y CubaPay le avisa a tu servidor en el instante en que llega el pago.
4. Crear una orden
POST /api/v1/orders
curl -X POST https://cubapay-api.com/api/v1/orders \
-H "Authorization: Bearer cbp_live_tu_clave" \
-H "Content-Type: application/json" \
-d '{ "amount": 100, "reference": "pedido-123" }'Respuesta:
{
"id": "b1d2...-uuid",
"reference": "pedido-123",
"status": "pending",
"mode": "live",
"amount_cup": 100,
"payable_amount_cup": 100.37,
"payable_amount_cents": 10037,
"destination_account": "9224069998586123",
"expires_at": "2026-09-16T15:00:00Z"
}Muestra payable_amount_cup (importe exacto a transferir) y destination_account a tu cliente. El importe lleva centavos únicos para poder emparejar el pago sin ambigüedad.
5. Consultar el estado
GET /api/v1/orders/:id
curl https://cubapay-api.com/api/v1/orders/b1d2...-uuid \
-H "Authorization: Bearer cbp_live_tu_clave"Respuesta cuando el pago llega:
{ "id": "b1d2...-uuid", "status": "paid", "paid_at": "2026-09-16T14:32:10Z", ... }Estados posibles: pending, paid, expired. Puedes hacer polling cada 2–3 segundos mientras esté pending.
6. Listar pagos
GET /api/v1/payments?status=paid&limit=50
curl "https://cubapay-api.com/api/v1/payments?status=paid" \
-H "Authorization: Bearer cbp_live_tu_clave"7. Webhooks
Cuando una orden pasa a paid, enviamos un POST a tu URL configurada con este cuerpo:
{
"event": "payment.confirmed",
"data": {
"id": "b1d2...-uuid",
"reference": "pedido-123",
"amountCents": 10037,
"status": "paid",
"operationId": "...",
"paidAt": "2026-09-16T14:32:10Z"
}
}Encabezados: X-CubaPay-Signature, X-CubaPay-Timestamp, X-CubaPay-Event. Verifica la firma así:
import crypto from 'crypto'
function verify(rawBody, signature, timestamp, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + rawBody)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}8. Códigos de error
401 unauthorized— clave ausente, inválida o revocada.403 merchant_inactive— el comercio está desactivado.400 invalid_amount— monto fuera de rango (1 a 1,000,000 CUP).429 rate_limited— límite de 120 peticiones/minuto por clave.
¿Listo para producción? Solicita una clave cbp_live_ al administrador de la plataforma.