Documentación de la API
Valida pagos desde tu propio sistema
ChecaPagos confirma contra el banco si un Pago Móvil, una transferencia o un depósito llegó a tu cuenta. Todo lo que puedes hacer en el panel lo puedes hacer con una petición HTTP. Esta guía te lleva de cero a tu primera validación y de ahí a integrarlo en tu checkout.
1. Empieza en 5 minutos
- Crea tu cuenta y tu negocio.
- En Cuenta BNC conecta tu cuenta: la identificación que BNC registró («Childclient» en su correo) y tu número de cuenta. Para confirmar que es tuya te pedimos enviar desde ella un monto pequeño y escribir la referencia. Antes, BNC tiene que haberte registrado como asociado de ChecaPagos.
- En API keys crea una key y cópiala. Solo se muestra una vez.
- Haz tu primera llamada con la referencia de un pago que te hayan hecho hoy:
curl https://app.checapagos.com/v1/validaciones \
-H "Authorization: Bearer cp_live_TU_KEY" \
-H "Content-Type: application/json" \
-d '{"reference":"123456","payment_date":"2026-11-06"}'
Si la respuesta trae "status": "found", ya estás integrado. El resto de la guía explica qué más puedes pedir y cómo interpretar lo que vuelve.
2. API keys y entornos
Cada petición lleva tu key en la cabecera Authorization:
Authorization: Bearer cp_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Las keys nuevas son cp_live_… y consultan tu cuenta real en BNC, así que necesitan tu cuenta BNC conectada (panel → Cuenta BNC, o POST /v1/negocio/cuenta-bnc y /confirmar). Las keys cp_test_… creadas antes siguen funcionando contra el ambiente de pruebas del banco, pero ya no se crean nuevas.
Guarda la key en el servidor, nunca en una app móvil ni en JavaScript del navegador. Si se filtra, revócala en el panel y crea otra: la antigua deja de funcionar al instante.
3. Validar un pago: con la referencia basta
Tu cliente te manda «pagué, referencia 59487». Con esa referencia y el día del pago le preguntamos al banco si ese pago entró en tu cuenta. Si además conoces el monto, mándalo: el banco solo confirma cuando coincide exacto.
POST /v1/validaciones
{
"reference": "59487",
"payment_date": "2026-10-01",
"days_back": 3,
"amount": "12.00",
"metadata": { "order_id": "1042" }
}
reference: la referencia completa o sus últimos 6 dígitos. Se comparan como número, así que59487,059487y0000059487son lo mismo. Es el único campo obligatorio.payment_date: el día en que tu cliente pagó,AAAA-MM-DD. Por defecto hoy.days_back: cuántos días consultar, de 1 a 7, contando desdepayment_datehacia atrás. Por defecto 3: el día del pago y los dos anteriores. El banco responde por un día exacto, así que si el cliente no está seguro del día, amplía la ventana. Cada día consultado tarda cerca de un segundo.amount: opcional, en bolívares con dos decimales y punto:"150.00". Si lo mandas tiene que coincidir exacto; si no, cualquier monto con esa referencia vale.metadata: lo que quieras guardar junto a la validación (tu número de pedido, el cliente). Te lo devolvemos tal cual.note: opcional, una nota para personas (hasta 500 caracteres). Se ve y se edita en la columna Nota del panel; cámbiala después conPATCH /v1/validaciones/pv_…y{"note": "…"}.
Seis dígitos no son únicos: la misma referencia puede aparecer en un pago recibido y en un cargo (una comisión, un pago que hiciste tú). Por eso el estado solo es found cuando el banco reporta un movimiento entrante; si lo único que encuentra es un cargo, responde not_found y te lo muestra igual en movement con "incoming": false.
4. Leer la respuesta
La llamada es síncrona: cuando responde, ya tiene el resultado final.
{
"id": "pv_qnjqTgTa2fqz8IBUtNOv",
"object": "payment_validation",
"status": "found",
"mode": "test",
"reference": "59487",
"amount": "12.00",
"payment_date": "2026-10-01",
"days_back": 3,
"matched_via": "bnc_api",
"movement": {
"date": "2026-10-01", "amount": 12.0, "incoming": true,
"type": "Abono Pago Movil BNC", "code": "388", "control_number": "102652871",
"reference": "59487", "bank_code": "0191",
"payer_phone": "584142786580", "payer_id": "V16113363",
"source": "bank"
},
"bank": { "status": "OK", "code": "000000", "message": "Consulta exitosa" },
"metadata": { "order_id": "1042" },
"validated_at": "2026-10-02T01:36:02-04:00",
"created_at": "2026-10-02T01:36:00-04:00"
}
| status | Significa | Qué hacer |
|---|---|---|
| Encontrado | El banco confirma un pago recibido con esos datos. | Libera el pedido. Guarda movement.control_number como comprobante. |
| No encontrado | El banco respondió, pero ningún pago recibido coincide. Si movement viene con "incoming": false, lo único con esa referencia es un cargo. | Revisa los datos con el cliente, amplía days_back, o reintenta en unos minutos si el pago es reciente. |
| Error | No se pudo consultar. bank.code dice por qué. | Reintenta más tarde. CPNOTO: tu comercio aún no está activo en producción. CPBANK: el banco no respondió. |
movement.incoming te dice si el dinero entró (true) o salió. payer_phone y payer_id son el teléfono y la cédula o RIF del pagador cuando el banco los informa (Pago Móvil, pagos entre cuentas BNC): no hace falta que se los pidas a tu cliente. movement.date es el día en que el banco registró el pago, que puede ser anterior a payment_date si lo encontró en la ventana. Para auditoría, GET /v1/validaciones/pv_… devuelve la validación cuando quieras.
5. Integrarlo en tu checkout
El flujo que recomendamos para una tienda:
- Muestra al cliente tus datos de Pago Móvil y el monto exacto del pedido.
- Pídele la referencia y el día en que pagó.
- Llama a
POST /v1/validacionesconIdempotency-Keyigual a tu número de pedido. Si tu servidor reintenta, recibes la misma validación sin volver a consultar al banco. - Si es
foundymovement.amountes igual o mayor al pedido, márcalo pagado. - Si es
not_found, dile al cliente que revise los datos y permite reintentar. Los pagos interbancarios pueden tardar unos minutos en aparecer.
Ejemplo en Node.js:
const res = await fetch("https://app.checapagos.com/v1/validaciones", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CHECAPAGOS_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `order-${order.id}`
},
body: JSON.stringify({
reference: order.reference,
amount: order.total.toFixed(2),
payment_date: order.paidOn,
metadata: { order_id: order.id }
})
});
const validation = await res.json();
if (validation.status === "found") markAsPaid(order, validation.movement.control_number);
Y en PHP:
$ch = curl_init("https://app.checapagos.com/v1/validaciones");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("CHECAPAGOS_KEY"),
"Content-Type: application/json",
"Idempotency-Key: order-" . $orderId
],
CURLOPT_POSTFIELDS => json_encode([
"reference" => $reference,
"payment_date" => $paidOn,
"metadata" => ["order_id" => $orderId]
])
]);
$validation = json_decode(curl_exec($ch), true);
if ($validation["status"] === "found") { /* pedido pagado */ }
6. Errores y límites
Los errores siempre tienen la misma forma:
{ "error": { "type": "invalid_request_error", "code": "invalid_parameter", "param": "days_back", "message": "days_back: debe estar entre 1 y 7" } }
| HTTP | code | Causa |
|---|---|---|
| 401 | invalid_api_key | Falta la key, está mal escrita o fue revocada. |
| 403 | organization_disabled | Tu cuenta está desactivada. Escríbenos. |
| 404 | resource_missing | Ese pv_… no existe o no es tuyo. |
| 422 | invalid_parameter | Un campo falta o tiene mal formato. param dice cuál. |
| 429 | rate_limit_error | Más de 120 peticiones por minuto con la misma key. Espera y reintenta. |
Una validación tarda cerca de un segundo por cada día consultado: con days_back 3, entre 2 y 3 segundos; con 7, hasta 6. Pon un tiempo de espera de al menos 20 segundos en tu cliente HTTP.
7. Avisos del banco
En producción, BNC nos avisa en tiempo real de cada pago que entra a tu cuenta. Los guardamos y los usamos para responder validaciones sin esperar al banco. Puedes listarlos:
GET /v1/notificaciones?tx_date=2026-10-02
Pronto podrás recibirlos también en tu propio servidor (webhooks salientes). Si te interesa, dínoslo.
8. Cobros: enlaces de pago con Pago Móvil
Hasta aquí el cliente te paga por su cuenta y tú verificas. Con un cobro es al revés: tú dices cuánto y por qué, nosotros te damos una URL, y tu cliente paga ahí mismo con Pago Móvil C2P (banco, teléfono, cédula y la clave de pago que genera en su banco). El dinero llega a tu cuenta BNC en el momento y el cobro queda en paid.
Creas el cobro con tres datos obligatorios: amount, description y, si quieres que el cliente vuelva a tu sitio, success_url.
curl https://app.checapagos.com/v1/cobros \
-H "Authorization: Bearer cp_test_TU_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-42" \
-d '{
"amount": "150.00",
"description": "Pedido #42",
"reference": "42",
"success_url": "https://tutienda.com/pedidos/42/gracias",
"cancel_url": "https://tutienda.com/carrito",
"metadata": { "order_id": "42" }
}'
La respuesta trae la página que debes mostrar o enviar a tu cliente en url:
{
"id": "chk_7f3kq0pzmd1vn8ta2r6xuc9b",
"object": "checkout",
"status": "open",
"mode": "test",
"url": "https://app.checapagos.com/pagar/XkQ2v9mLp0aZ4rT8wN1cH6yB3sD5fG7j",
"store_name": "Tu Tienda",
"description": "Pedido #42",
"amount": "150.00",
"currency": "VES",
"reference": "42",
"success_url": "https://tutienda.com/pedidos/42/gracias",
"cancel_url": "https://tutienda.com/carrito",
"attempts": 0,
"payment": null,
"metadata": { "order_id": "42" },
"expires_at": "2026-10-09T12:00:00-04:00",
"paid_at": null,
"canceled_at": null,
"created_at": "2026-10-02T12:00:00-04:00"
}
A dónde vuelve el cliente
Cuando el banco aprueba el pago, el cliente ve su comprobante y un botón «Volver a Tu Tienda» que lo lleva a success_url con dos parámetros añadidos: ?checkout_id=chk_…&status=paid. Si no mandas success_url, se queda con el comprobante (ideal para enlaces que compartes por WhatsApp). cancel_url aparece como «Volver sin pagar».
No confíes en la redirección para marcar el pedido pagado: cualquiera puede abrir esa URL. La fuente de verdad es el cobro. Cuando el cliente llegue a tu success_url, lee GET /v1/cobros/:id y actúa solo si status es paid:
{
"id": "chk_7f3kq0pzmd1vn8ta2r6xuc9b",
"status": "paid",
"paid_at": "2026-10-02T12:04:31-04:00",
"payment": {
"status": "succeeded",
"amount": "150.00",
"payer_bank_code": "0191",
"payer_bank_name": "Banco Nacional de Crédito",
"payer_phone": "584121234567",
"payer_id": "V12345678",
"bank_transaction_id": 26136,
"bank_reference": "442350",
"created_at": "2026-10-02T12:04:31-04:00"
}
}
Si la respuesta del banco a un cobro se pierde (por ejemplo, un timeout después de enviarlo), el cobro pasa a requires_review: el cliente pudo haber sido cobrado, así que la página deja de aceptar pagos hasta que revises tu cuenta BNC y lo resuelvas desde el panel o con POST /v1/cobros/:id/resolver ({"outcome": "paid"} o "not_paid").
Mientras el cliente no haya pagado puedes consultar el cobro las veces que quieras. Si el cliente se equivoca con la clave, el banco rechaza y puede volver a intentar (hasta 5 veces por enlace). El enlace vence a los 7 días salvo que mandes expires_at (máximo 30 días), y puedes cerrarlo antes con POST /v1/cobros/:id/cancelar.
El dinero entra en tu cuenta BNC. Para cobrar necesitas el terminal C2P que asigna BNC, que se carga al conectar la cuenta en Cuenta BNC; sin terminal, POST /v1/cobros responde 422 en mode.
9. Referencia de endpoints
| Método y ruta | Qué hace |
|---|---|
| POST /v1/validaciones | Crea y resuelve una validación: ¿entró este pago a mi cuenta? |
| GET /v1/validaciones/:id | Una validación por su pv_…. |
| GET /v1/validaciones | Lista, más reciente primero. Filtros: status, reference, limit, starting_after. |
| POST /v1/cobros | Crea un cobro y devuelve la URL de pago para tu cliente. |
| GET /v1/cobros/:id | Un cobro por su chk_…; trae payment cuando está pagado. |
| GET /v1/cobros | Lista de cobros. Filtros: status, reference, limit, starting_after. |
| POST /v1/cobros/:id/cancelar | Cancela un cobro abierto; la página deja de aceptar pagos. |
| POST /v1/cobros/:id/resolver | Resuelve un cobro requires_review (respuesta del banco perdida): paid o not_paid. |
| GET /v1/notificaciones | Pagos avisados por el banco para tu RIF (producción). |
| GET /v1/bancos | Códigos de bancos venezolanos y qué servicios admiten. |
| GET /v1/negocio | Tu comercio, el entorno de la key y la propia key. Útil para probar credenciales. |
La base es https://app.checapagos.com/v1. Todo es JSON. Las fechas van en AAAA-MM-DD y las horas en ISO 8601 con zona de Caracas. La versión va en la ruta: cambios que rompan compatibilidad saldrán como /v2; añadir campos no cuenta.
¿Algo no cuadra? Escríbenos desde el panel o a hola@checapagos.com.