Consulta masiva de CEP: cómo validar cientos de comprobantes sin entrar al portal de Banxico
Validar un comprobante en el portal CEP de Banco de México toma alrededor de un minuto: capturar fecha, monto, bancos, cuenta destino y clave de rastreo, resolver el captcha y descargar el archivo. Con cinco pagos al día es tolerable. Con trescientos, es un puesto de trabajo completo.
Este artículo explica cómo hacer consulta masiva de CEP sin capturar nada a mano.
Por qué el portal no escala
El portal de Banxico está diseñado para consultas individuales de una persona. No tiene carga de archivos, no acepta listas y no entrega resultados en lote. Además, cada consulta exige que los datos coincidan exactamente: un peso de diferencia en el monto o un dígito mal en la CLABE devuelve "no encontrado", aunque la transferencia sí exista.
En operaciones con volumen —tiendas en línea, rifas, colegiaturas, cobranza, marketplaces— eso se traduce en tres problemas: tiempo del equipo, errores de captura y ventana de fraude mientras el pago sigue "por revisar".
La alternativa: validar por API
La consulta al CEP se puede automatizar. En apiCEP mandas los datos de la operación a un solo endpoint y recibes de vuelta el resultado ya verificado contra Banxico, junto con el CEP oficial en PDF y XML.
POST https://api.apicep.cloud/validate-transfer
Authorization: Bearer TU_API_KEY
Content-Type: application/json
Hay dos formas de mandar la información, y para consulta masiva ambas son útiles.
Modo directo: cuando ya tienes los datos en tu sistema
Si tu base de datos ya guarda la fecha, el monto, el banco y la clave de rastreo de cada pago —lo típico en un sistema de cobranza o en la conciliación contra tu estado de cuenta— no necesitas ninguna imagen. Mandas el objeto sender:
{
"beneficiary": {
"clabe": "012180015469165113",
"bank": "BBVA MEXICO",
"name": "Juan Pérez"
},
"sender": {
"date": "2026-01-17",
"amount": 1,
"bank": "HSBC",
"trackingKey": "HSBC712057",
"referenceNumber": "0170126"
},
"system": "SPEI"
}
De sender son obligatorios date, amount y bank, más al menos uno entre trackingKey y referenceNumber. En este modo imageUrl no es necesario.
Modo OCR: cuando lo que tienes son capturas de pantalla
Si tus clientes te mandan la imagen del comprobante por WhatsApp o la suben a un formulario, mandas la URL del archivo y el sistema extrae los datos y los valida:
{
"imageUrl": "https://ejemplo.com/comprobante.jpg",
"system": "SPEI",
"beneficiary": {
"clabe": "012180015469165113",
"bank": "BBVA MEXICO"
}
}
Acepta JPEG, PNG y PDF, hasta 1 MB, y el archivo debe ser accesible por HTTPS al momento de la consulta.
Si recibes pagos en varias cuentas y no sabes de antemano a cuál llegó cada uno, puedes mandar potentialBeneficiaries con todos tus candidatos y el sistema elige el correcto según lo que lea del comprobante:
{
"imageUrl": "https://ejemplo.com/comprobante.jpg",
"system": "SPEI",
"potentialBeneficiaries": [
{ "clabe": "127180016477999560", "bank": "AZTECA" },
{ "phoneNumber": "1234567890", "bank": "BBVA MEXICO" },
{ "cardNumber": "1234567890123456", "bank": "BANORTE" }
]
}
Cómo procesar el lote correctamente
La recomendación para operaciones masivas es no disparar todas las solicitudes al mismo tiempo. Procesa de forma secuencial, con una pausa de aproximadamente un segundo entre llamadas. Enviar cientos de peticiones simultáneas provoca timeouts y respuestas inconsistentes, y hace muy difícil depurar qué falló.
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
for (const pago of pagos) {
const res = await fetch('https://api.apicep.cloud/validate-transfer', {
method: 'POST',
headers: {
'Authorization': 'Bearer TU_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
system: 'SPEI',
beneficiary: { clabe: pago.clabe, bank: pago.bank },
sender: {
date: pago.fecha,
amount: pago.monto,
bank: pago.bancoEmisor,
trackingKey: pago.claveRastreo,
},
}),
});
const result = await res.json();
if (result.status === 'valid' && result.validation.banxicoConfirmed) {
console.log('Confirmado por Banxico:', result.extracted.amount);
console.log('CEP PDF:', result.downloads.cepPdf);
} else {
console.log('No verificado:', result.error ?? result.status);
}
await sleep(1000);
}
Este patrón se llama throttling del lado del cliente y es la práctica estándar en integraciones masivas.
Qué te devuelve cada validación
Además del status (valid, invalid, pending o error), la respuesta trae el bloque validation con:
banxicoConfirmed: si Banco de México confirmó la operación.cepStatus: el estado oficial,LIQUIDADO,EN PROCESO,DEVUELTOoRECHAZADO.cepPreviouslyValidated: si ese mismo CEP ya se había validado antes. Es la señal que detecta un comprobante reutilizado, el fraude más común en rifas y ventas por transferencia.cepDetails: todos los campos del XML oficial, incluidos nombres, RFC, cuentas y sello digital.
Y el bloque downloads, con el CEP en PDF, el CEP en XML y una copia del comprobante original. Ojo: esas URLs se eliminan automáticamente 15 días después de la validación, así que descarga y guarda los archivos si necesitas conservarlos.
Un detalle importante sobre el estado
Un 200 no significa "transferencia válida", significa "solicitud procesada". Siempre revisa el campo status. Y ten presente que valid depende de que el CEP exista al momento de la consulta: si Banxico aún no lo generó, el resultado será invalid aunque la transferencia sea real. En esos casos conviene reintentar minutos más tarde.
Cuándo conviene automatizar
Si validas menos de diez pagos al día, el portal alcanza. A partir de ahí, el cálculo cambia: automatizar te devuelve horas de trabajo y cierra la ventana en la que un comprobante falso pasa desapercibido.
Puedes revisar la referencia completa de la API, o probar primero la validación desde el navegador si todavía no quieres integrar nada.