Referencia de la API de apiCEP
La API de apiCEP permite validar comprobantes de transferencia SPEI mediante la combinación de análisis OCR de imágenes con verificación en tiempo real contra el sistema CEP (Comprobante Electrónico de Pago) de Banxico. Envía la imagen del comprobante junto con los datos del beneficiario, y la API devuelve un resultado validado y estructurado, incluyendo el CEP oficial.
URL Base
https://api.apicep.cloud
Autenticación
Todas las solicitudes requieren una API key válida enviada en el encabezado Authorization usando el esquema Bearer.
Authorization: Bearer TU_API_KEY
Las solicitudes sin una clave válida retornan 401 Unauthorized. Si excedes la cuota de tu plan, la API retorna 429 Too Many Requests.
Límite de Solicitudes (Rate Limiting)
La información del límite se devuelve en cada respuesta a través de estos encabezados:
| Encabezado | Descripción |
|---|---|
| X-RateLimit-Limit | Total de solicitudes permitidas en el periodo actual |
| X-RateLimit-Remaining | Solicitudes restantes en el periodo actual |
| X-RateLimit-Reset | Timestamp (ISO 8601) en que se restablece la cuota |
Endpoint
/validate-transferValida un comprobante de transferencia SPEI contra el registro CEP de Banxico.
POST https://api.apicep.cloud/validate-transfer
Solicitud (Request)
Encabezados
| Encabezado | Valor | Requerido |
|---|---|---|
| Authorization | Bearer TU_API_KEY | ✅ Sí |
| Content-Type | application/json | ✅ Sí |
Modos de Validación
El endpoint soporta dos modos de validación según los campos enviados en el body:
- Modo OCR — envía
imageUrlcon la URL del comprobante. La API extrae los datos automáticamente y los valida contra Banxico. - Modo Directo (sin OCR) — envía el objeto
sendercon los datos de la transferencia. En este modoimageUrlno es requerido.
Esquema del Body — Modo OCR
{"imageUrl": "https://ejemplo.com/comprobante.jpg","beneficiary": {"clabe": "012180015469165113","bank": "BBVA MEXICO","name": "Juan Pérez"}}
Esquema del Body — Modo Directo (con sender)
{"beneficiary": {"clabe": "012180015469165113","bank": "BBVA MEXICO","name": "Juan Pérez"},"sender": {"date": "2026-01-17","amount": 1,"bank": "HSBC","trackingKey": "HSBC712057","referenceNumber": "0170126"}}
Esquema del Body — Modo OCR con potentialBeneficiaries
{"imageUrl": "https://ejemplo.com/comprobante.jpg","potentialBeneficiaries": [{"clabe": "127180016477999560","bank": "AZTECA"},{"phoneNumber": "1234567890","bank": "BBVA"},{"cardNumber": "1234567890123456","bank": "BANORTE"},{"clabe": "123456789012345678","bank": "BANORTE"}]}
Campos de Nivel Superior
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| imageUrl | string | Condicional | URL pública del comprobante de transferencia (JPEG, PNG o PDF). Requerido cuando no se envía sender. Tamaño máximo: 1 MB. |
| beneficiary | object | Condicional | Datos del beneficiario del pago. Requerido cuando no se envía potentialBeneficiaries. |
| sender | object | Condicional | Datos del ordenante para validar sin OCR. Si se envía, imageUrl no es requerido. |
| potentialBeneficiaries | array | Condicional | Array de objetos beneficiary para validación multi-cuenta. Solo funciona en modo OCR. Si se envía, beneficiary no es requerido. |
Objeto beneficiary
clabe, phoneNumber o cardNumber.| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| clabe | string | Condicional | CLABE interbancaria de 18 dígitos |
| phoneNumber | string | Condicional | Número de teléfono móvil de 10 dígitos |
| cardNumber | string | Condicional | Número de tarjeta de débito de 16 dígitos |
| bank | string | ✅ Sí | Nombre del banco beneficiario. Ver Bancos Válidos |
| name | string | No | Nombre esperado del beneficiario (referencia interna) |
Objeto sender
trackingKey o referenceNumber (pueden enviarse ambos, pero al menos uno es obligatorio).| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| date | string | ✅ Sí | Fecha de la operación (YYYY-MM-DD) |
| amount | number | ✅ Sí | Monto de la transferencia en MXN |
| bank | string | ✅ Sí | Banco ordenante. Ver Bancos Válidos |
| trackingKey | string | Condicional | Clave de rastreo SPEI. Obligatorio si no se envía referenceNumber. |
| referenceNumber | string | Condicional | Número de referencia del pago. Obligatorio si no se envía trackingKey. |
Reglas de formato
clabe— exactamente 18 dígitosphoneNumber— exactamente 10 dígitoscardNumber— exactamente 16 dígitos
Array potentialBeneficiaries
imageUrl).potentialBeneficiaries, la propiedad beneficiary no es obligatoria. El sistema buscará coincidencias entre los datos extraídos por OCR y los candidatos proporcionados.| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| clabe | string | Condicional | CLABE interbancaria de 18 dígitos |
| phoneNumber | string | Condicional | Número de teléfono móvil de 10 dígitos |
| cardNumber | string | Condicional | Número de tarjeta de débito de 16 dígitos |
| bank | string | ✅ Sí | Nombre del banco beneficiario. Ver Bancos Válidos |
clabe, phoneNumber o cardNumber.Cómo funciona la selección
El sistema compara los datos extraídos por OCR (banco destino, nombre del beneficiario, CLABE o cuenta detectada) contra cada candidato en potentialBeneficiaries. El candidato con mayor coincidencia se utiliza como beneficiario definitivo para la validación CEP. Si ningún candidato coincide, la validación retornará status: "error".
Bancos Válidos
El campo beneficiary.bank acepta el nombre del banco beneficiario.
Códigos de Estado HTTP
| Código | Significado |
|---|---|
| 200 | Solicitud procesada correctamente. Revisa el campo status en el body para conocer el resultado. |
| 400 | Solicitud inválida — campos faltantes o con formato incorrecto. |
| 401 | No autorizado — API key ausente o inválida. |
| 405 | Método no permitido — solo se acepta POST. |
| 429 | Límite de solicitudes excedido. |
| 500 | Error interno del servidor. |
status.Encabezados de Respuesta
| Encabezado | Descripción |
|---|---|
| X-Processing-Time | Tiempo total de procesamiento en el servidor (ej. 2340ms) |
| X-RateLimit-Remaining | Solicitudes restantes en la ventana de cuota actual |
| X-RateLimit-Reset | Timestamp ISO 8601 del restablecimiento de cuota |
| X-RateLimit-Limit | Total de solicitudes permitidas por periodo |
Esquema del Body de Respuesta
{"validationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","status": "valid","confidence": 0.97,"extracted": {"senderBank": "HSBC","receiverBank": "BBVA MEXICO","trackingKey": "2024010112345678","referenceNumber": "987654321","amount": 1500.00,"date": "2024-01-15","senderName": "María García","beneficiaryName": "Juan Pérez","paymentConcept": "Pago de renta"},"validation": {"banxicoConfirmed": true,"cepStatus": "LIQUIDADA","cepPreviouslyValidated": false,"cepDetails": { "..." : "..." }},"downloads": {"cepXml": "https://storage.apicep.cloud/...","cepPdf": "https://storage.apicep.cloud/...","originalImage": "https://storage.apicep.cloud/..."},"processingTime": {"ocr": "1.20s","validation": "3.45s","total": "4.68s"}}
Campos de la Respuesta
Nivel Superior
| Campo | Tipo | Descripción |
|---|---|---|
| validationId | string | Identificador único de esta validación (UUID) |
| status | string | Resultado de la validación (ver Valores de Status) |
| confidence | number | Puntaje de confianza del OCR de 0.0 a 1.0 |
| extracted | object | Datos extraídos del comprobante mediante OCR |
| validation | object | Resultado de la consulta al registro CEP de Banxico |
| downloads | object | URLs de descarga para el CEP y la imagen del comprobante |
| processingTime | object | Desglose del tiempo por etapa de procesamiento |
| missingFields | string[] | Lista de campos obligatorios que el OCR no pudo extraer (solo presente cuando status es "error" por datos faltantes) |
| error | string | Descripción del error (solo presente cuando status es "error") |
Objeto extracted
Todos los campos son opcionales — su presencia depende de lo que el OCR haya podido leer.
| Campo | Tipo | Descripción |
|---|---|---|
| senderBank | string | Nombre del banco emisor |
| receiverBank | string | Nombre del banco destino |
| trackingKey | string | Clave de rastreo SPEI |
| referenceNumber | string | Número de referencia del pago |
| amount | number | Monto de la transferencia en MXN |
| date | string | Fecha de operación (YYYY-MM-DD) |
| senderName | string | Nombre del ordenante |
| beneficiaryName | string | Nombre del beneficiario |
| paymentConcept | string | Concepto del pago |
Objeto validation
| Campo | Tipo | Descripción |
|---|---|---|
| banxicoConfirmed | boolean | true si Banxico confirmó la transferencia |
| cepStatus | string | Estatus oficial del CEP (ej. "LIQUIDADA") |
| cepPreviouslyValidated | boolean | null | null si no se obtuvo digitalSignature del CEP; false si este CEP no había sido validado anteriormente; true si ya fue validado en una solicitud previa |
| cepDetails | object | Datos del XML oficial del CEP (ver abajo) |
Objeto cepDetails
Solo se incluye cuando banxicoConfirmed es true.
| Campo | Tipo | Descripción |
|---|---|---|
| operationDate | string | Fecha en que se ejecutó la operación |
| processingDate | string | Fecha en que SPEI procesó la operación |
| processingTime | string | Hora de procesamiento (HH:MM:SS) |
| speiKey | string | Clave interna del sistema SPEI |
| trackingKey | string | Clave de rastreo SPEI |
| senderBank | string | Nombre del banco emisor |
| senderName | string | Nombre completo del ordenante |
| senderAccountType | string | Tipo de cuenta del ordenante |
| senderAccount | string | Número de cuenta del ordenante |
| senderRfc | string | RFC del ordenante |
| receiverBank | string | Nombre del banco receptor |
| beneficiaryName | string | Nombre del beneficiario |
| beneficiaryAccountType | string | Tipo de cuenta del beneficiario |
| beneficiaryAccount | string | Número de cuenta del beneficiario |
| beneficiaryRfc | string | RFC del beneficiario |
| amount | number | Monto de la transferencia en MXN |
| iva | number | Monto del IVA, si aplica |
| paymentConcept | string | Concepto del pago según el CEP |
| digitalSignature | string | Sello digital SAT del CEP |
| certificateNumber | string | Número de certificado de la firma digital |
Objeto downloads
| Campo | Tipo | Descripción |
|---|---|---|
| cepXml | string | URL al archivo XML oficial del CEP |
| cepPdf | string | URL al archivo PDF oficial del CEP |
| originalImage | string | URL a la copia almacenada del comprobante enviado |
Todas las URLs se sirven desde https://storage.apicep.cloud.
cepXml, cepPdf y originalImage se eliminan automáticamente 15 días después de la validación. Descarga y almacena los archivos en tu propio sistema si necesitas conservarlos por más tiempo.Objeto processingTime
| Campo | Tipo | Descripción |
|---|---|---|
| ocr | string | Tiempo en análisis OCR (ej. "1.20s") |
| validation | string | Tiempo en consultar CEP de Banxico (ej. "3.45s") |
| total | string | Tiempo total (ej. "4.68s") |
Valores de Status
| Status | Significado |
|---|---|
valid | La transferencia fue confirmada por Banxico — el comprobante es auténtico. |
invalid | La transferencia no fue encontrada en el registro CEP de Banxico. |
pending | La validación aún está en progreso (reservado para flujos asíncronos). |
error | Ocurrió un error durante el procesamiento — revisa el campo error. |
"valid" depende directamente de la existencia del CEP. Si el CEP no existe al momento de la consulta, el estatus será "invalid". El CEP normalmente se genera segundos después de la transferencia, pero existen escenarios en los que Banxico puede tardar horas en generarlo.Cómo Funciona
El endpoint /validate-transfer ejecuta el siguiente flujo:
- 1
Descarga de imagen
Descarga el comprobante desde la imageUrl proporcionada y almacena una copia en storage.apicep.cloud.
- 2
Extracción OCR
Analiza la imagen para extraer campos SPEI (clave de rastreo, monto, fecha, bancos, nombres).
- 3
Consulta CEP
Verifica el registro CEP de Banxico usando los datos extraídos y la cuenta del beneficiario proporcionada.
- 4
Parseo XML
Si se encuentra un CEP, descarga y parsea el XML oficial para obtener el objeto cepDetails estructurado.
- 5
Respuesta
Retorna el resultado de validación, datos extraídos, detalles del CEP y URLs de descarga.
Referencia de Errores
400 Bad Request
| Mensaje de Error | Causa |
|---|---|
| imageUrl is required | El campo imageUrl no fue enviado en el body |
| beneficiary must include one of: clabe, phoneNumber, or cardNumber | No se proporcionó ningún identificador de cuenta |
| beneficiary must include only one of: clabe, phoneNumber, or cardNumber | Se proporcionó más de un identificador de cuenta |
| beneficiary.clabe must be exactly 18 digits | La CLABE tiene un formato inválido |
| beneficiary.phoneNumber must be exactly 10 digits | El número de teléfono tiene un formato inválido |
| beneficiary.cardNumber must be exactly 16 digits | El número de tarjeta tiene un formato inválido |
| beneficiary.bank is required | El campo beneficiary.bank no fue enviado |
| El archivo proporcionado no es una imagen válida (content-type: <tipo>). Solo se admiten formatos de imagen: JPEG, PNG, GIF, WebP, BMP, TIFF, HEIC. | La URL en imageUrl apunta a un archivo cuyo Content-Type no corresponde a un formato de imagen soportado |
403 Forbidden
Retornado cuando el usuario no tiene un plan activo con solicitudes disponibles:
| Código | Mensaje | Causa |
|---|---|---|
| NO_ACTIVE_PLAN | No active plan with remaining requests. Purchase a new plan at apicep.cloud | El API key es válido pero el plan asociado no tiene solicitudes disponibles o ha expirado. Adquiere un nuevo plan en apicep.cloud |
200 con status: "error"
Estos son errores de procesamiento que se retornan con código 200:
| Error | Causa |
|---|---|
| Failed to download image | La imageUrl no era accesible al momento del procesamiento |
| Failed to extract data from image | El OCR retornó confianza cero — calidad de imagen insuficiente |
| El OCR no pudo extraer los siguientes datos obligatorios... | El OCR no pudo leer uno o más campos requeridos: fecha de la operación, clave de rastreo o número de referencia, institución emisora del pago, monto del pago. La respuesta incluye el arreglo missingFields con los campos faltantes. |
Ejemplo de respuesta con campos faltantes
Cuando el OCR no puede extraer todos los datos obligatorios, la API retorna status: "error" con un mensaje descriptivo y el arreglo missingFields indicando exactamente qué campos faltan. Los campos obligatorios son: fecha de la operación, clave de rastreo o número de referencia, institución emisora del pago y monto del pago.
{"validationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","status": "error","confidence": 0.45,"extracted": {"senderBank": "HSBC","amount": 1500.00},"validation": { "banxicoConfirmed": false },"processingTime": {"ocr": "1.10s","total": "1.15s"},"error": "El OCR no pudo extraer los siguientes datos obligatorios del comprobante: fecha de la operación, clave de rastreo o número de referencia. Por favor envía una imagen más clara.","missingFields": ["fecha de la operación","clave de rastreo o número de referencia"]}
Ejemplos de Código
curl -X POST https://api.apicep.cloud/validate-transfer \-H "Authorization: Bearer TU_API_KEY" \-H "Content-Type: application/json" \-d '{"imageUrl": "https://ejemplo.com/comprobante.jpg","beneficiary": {"clabe": "012180015469165113","bank": "BBVA MEXICO","name": "Juan Pérez"}}'
Buenas Prácticas para Operaciones Masivas
Si necesitas validar múltiples comprobantes de transferencia en un solo proceso, te recomendamos no enviar todas las solicitudes al mismo tiempo. En su lugar, procésalas de forma secuencial con un intervalo de espera entre cada llamada. Sugerimos 1 segundo entre cada una.
¿Por qué? Enviar demasiadas solicitudes simultáneas puede generar condiciones de carrera, timeouts o respuestas inconsistentes.
¿Cómo implementarlo? Usa una función sleep entre cada llamada dentro de tu ciclo:
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));const comprobantes = [{ imageUrl: 'https://ejemplo.com/comprobante1.jpg', clabe: '012180015469165113', bank: 'BBVA MEXICO', name: 'Juan Pérez' },{ imageUrl: 'https://ejemplo.com/comprobante2.jpg', clabe: '014180015469165114', bank: 'BANAMEX', name: 'María García' },{ imageUrl: 'https://ejemplo.com/comprobante3.jpg', clabe: '006180015469165115', bank: 'BANORTE', name: 'Carlos López' },// ...más comprobantes];for (const comprobante of comprobantes) {const response = await fetch('https://api.apicep.cloud/validate-transfer', {method: 'POST',headers: {'Authorization': 'Bearer TU_API_KEY','Content-Type': 'application/json',},body: JSON.stringify({imageUrl: comprobante.imageUrl,beneficiary: {clabe: comprobante.clabe,bank: comprobante.bank,},}),});const result = await response.json();if (result.status === 'valid' && result.validation.banxicoConfirmed) {console.log(`Transferencia verificada por Banxico ✅`);console.log('Monto:', result.extracted.amount);console.log('CEP PDF:', result.downloads.cepPdf);} else {console.log(`No se pudo verificar la transferencia ❌`);console.log('Razón:', result.error);}await sleep(1_000); // ⏳ espera 1 segundo antes del siguiente comprobante}
Este patrón se llama throttling del lado del cliente y es una buena práctica estándar en integraciones que manejan operaciones masivas. Garantiza que tu proceso sea estable, predecible y fácil de depurar en caso de errores.
Notas
- Las imágenes del comprobante deben ser accesibles públicamente vía HTTPS al momento de la solicitud.
- Las URLs pre-firmadas son compatibles siempre que sigan vigentes durante el procesamiento.