API de CEP · Documentación
Valida transferencias SPEI y obtén el Comprobante Electrónico de Pago
(CEP) oficial de Banco de México de forma programática — en JSON, PDF, XML o ZIP.
Sin SDKs: funciona con curl, fetch o cualquier cliente HTTP.
Primeros pasos
De cero a validar un CEP en tres pasos. Usa los datos de tu comprobante SPEI (fecha, clave de rastreo, montos y cuentas).
1 · Obtén los códigos de banco
Lista las instituciones para conocer el code del emisor y receptor.
curl $BASE/api/banks
# [{ "code": "40002", "name": "BANAMEX" }, { "code": "90684", "name": "TRANSFER" }, ...]2 · Valida la transferencia
Envía los datos del pago y recibe el CEP en JSON.
curl -X POST $BASE/api/cep/validate \
-H "Content-Type: application/json" \
-d '{
"fecha": "2026-06-10",
"clave_rastreo": "085909274480316161",
"emisor": "40002",
"receptor": "90684",
"cuenta": "684180142033702249",
"monto": "9000.00"
}'3 · Descarga el comprobante
Con los mismos datos, baja el PDF oficial (o XML / ZIP).
curl -G $BASE/api/cep/download \
--data-urlencode "fecha=2026-06-10" \
--data-urlencode "clave_rastreo=085909274480316161" \
--data-urlencode "emisor=40002" \
--data-urlencode "receptor=90684" \
--data-urlencode "cuenta=684180142033702249" \
--data-urlencode "monto=9000.00" \
--data-urlencode "formato=PDF" \
-o cep.pdfBase URL
Todas las rutas son relativas a tu host. En estos ejemplos:
http://localhost:8000Autenticación
Los endpoints de CEP se protegen con API key. Si el servidor
tiene llaves configuradas, debes enviar una válida; si no, opera en modo abierto.
Los endpoints /api/health y /api/banks son siempre públicos.
Puedes enviar la llave de tres formas (en orden de preferencia):
| Método | Ejemplo |
|---|---|
Header X-API-Key | X-API-Key: TU_API_KEY |
| Bearer token | Authorization: Bearer TU_API_KEY |
| Query param (para descargas) | ?api_key=TU_API_KEY |
401 unauthorized. Solicita tu API key al administrador del servicio.
Health
Verifica que el servicio está disponible.
curl $BASE/api/health
const r = await fetch("$BASE/api/health");
console.log(await r.json());
import requests
requests.get("$BASE/api/health").json()
Respuesta 200
{ "status": "ok", "version": "0.1.0" }Listar bancos
Devuelve el catálogo de instituciones participantes en SPEI. Usa los
code para los campos emisor y receptor.
La respuesta se cachea (1 h) en el navegador.
curl $BASE/api/banks
const banks = await (await fetch("$BASE/api/banks")).json();
import requests
banks = requests.get("$BASE/api/banks").json()
Respuesta 200
[
{ "code": "40002", "name": "BANAMEX" },
{ "code": "40012", "name": "BBVA BANCOMER" },
{ "code": "90684", "name": "TRANSFER" }
]Validar CEP
Valida una transferencia contra Banxico y devuelve los datos estructurados del comprobante en JSON. Ver parámetros para el detalle de campos.
curl -X POST $BASE/api/cep/validate \
-H "Content-Type: application/json" \
-H "X-API-Key: TU_API_KEY" \
-d '{
"fecha": "2026-06-10",
"clave_rastreo": "085909274480316161",
"emisor": "40002",
"receptor": "90684",
"cuenta": "684180142033702249",
"monto": "9000.00"
}'
const res = await fetch("$BASE/api/cep/validate", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": "TU_API_KEY" },
body: JSON.stringify({
fecha: "2026-06-10",
clave_rastreo: "085909274480316161",
emisor: "40002", receptor: "90684",
cuenta: "684180142033702249", monto: "9000.00"
})
});
const cep = await res.json();
import requests
cep = requests.post("$BASE/api/cep/validate",
headers={"X-API-Key": "TU_API_KEY"},
json={
"fecha": "2026-06-10",
"clave_rastreo": "085909274480316161",
"emisor": "40002", "receptor": "90684",
"cuenta": "684180142033702249", "monto": "9000.00",
}).json()
Respuesta 200
{
"clave_rastreo": "085909274480316161",
"fecha_operacion": "20260610",
"hora_operacion": "15:32:34",
"monto": "9000.00",
"iva": "0.00",
"concepto": "pago",
"emisor": "BANAMEX",
"receptor": "TRANSFER",
"ordenante_nombre": "ANGEL ISSAC,PEREZ/MARTINEZ",
"ordenante_cuenta": "002910702140629588",
"beneficiario_nombre": "TODO MUNDO FINTECH-PRO SA DE CV",
"beneficiario_cuenta": "684180142033702249",
"beneficiario_rfc": "TMF180212UKA",
"sello": "SQeXs/GkbMJ3Ae+He..."
}Descargar CEP
Valida y devuelve el comprobante oficial como archivo binario. Usa el parámetro
formato = PDF · XML · ZIP
(por defecto PDF). Mismos campos que validar,
enviados como query string.
curl -G $BASE/api/cep/download \
--data-urlencode "fecha=2026-06-10" \
--data-urlencode "clave_rastreo=085909274480316161" \
--data-urlencode "emisor=40002" \
--data-urlencode "receptor=90684" \
--data-urlencode "cuenta=684180142033702249" \
--data-urlencode "monto=9000.00" \
--data-urlencode "formato=PDF" \
--data-urlencode "api_key=TU_API_KEY" \
-o cep.pdf
const q = new URLSearchParams({
fecha: "2026-06-10", clave_rastreo: "085909274480316161",
emisor: "40002", receptor: "90684",
cuenta: "684180142033702249", monto: "9000.00", formato: "PDF",
api_key: "TU_API_KEY"
});
const blob = await (await fetch(`$BASE/api/cep/download?${q}`)).blob();
import requests
r = requests.get("$BASE/api/cep/download", params={
"fecha": "2026-06-10", "clave_rastreo": "085909274480316161",
"emisor": "40002", "receptor": "90684",
"cuenta": "684180142033702249", "monto": "9000.00", "formato": "PDF",
}, headers={"X-API-Key": "TU_API_KEY"})
open("cep.pdf", "wb").write(r.content)
Respuesta: el archivo binario con
Content-Type application/pdf · application/xml ·
application/zip y Content-Disposition: attachment.
Lote por archivos
Sube hasta 10 comprobantes (PDF o imagen). El servicio extrae
los campos de cada archivo (texto de PDF o OCR de imagen) y valida cada uno
contra Banxico. Se envía como multipart/form-data con el campo
repetido files.
not_found for that item.
curl -X POST $BASE/api/cep/batch \
-H "X-API-Key: TU_API_KEY" \
-F "files=@comprobante1.pdf" \
-F "files=@captura2.png"
const fd = new FormData();
fd.append("files", file1);
fd.append("files", file2);
const res = await fetch("$BASE/api/cep/batch", {
method: "POST", headers: { "X-API-Key": "TU_API_KEY" }, body: fd
});
const { items } = await res.json();
import requests
files = [
("files", open("comprobante1.pdf", "rb")),
("files", open("captura2.png", "rb")),
]
r = requests.post("$BASE/api/cep/batch",
headers={"X-API-Key": "TU_API_KEY"}, files=files).json()
Respuesta 200
{
"items": [
{
"filename": "comprobante1.pdf",
"status": "valid", // valid | pending | needs_bank | not_found | extract_failed | error
"request": { "fecha": "2026-06-10", "clave_rastreo": "...", "...": "..." },
"details": { "beneficiario_nombre": "...", "monto": "9000.00" }
},
{ "filename": "captura2.png", "status": "not_found", "message": "..." }
]
}Descarga los archivos de cada
valid con /api/cep/download usando los campos de
request.
Parámetros
Todos son obligatorios. Para validate van en el cuerpo JSON; para
download, como query string (más formato).
| Campo | Tipo | Descripción | |
|---|---|---|---|
fecha | string | REQ | Fecha de operación, formato YYYY-MM-DD. |
clave_rastreo | string | REQ | Clave de rastreo de la transferencia (≤ 30 caracteres). |
emisor | string | REQ | Código del banco emisor (ver /api/banks). |
receptor | string | REQ | Código del banco receptor. |
cuenta | string | REQ | Cuenta beneficiaria: CLABE, tarjeta o teléfono. |
monto | string | REQ | Monto en pesos, p. ej. 9000.00. |
formato | string | OPC | Solo download: PDF (default), XML o ZIP. |
Códigos de error
Los errores devuelven JSON con error y detail
(excepto 422, que usa el formato de validación estándar).
| HTTP | error | Significado |
|---|---|---|
401 | unauthorized | API key faltante o inválida (cuando el servidor tiene auth activada). |
404 | not_found | Banxico no encontró una transferencia con esos datos. |
409 | cep_pending | Banxico identificó el pago, pero el CEP aún no está disponible (reintenta más tarde). |
422 | — | Parámetros inválidos o faltantes (validación). |
502 | banxico_unavailable | Banxico no respondió o devolvió un error transitorio. |
503 | captcha_enforced | Banxico exige captcha (rate-limiting); reintenta más tarde. |
Ejemplo 404
{ "error": "not_found", "detail": "Banxico no encontró una transferencia que coincida con los datos proporcionados." }Límites de uso
Banxico aplica rate-limiting por IP a su servicio de CEP. La API lo mitiga con throttling, reintentos con backoff y caché de comprobantes (los CEP son inmutables, así que una consulta repetida es instantánea).
503 captcha_enforced. Reintenta con backoff exponencial.