Volver al blog
extraction · finO$ Team

Cómo extraer datos de BBVA México con Python en 10 líneas

Tutorial práctico: convierte un estado de cuenta de BBVA México (PDF) a JSON con Python usando el API de finO$. Pricing $5 MXN por hoja procesada.

TL;DR: Procesar un estado de cuenta de BBVA México con Python toma 10 líneas usando el API de finO$. Pagas $5 MXN por hoja procesada. Un estado típico de 8 hojas cuesta $40 MXN y se procesa en 15 segundos.

Por qué este tutorial

Si trabajas con datos bancarios mexicanos, eventualmente tienes que parsear PDFs de BBVA. Los estados de cuenta de BBVA México tienen un layout consistente desde 2024 (cuenta de cheques, débito, nómina, empresarial) y son una buena base para construir herramientas contables, dashboards de finanzas personales, o motores de underwriting.

Este tutorial muestra cómo llamar al API de finO$ desde Python para convertir un PDF de BBVA en JSON estructurado.

Lo que necesitas

  • Python 3.9+
  • Un API key de finO$ (solicita acceso en getfinos.com — aprobación en 24-48h)
  • Un PDF de tu estado de cuenta BBVA México

Setup

pip install requests

Exporta tu API key:

export FINOS_API_KEY="tu_api_key_aqui"

El código completo

import os
import time
import requests

API = "https://api.getfinos.com/v1"
KEY = os.environ["FINOS_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}

# 1. Sube el PDF
with open("bbva-statement.pdf", "rb") as f:
    upload = requests.post(
        f"{API}/upload",
        headers=HEADERS,
        files={"file": f},
        data={"bank_hint": "bbva_mx"},
    ).json()

job_id = upload["job_id"]

Eso es la mitad. Ahora consultas el resultado:

# 2. Espera a que termine (~15s típico)
while True:
    job = requests.get(f"{API}/jobs/{job_id}", headers=HEADERS).json()
    if job["status"] == "completed":
        break
    if job["status"] == "failed":
        raise Exception(job["error"])
    time.sleep(2)

# 3. Obtén las transacciones
result = requests.get(f"{API}/extractions/{job['extraction_id']}", headers=HEADERS).json()

for tx in result["transactions"]:
    print(f"{tx['date']} | {tx['description'][:40]:40} | {tx['amount']:>10}")

Qué obtienes

El resultado es un JSON con:

{
  "bank": "BBVA México",
  "account_clabe": "012180001234567890",
  "account_type": "cheques",
  "period": { "start": "2026-04-01", "end": "2026-04-30" },
  "opening_balance": 18450.32,
  "closing_balance": 22107.18,
  "transactions": [
    {
      "date": "2026-04-03",
      "posting_date": "2026-04-03",
      "description": "TRANSFERENCIA SPEI RECIBIDA - CLIENTE ACME",
      "reference": "ABCD12345",
      "amount": 15000.00,
      "type": "credit",
      "category": "income.client_payment",
      "balance_after": 33450.32,
      "spei": {
        "tracking_key": "1234567890",
        "source_clabe": "012180009876543210"
      }
    }
  ]
}

Pricing real

El API cuesta $5 MXN por hoja procesada. Un estado de cuenta de BBVA México típicamente tiene 8 hojas, así que cada extracción cuesta $40 MXN. No hay setup fee, no hay mínimo mensual, no hay compromiso anual.

Si procesas 30 estados al mes (caso típico de un contador con 30 clientes):

  • 30 estados × 8 hojas = 240 hojas
  • 240 × $5 MXN = $1,200 MXN/mes

Es menos del costo de una hora de un asistente contable junior.

Manejo de errores

ERROR_CODES = {
    401: "API key inválida o expirada",
    403: "Sin permiso para este recurso",
    413: "PDF excede límite de 50MB",
    422: "PDF no pudo ser parseado (¿está corrupto o con contraseña?)",
    429: "Rate limit excedido (100 req/min)",
    500: "Error del servidor — reintenta con backoff",
}

response = requests.post(f"{API}/upload", ...)
if not response.ok:
    raise Exception(f"{response.status_code}: {ERROR_CODES.get(response.status_code, 'unknown')}")

Siguiente paso

Si quieres procesar batch de cientos de estados, configura webhooks para no hacer polling:

upload = requests.post(
    f"{API}/upload",
    headers=HEADERS,
    files={"file": f},
    data={
        "bank_hint": "bbva_mx",
        "webhook_url": "https://tu-server.com/finos-callback",
    },
).json()

finO$ te avisa con un POST cuando el job termina. Idempotencia firmada con HMAC-SHA256.

Recursos