Documentación de la API

Fintable se conecta a tus bancos y sincroniza tus cuentas, saldos, transacciones y posiciones de inversión con hojas de cálculo como Google Sheets o Airtable. La API V2 de Fintable abre esos mismos datos (¡y más!) a tu propio código: todo lo almacenado en Fintable —conexiones bancarias, cuentas, transacciones, posiciones de inversión, el categorizador y tus integraciones de hojas de cálculo— está disponible a través de una interfaz REST limpia.

Pero la API de Fintable no es solo para tus datos financieros privados. Es también una API pública de información financiera pública, como los tipos de cambio de divisas y las cotizaciones de acciones. La API de Fintable está pensada para ser una ventanilla única con la que construir desde cero tu propia aplicación de finanzas (para ti, no para revenderla).

API de datos privados

Sirve para recuperar tus datos financieros privados, como los saldos y las transacciones de tus cuentas bancarias.

API de datos públicos

Incluye datos financieros públicos muy útiles para construir aplicaciones y paneles de finanzas completos, como tipos de cambio de divisas y cotizaciones de acciones en vivo.

API de panel / gestión

Sirve para gestionar el propio Fintable, crear nuevas conexiones bancarias y consultar su estado de sincronización, de modo que ni siquiera tengas que entrar en el panel de Fintable.

Sin acceso de terceros para plataformas o aplicaciones: solo tus datos

La API de Fintable es estrictamente de primera parte, para cuentas bancarias que poseas o que estés autorizado a controlar directamente (como las cuentas de tus clientes si eres contable). No es una plataforma de agregación de datos como Plaid: no puede ni debe usarse para crear aplicaciones de finanzas destinadas a la reventa, solo para ti.


Primeros pasos

¿Nunca has usado Fintable? Aquí tienes el recorrido completo, desde cero hasta tu primera llamada a la API sobre tus propios datos bancarios.

URL base https://fintable.io/api/v2
Descripción OpenAPI 3.1 https://fintable.io/api/v2/openapi.json
Servidor MCP para asistentes de IA https://fintable.io/mcp
Skill de IA o documentación para LLM (llms.txt) https://fintable.io/llms.txt
Gestionar tokens Panel → API

1. Crea una cuenta de Fintable

Regístrate aquí: empezar es gratis, y el plan gratuito incluye acceso a la API, así que puedes desarrollar contra ella antes de pagar nada.

2. Crea un token de acceso personal

Abre Panel → API y crea un token de acceso personal, eligiendo acceso de solo lectura o de lectura y escritura. El token se muestra una sola vez, así que cópialo en un lugar seguro y trátalo como una contraseña. Es lo que tus scripts enviarán para autenticarse en tu nombre.

3. Conecta una cuenta bancaria

Genera el enlace, visita la URL que te devuelve y sigue los pasos en un navegador para completar el flujo de conexión bancaria:

curl -X POST https://fintable.io/api/v2/connections/link \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
{
    "data": {
        "url": "https://fintable.io/api-link/eyJpdiI6...",
        "expires_at": "2026-07-26T15:42:00Z"
    }
}

El enlace es de un solo uso y caduca en 30 minutos; una vez completado, Fintable empieza a sincronizar las cuentas y transacciones del banco. Todos los detalles (preselección de institución, reconexiones, elegibilidad) están en POST /connections/link.

4. Recupera tus saldos y transacciones

Cuando llegue la primera sincronización —normalmente en un par de minutos— tus datos ya estarán ahí. Saldos:

curl https://fintable.io/api/v2/accounts \
  -H "Authorization: Bearer YOUR_TOKEN"
{
    "data": [
        {
            "id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
            "name": "Chase Total Checking",
            "balance": "5240.12",
            "balance_available": "5190.12",
            "currency": "USD",
            "...": "..."
        }
    ]
}

Y transacciones:

curl "https://fintable.io/api/v2/transactions?limit=5" \
  -H "Authorization: Bearer YOUR_TOKEN"
{
    "data": [
        {
            "id": "tx_01JB2M9QK4R7X3W8N5PDY6TF2H",
            "date": "2026-07-24",
            "amount": "-4.50",
            "currency": "USD",
            "description": "BLUE BOTTLE COFFEE",
            "...": "..."
        }
    ],
    "next_cursor": null
}

Las formas completas, los filtros y la paginación están en Cuenta y Transacción — y toda la Referencia de la API sigue el mismo patrón. ¿Prefieres clientes generados? Apunta Swagger UI, Postman o tu generador de código a la descripción OpenAPI 3.1: https://fintable.io/api/v2/openapi.json.


Autenticación

Hay dos formas de entrar, según lo que estés construyendo:

  • Tokens de acceso personal: para tus propios scripts y herramientas. Crea uno en el panel, ponlo en una cabecera y listo.
  • OAuth 2.0: para aplicaciones y asistentes de IA que se conectan a tu cuenta mediante un flujo de autorización en condiciones (es lo que usa el servidor MCP por debajo).

Tokens de acceso personal

Crea y revoca tokens en la página Panel → API. Los tokens son válidos durante 1 año y llevan los ámbitos que elijas al crearlos: solo lectura (read) o lectura y escritura (read + write). Envíalos como cabecera bearer:

Authorization: Bearer YOUR_TOKEN

La revocación surte efecto de inmediato.

OAuth 2.0

Fintable ejecuta un servidor de autorización OAuth 2.0 estándar, así que funcionará cualquier biblioteca cliente de OAuth convencional:

Endpoint URL
Autorización https://fintable.io/oauth/authorize
Token https://fintable.io/oauth/token
Registro dinámico de clientes https://fintable.io/oauth/register
Descubrimiento https://fintable.io/.well-known/oauth-authorization-server

Algunos detalles que conviene conocer:

  • El grant admitido es Authorization Code + PKCE.
  • Los tokens de acceso duran 1 hora; los de actualización, 30 días.
  • Autorizar siempre requiere iniciar sesión y volver a confirmar la contraseña de la cuenta. La pantalla de consentimiento indica exactamente qué podrá hacer la aplicación. Esta fricción es deliberada: son tus datos bancarios.

Ámbitos

Ámbito Qué permite
read Leer todos los datos de la cuenta
write Modificar datos: renombrar, categorizar, activar/desactivar, eliminar, sincronizar
mcp:use Acceso completo de lectura y escritura, para clientes MCP (Claude, ChatGPT)

mcp:use es un superconjunto: se acepta en todos los sitios donde valen read o write. Los tokens con solo read/write son rechazados por el endpoint MCP.


Referencia de la API

Todo lo que sigue usa la misma autenticación bearer, y los comportamientos comunes —envoltorios, importes como cadenas, errores, límites de tasa, paginación— se describen en Convenciones de la API y Paginación más abajo. Cada sección cubre un tipo de recurso: qué es, su forma exacta (un ejemplo realista y cada campo explicado) y después los endpoints que operan sobre él.

Perfil

Endpoint Qué hace
GET /me Tu perfil y metadatos de facturación

El Perfil es tu cuenta tal como la ve la API: quién eres, en qué plan estás y cuánto margen te queda. Consúltalo antes de añadir una conexión o lanzar una sincronización: los límites que informa son los que aplican los endpoints de escritura.

{
    "data": {
        "name": "Jamie",
        "tier": "personal",
        "plan_period": "monthly",
        "connection_limit": 10,
        "connections_used": 3,
        "tx_365_limit_usd": null,
        "can_sync": true,
        "renews_at": "2026-08-14T00:00:00Z",
        "renewal_amount": "9.00",
        "renewal_currency": "USD",
        "will_renew": true,
        "expires_at": "2026-08-14T00:00:00Z"
    }
}
Campo Tipo Significado
name string Tu nombre visible
tier string Nivel del plan: free, trial, personal, office o enterprise
plan_period string | null Ciclo de facturación: monthly, annual, lifetime, trial o manual; null en cuentas gratuitas
connection_limit integer Tope de conexiones bancarias que permite tu plan en total. Añadir una conexión falla cuando connections_used ya ha alcanzado este número. Las cuentas gratuitas informan su recuento actual como límite (sin huecos libres).
connections_used integer Cuántas conexiones bancarias tienes ahora mismo. Compáralo con connection_limit para saber el margen restante: connection_limit - connections_used. Desconectar un banco lo reduce; el límite en sí no cambia salvo que cambie tu plan.
tx_365_limit_usd integer | null Límite móvil de volumen de transacciones a 365 días en USD; null significa ilimitado
can_sync boolean Si las sincronizaciones están disponibles (false en cuentas gratuitas)
renews_at string | null Momento ISO-8601 en que se renueva la suscripción activa
renewal_amount string | null Precio de renovación, como cadena decimal
renewal_currency string | null Código de moneda de la renovación
will_renew boolean Si la suscripción se renovará automáticamente
expires_at string | null Cuándo termina el derecho de uso actual

Las cuentas gratuitas obtienen "tier": "free", "can_sync": false y su recuento actual de conexiones como límite.

GET /me

Devuelve tu Perfil: el objeto de arriba. Sin parámetros:

curl https://fintable.io/api/v2/me \
  -H "Authorization: Bearer YOUR_TOKEN"

Conexión

Endpoint Qué hace
GET /connections Lista todas las conexiones
GET /connections/{id} Una conexión
PATCH /connections/{id} Renombrar o fijar la fecha de inicio de sincronización
DELETE /connections/{id} Desconectar el banco y purgar sus datos
POST /connections/link Generar un enlace de navegador para conectar un banco nuevo
POST /connections/{id}/link Generar un enlace de navegador para reconectar este banco

Una Conexión es un banco vinculado: un inicio de sesión en una institución. Una conexión posee una o más cuentas y lleva el estado de salud y de sincronización de esa relación bancaria.

{
    "data": {
        "id": "conn_plaid_1771845993762884095",
        "provider": "PLAID",
        "institution_name": "Chase",
        "name": null,
        "healthy": true,
        "status_text": "OK",
        "needs_reconnect": false,
        "last_successful_update": "2026-07-26T09:12:44Z",
        "created_at": "2025-11-02T18:20:11Z",
        "accounts_count": 3,
        "sync_status": {
            "state": "finished",
            "progress_now": 4,
            "progress_max": 4,
            "stage": "Sync complete",
            "started_at": "2026-07-26T09:11:58Z",
            "finished_at": "2026-07-26T09:12:44Z"
        }
    }
}
Campo Tipo Significado
id string Id de la conexión, conn_{provider}_{number}
provider string El agregador detrás de esta conexión, p. ej. PLAID, NORDIGEN, AKOYA, FINICITY, MERCURY, SNAPTRADE
institution_name string El nombre del banco (tu nombre personalizado, si lo has puesto)
name string | null Tu nombre personalizado para la conexión
healthy boolean Señal de salud almacenada: false significa que la conexión necesita atención
status_text string Estado legible: OK, o el mensaje de error del proveedor
needs_reconnect boolean true cuando el banco exige que vuelvas a autenticarte
last_successful_update string | null Momento ISO-8601 de la última sincronización correcta
created_at string Cuándo se conectó el banco
accounts_count integer Número de cuentas bajo esta conexión
sync_status object | null El trabajo de sincronización más reciente: un objeto Estado de sincronización

GET /connections

Lista todas tus conexiones. Sin parámetros.

GET /connections/{id}

Una conexión por id.

PATCH /connections/{id}

Renombra la conexión o fija su fecha de inicio de sincronización. Acepta uno o ambos de:

  • name: tu nombre personalizado, máximo 64 caracteres; null lo borra.
  • sync_start_date: YYYY-MM-DD; null lo borra. Fintable solo sincronizará transacciones a partir de esta fecha.
curl -X PATCH https://fintable.io/api/v2/connections/conn_plaid_1771845993762884095 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Chase (Jamie)", "sync_start_date": "2026-01-01"}'

La respuesta es el objeto de conexión actualizado. Dos detalles: la fecha de inicio se aplica solo a las cuentas activadas de la conexión (las desactivadas conservan su fecha hasta que se reactiven), y la fecha se valida contra el histórico mínimo del proveedor y el límite de 30 días de las cuentas de prueba (422 si está fuera de rango).

DELETE /connections/{id}

Desconecta el banco y purga sus cuentas y transacciones de Fintable. Como la purga implica al proveedor, se completa de forma asíncrona: la respuesta es un 202:

{
    "data": {
        "id": "conn_plaid_1771845993762884095",
        "status": "deleting"
    }
}

La conexión y sus datos desaparecen en cuestión de minutos.

POST /connections/link

Conectar un banco significa iniciar sesión en él, y las páginas de login bancario necesitan un navegador real, así que este es el único flujo que la API no puede completar por sí sola. En su lugar, este endpoint genera una URL de un solo uso, válida 30 minutos, que abres tú (o le pasas al titular de la cuenta: es su cuenta):

curl -X POST https://fintable.io/api/v2/connections/link \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"institution": "12913262_chase"}'
{
    "data": {
        "url": "https://fintable.io/api-link/eyJpdiI6...",
        "expires_at": "2026-07-26T15:42:00Z"
    }
}

El campo institution es opcional: es un slug del directorio de Instituciones y preselecciona el banco en el flujo. Quien abra la URL verá a qué cuenta de Fintable se está conectando, confirmará la contraseña de la cuenta y aterrizará en el flujo de selección de banco del proveedor. La URL se consume en la primera confirmación correcta.

Generarla requiere un plan activo con margen: una suscripción o prueba activa, por debajo del límite de conexiones, por debajo del límite mensual de intentos y por debajo del límite de volumen de transacciones; en caso contrario, 422 con una explicación (y las mismas comprobaciones se repiten cuando el banco se crea realmente).

POST /connections/{id}/link

Funciona exactamente como POST /connections/link, pero genera un enlace de reconexión para una conexión existente, y está exento de las comprobaciones de conexión nueva.

Cuenta

Endpoint Qué hace
GET /accounts Lista todas las cuentas, incluidas las desactivadas
GET /accounts/{id} Una cuenta
PATCH /accounts/{id} Actualiza display_name, sync_start_date y/o enabled

Una Cuenta es una cuenta bancaria concreta dentro de una conexión: una cuenta corriente, una de ahorro, una de bróker. Las cuentas son donde viven los saldos y a las que pertenecen las transacciones.

{
    "data": {
        "id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
        "connection_id": "conn_plaid_1771845993762884095",
        "name": "Chase Total Checking",
        "display_name": "Household checking",
        "type": "depository / checking",
        "currency": "USD",
        "balance": "5240.12",
        "balance_available": "5190.12",
        "sync_start_date": "2026-01-01",
        "last_tx_date": "2026-07-25",
        "enabled": true,
        "created_at": "2025-11-02T18:20:14Z",
        "updated_at": "2026-07-26T09:12:40Z"
    }
}
Campo Tipo Significado
id string Id de la cuenta: opaco, normalmente acc_...
connection_id string La Conexión a la que pertenece esta cuenta
name string El nombre que el banco da a la cuenta
display_name string | null Tu nombre personalizado: es lo que muestran tus hojas de cálculo
type string Texto libre con sabor del proveedor, como depository / checking o investment / brokerage: muéstralo, no ramifiques según él
currency string Código de moneda efectivo (respeta cualquier anulación que hayas puesto)
balance string | null Saldo actual como cadena decimal
balance_available string | null Saldo disponible, cuando el banco lo informa
sync_start_date string | null YYYY-MM-DD: las transacciones solo se sincronizan a partir de esta fecha
last_tx_date string | null Fecha de la transacción sincronizada más reciente
enabled boolean Si la cuenta se sincroniza; las cuentas desactivadas siguen apareciendo aquí con enabled: false
created_at / updated_at string Marcas de tiempo ISO-8601

GET /accounts

Lista todas las cuentas, incluidas las desactivadas (enabled: false). Filtros: connection_id, ids[] y enabled.

GET /accounts/{id}

Una cuenta por id.

PATCH /accounts/{id}

Actualiza display_name, sync_start_date y/o enabled.

Aviso: desactivar una cuenta elimina sus transacciones. Poner "enabled": false elimina permanentemente todas las transacciones de esa cuenta en Fintable, igual que el interruptor del panel. Reactivarla no las restaura; una sincronización posterior tendrá que recuperarlas del proveedor. No desactives una cuenta salvo que sea exactamente lo que quieres.

Posición

Endpoint Qué hace
GET /accounts/{id}/holdings Una instantánea de las posiciones de una cuenta

Una Posición es una participación en una cuenta de inversión: una acción, un fondo u otro valor. Fintable registra las posiciones como instantáneas diarias: qué tenías, a qué precio, una vez al día. Una respuesta de posiciones es el conjunto de filas de una fecha de instantánea, con la fecha en el envoltorio como snapshot_date.

{
    "data": [
        {
            "id": "hol_01JB7Q2M5X8R4T6W9NKZP3VD1F",
            "name": "Vanguard Total Stock Market ETF",
            "symbol": "VTI",
            "quantity": "42.0000",
            "price": "279.35",
            "value": "11732.70",
            "cost_basis": "9450.00",
            "currency": "USD",
            "updated_at": "2026-07-26T09:12:41Z"
        }
    ],
    "snapshot_date": "2026-07-26"
}
Campo Tipo Significado
id string Id de la posición: opaco, normalmente hol_...
name string El nombre del valor
symbol string | null Símbolo bursátil, cuando el proveedor lo informa
quantity string | null Unidades en cartera, como cadena decimal
price string | null Precio por unidad
value string | null Valor de mercado actual de la posición
cost_basis string | null Coste total de la posición, no por acción: una peculiaridad del proveedor que trasladamos tal cual en vez de adivinar
currency string La moneda efectiva de la cuenta
updated_at string | null Cuándo se escribió esta fila por última vez
snapshot_date (envoltorio) string | null El día de la instantánea que describe esta respuesta; null cuando la cuenta no tiene posiciones

GET /accounts/{id}/holdings

Devuelve la instantánea más reciente por defecto; ?date=YYYY-MM-DD selecciona una concreta. No hay paginación de histórico: recupera fecha a fecha.

Transacción

Endpoint Qué hace
GET /transactions Todas las transacciones, paginadas por cursor
GET /accounts/{id}/transactions Las transacciones de una cuenta
GET /transactions/{id} Una transacción
PATCH /transactions/{id} Fijar o borrar la categoría
PATCH /transactions/bulk Categorizar muchas a la vez

El corazón de la API. Una Transacción es un movimiento de dinero en una cuenta: una compra, un ingreso, una transferencia, una comisión. Las transacciones llevan el estado de categorización: tanto la categoría asignada como si se fijó a mano o por una regla.

{
    "data": {
        "id": "tx_01JB2M9QK4R7X3W8N5PDY6TF2H",
        "account_id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
        "date": "2026-07-24",
        "datetime": "2026-07-24T16:41:02Z",
        "auth_date": "2026-07-23",
        "amount": "-4.50",
        "currency": "USD",
        "description": "BLUE BOTTLE COFFEE",
        "merchant": "Blue Bottle Coffee",
        "pending": false,
        "check_num": null,
        "external_memo": null,
        "account_owner": null,
        "category": {
            "id": "dining-out_aB3xY9k2Lm",
            "name": "Dining Out",
            "header": "Expenses"
        },
        "category_manual_override": false,
        "created_at": "2026-07-24T18:03:12Z",
        "updated_at": "2026-07-25T06:14:09Z"
    }
}
Campo Tipo Significado
id string Id de la transacción: opaco, normalmente tx_...
account_id string La Cuenta a la que pertenece esta transacción
date string Fecha de la transacción, YYYY-MM-DD
datetime string | null Hora ISO-8601 exacta, cuando el proveedor la facilita
auth_date string | null Fecha de autorización, cuando difiere de la de contabilización
amount string Cadena decimal exacta; negativo es dinero que sale
currency string Código de moneda efectivo
description string La descripción del extracto
merchant string | null Nombre del comercio ya limpio, cuando se conoce
pending boolean true mientras la transacción no se ha contabilizado; las filas pendientes pueden sustituirse al contabilizarse
check_num string | null Número de cheque, para pagos con cheque
external_memo string | null Texto adicional de nota del banco
account_owner string | null Nombre del titular en cuentas compartidas o con varios titulares
category object | null La Categoria asignada —{id, name, header}— o null si no está categorizada
category_manual_override boolean true cuando la categoría se fijó a mano; las reglas nunca tocan filas anuladas
created_at / updated_at string Marcas de tiempo ISO-8601; updated_at es lo que impulsa la sincronizacion incremental
raw object El JSON en bruto del proveedor: solo presente con ?include=raw; los mismos datos que los campos **Raw de tus hojas de cálculo

GET /transactions

Todas tus transacciones, paginadas por cursor, de más reciente a más antigua por defecto. Filtros:

Filtro Significado
date_from, date_to Rango de fechas (YYYY-MM-DD, inclusive)
account_ids[] Limitar a cuentas concretas
category_ids[] Limitar a categorías: incluye el literal uncategorized para las filas sin categorizar
pending true o false
amount_min, amount_max Rango de importes
q Búsqueda de subcadena sin distinguir mayúsculas sobre descripción + comercio
description Coincidencia exacta de descripción
updated_since, order Para la sincronizacion incremental; order es date o updated

GET /accounts/{id}/transactions

Las transacciones de una cuenta: mismos filtros, paginación y forma que GET /transactions.

GET /transactions/{id}

Una transacción por id. ?include=raw también funciona aquí.

PATCH /transactions/{id}

Hace exactamente una cosa: fijar la categoría.

curl -X PATCH https://fintable.io/api/v2/transactions/tx_01JB2M9QK4R7X3W8N5PDY6TF2H \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"category_id": "dining-out_aB3xY9k2Lm"}'

Fijar una categoría marca la transacción como anulada manualmente (category_manual_override: true): las reglas no volverán a tocarla. Poner "category_id": null la descategoriza y borra la anulación, así que las reglas pueden volver a aplicarse en la siguiente pasada. La respuesta es la transacción actualizada.

PATCH /transactions/bulk

Aplica un category_id (o null) a muchas transacciones a la vez. Elige los objetivos con exactamente uno de estos dos selectores:

  • ids[]: hasta 10.000 ids (los ids que no sean tuyos se omiten en silencio), o
  • filters: las mismas claves que el endpoint de listado. Para que una errata no recategorice todo tu histórico, el filtro debe incluir al menos una clave restrictiva: date_from, date_to, account_ids, category_ids, q o description (pending y amount_* pueden afinar, pero no cuentan por sí solos). Si coinciden más de 10.000 transacciones, la petición falla con 422: acota y reintenta.

¿No sabes a qué va a afectar un filtro? Haz primero una prueba en seco:

curl -X PATCH https://fintable.io/api/v2/transactions/bulk \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {"q": "whole foods", "date_from": "2026-01-01"},
    "category_id": "groceries_x7Pq2Rv9Zn",
    "dry_run": true
  }'
{
    "data": {
        "dry_run": true,
        "matched_count": 37,
        "sample": [
            "... up to 10 matching transactions ..."
        ]
    }
}

¿Contento con la coincidencia? Envía la misma petición sin dry_run:

{
    "data": {
        "dry_run": false,
        "updated_count": 37
    }
}

La ejecución actualiza todas las filas coincidentes y sincroniza las categorías con tus hojas de cálculo una sola vez, como una única exportación.

Sincronización

Endpoint Qué hace
GET /sync Programación, sincronizaciones en curso y estado por conexión
POST /sync Sincronizar todas las conexiones ahora
POST /sync/{connection_id} Sincronizar una conexión ahora

Una Sincronización es una ejecución que trae datos frescos de una conexión bancaria a Fintable. Fintable las programa automáticamente: cada cuenta entra en un barrido aleatorizado que se ejecuta cada 6–23 horas, de modo que deliberadamente no existe una "hora exacta de la próxima sincronización". La API te permite inspeccionar la programación, observar las sincronizaciones en curso y (en planes de pago) lanzar una bajo demanda.

La forma recurrente aquí es el objeto Estado de sincronización: aparece en cada Conexión y a lo largo de GET /sync:

{
    "state": "finished",
    "progress_now": 4,
    "progress_max": 4,
    "stage": "Sync complete",
    "started_at": "2026-07-26T09:11:58Z",
    "finished_at": "2026-07-26T09:12:44Z"
}
Campo Tipo Significado
state string queued, executing, finished, failed o retrying
progress_now integer | null Pasos completados hasta ahora
progress_max integer | null Pasos totales de esta ejecución
stage string | null Descripción legible de la etapa actual
started_at string | null Cuándo empezó la ejecución
finished_at string | null Cuándo terminó; null mientras sigue en curso

GET /sync

Envuelve los objetos de Estado de sincronización en el cuadro completo: tu programación más el estado por conexión.

Campo Tipo Significado
schedule.type string default (el barrido aleatorizado) o custom (existen programaciones específicas de proveedor)
schedule.last_sync_at string | null Cuándo despachó el barrido tus sincronizaciones por última vez
schedule.next_sync_window object | null Ventana aproximada {earliest, latest} del próximo barrido: no existe una hora exacta
schedule.custom_schedules array Programaciones específicas de proveedor: {provider, cron, timezone, next_run_at}
schedule.default_sweep_applies boolean El barrido por defecto se aplica a todas las cuentas, haya programaciones personalizadas o no
active_syncs array Trabajos en curso (o atascados, o fallidos): {connection_id, sync_status}
connections array El último {connection_id, sync_status} de cada conexión
curl https://fintable.io/api/v2/sync \
  -H "Authorization: Bearer YOUR_TOKEN"
{
    "data": {
        "schedule": {
            "type": "default",
            "last_sync_at": "2026-07-26T09:11:55Z",
            "next_sync_window": {
                "earliest": "2026-07-26T15:23:00Z",
                "latest": "2026-07-27T09:11:55Z"
            },
            "custom_schedules": [],
            "default_sweep_applies": true
        },
        "active_syncs": [],
        "connections": [
            {
                "connection_id": "conn_plaid_1771845993762884095",
                "sync_status": {
                    "state": "finished",
                    "progress_now": 4,
                    "progress_max": 4,
                    "stage": "Sync complete",
                    "started_at": "2026-07-26T09:11:58Z",
                    "finished_at": "2026-07-26T09:12:44Z"
                }
            }
        ]
    }
}

POST /sync

La versión API del botón "Sincronizar todas las conexiones" del panel. Trae los datos cacheados del proveedor: no es una actualización en tiempo real desde el banco:

{
    "data": [
        {
            "connection_id": "conn_plaid_1771845993762884095",
            "status": "started"
        },
        {
            "connection_id": "conn_nordigen_1802214467911184310",
            "status": "already_syncing"
        }
    ]
}

Una sincronización ya en curso se informa como already_syncing, nunca como error. Requiere una suscripción o prueba activa: las cuentas gratuitas reciben un 403 antes de que empiece nada. Sigue el progreso con GET /sync o con el sync_status de cada conexión.

POST /sync/{connection_id}

Sincroniza solo una conexión: misma forma de respuesta que POST /sync (un elemento) y mismo requisito de plan.

Categoría

Endpoint Qué hace
GET /categorizer/categories Listar categorías
GET /categorizer/categories/{id} Una categoría
POST /categorizer/categories Crear una categoría (201)
PATCH /categorizer/categories/{id} Renombrar, cambiar de grupo, recolorear
DELETE /categorizer/categories/{id} Eliminar una categoría

Una Categoría es una etiqueta para transacciones: el bloque básico del categorizador, que es como se etiquetan las transacciones. Las categorías son las etiquetas, y las Reglas las aplican automáticamente conforme entran las transacciones. Todo lo que puedes hacer en el panel del categorizador puedes hacerlo aquí. Límite: 1.000 categorías por cuenta.

{
    "data": {
        "id": "groceries_x7Pq2Rv9Zn",
        "name": "Groceries",
        "header": "Expenses",
        "color": "green",
        "created_at": "2026-07-26T14:02:33Z",
        "updated_at": "2026-07-26T14:02:33Z"
    }
}
Campo Tipo Significado
id string Id de la categoría, {name-slug}_{10 alfanuméricos}: estable ante renombrados
name string La etiqueta que se muestra en las transacciones y en tus hojas de cálculo
header string El grupo bajo el que aparece la categoría, como Expenses o Income
color string Un nombre de la paleta del panel: red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose
created_at / updated_at string Marcas de tiempo ISO-8601

GET /categorizer/categories

Lista todas tus categorías.

GET /categorizer/categories/{id}

Una categoría por id.

POST /categorizer/categories

Crea una categoría (201): name, header y un color opcional.

curl -X POST https://fintable.io/api/v2/categorizer/categories \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Groceries", "header": "Expenses", "color": "green"}'

La respuesta es la categoría creada (como arriba).

PATCH /categorizer/categories/{id}

Actualiza name, header y/o color. Los renombrados se propagan automáticamente a tu Airtable y a tus Google Sheets.

DELETE /categorizer/categories/{id}

El borrado está protegido: si alguna regla sigue referenciando la categoría, la petición falla con 409 listando los ids de las reglas implicadas; actualiza o elimina esas reglas primero. En caso contrario, todas las transacciones de la categoría quedan sin categorizar y la categoría se elimina:

{
    "data": {
        "deleted": true,
        "uncategorized_count": 118
    }
}

Regla

Endpoint Qué hace
GET /categorizer/rules Listar reglas: solo metadatos, sin logic
GET /categorizer/rules/{id} Una regla, incluida su logic completa
POST /categorizer/rules Crear una regla (202)
PATCH /categorizer/rules/{id} Actualizar name, priority y/o logic
DELETE /categorizer/rules/{id} Eliminar una regla
POST /categorizer/sync Encolar una pasada completa de reglas + exportación a hojas (202)
GET /categorizer/status En qué punto está la tubería

Una Regla categoriza transacciones automáticamente conforme se sincronizan: la otra mitad del categorizador. Límite: 1.000 reglas por cuenta.

{
    "data": {
        "id": "a25a374d-e4d7-4652-aca7-5dd3c3d02d15",
        "name": "Big grocery runs",
        "type": "advanced",
        "priority": 7,
        "category_ids": [
            "groceries_x7Pq2Rv9Zn"
        ],
        "logic": {
            "if": [
                "..."
            ]
        },
        "created_at": "2026-07-26T14:10:05Z",
        "updated_at": "2026-07-26T14:10:05Z"
    }
}
Campo Tipo Significado
id string Id de la regla: un UUID
name string Nombre visible (autogenerado para las reglas simples)
type string simple (la descripción contiene un texto) o advanced (JSONLogic en bruto)
priority integer Las reglas se ejecutan en orden (priority, id); cuando coinciden varias, gana la de mayor prioridad
category_ids array of strings Las Categorias que pueden asignar las ramas de esta regla
logic object El JSONLogic completo: presente en GET /categorizer/rules/{id} y en las respuestas de creación/actualización, omitido en el listado
created_at / updated_at string Marcas de tiempo ISO-8601

Cómo se comportan las reglas, conviene leerlo una vez:

  • Las reglas se ejecutan en orden (priority, id). Cuando varias reglas coinciden con la misma transacción, gana la de mayor prioridad (se aplica la última). priority es editable vía PATCH.
  • Las transacciones categorizadas a mano (category_manual_override: true) nunca son tocadas por las reglas.
  • Una pasada de reglas preserva las categorizaciones antiguas. Solo sobrescribe las transacciones que coinciden con el conjunto de reglas actual: eliminar o cambiar una regla no descategoriza las transacciones que antes coincidían. Esto refleja el comportamiento del panel y es intencionado. Para reiniciar de verdad, descategoriza en bloque y vuelve a ejecutar.

GET /categorizer/rules

Lista todas tus reglas: solo metadatos (id, name, type, priority, category_ids[]), sin logic.

GET /categorizer/rules/{id}

Una regla por id, incluida su logic completa.

POST /categorizer/rules

Hay dos tipos. Las reglas simples cubren el caso habitual: "si la descripción contiene X, archívalo en Y" (sin distinguir mayúsculas, 3–128 caracteres):

curl -X POST https://fintable.io/api/v2/categorizer/rules \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type": "simple", "text": "STARBUCKS", "category_id": "dining-out_aB3xY9k2Lm"}'

Las reglas avanzadas son JSONLogic en bruto: condiciones arbitrarias sobre el importe, las fechas, la cuenta, la descripción e incluso los campos en bruto del proveedor (consulta la referencia de JSONLogic más abajo). Ten en cuenta que logic es una cadena codificada en JSON, no un objeto anidado:

curl -X POST https://fintable.io/api/v2/categorizer/rules \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "advanced",
    "name": "Big grocery runs",
    "logic": "{\"if\": [{\"and\": [{\"in\": [\"WHOLE FOODS\", {\"var\": \"transaction.description\"}]}, {\"<\": [{\"var\": \"transaction.amount\"}, -100]}]}, \"groceries_x7Pq2Rv9Zn\", null]}"
  }'

Crear o actualizar una regla devuelve 202 con el objeto de la regla (como arriba) más un "application": "queued" de primer nivel. Ese 202 te está diciendo algo real: la regla está guardada y se ha encolado una pasada ordenada completa de todas tus reglas sobre todas tus transacciones, junto con una exportación agrupada a tus hojas de cálculo. Consulta GET /categorizer/status para ver cuándo aterriza. Muchas ediciones rápidas producen una sola pasada y una sola exportación, no una por edición.

PATCH /categorizer/rules/{id}

Actualiza name, priority y/o logic. Los cambios de comportamiento (lógica o prioridad) devuelven 202 y encolan una pasada de reglas, igual que al crear; un simple renombrado devuelve 200 con "application": "none".

DELETE /categorizer/rules/{id}

Elimina la regla. Las transacciones que categorizó previamente conservan sus categorías (consulta las notas de comportamiento de arriba).

Escribir reglas avanzadas en JSONLogic

logic debe ser un objeto JSON cuyo único operador de primer nivel sea if. Cada rama de resultado debe ser una cadena literal con un id de categoría o el literal null, nunca una expresión calculada. Tu lógica se evalúa contra esta entrada para cada transacción:

{
    "transaction": {
        "fin_id": "tx_01JB2M9QK4R7X3W8N5PDY6TF2H",
        "ext_id": "plaid-tx-4821bd0e",
        "account_id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
        "date": "2026-07-24",
        "auth_date": "2026-07-23",
        "amount": "-4.50",
        "currency": "USD",
        "description": "BLUE BOTTLE COFFEE",
        "payee": "Blue Bottle Coffee",
        "sub_account": null,
        "acc_name": "Chase Total Checking",
        "raw": {
            "provider fields": "..."
        }
    }
}

Dos comodidades a tener en cuenta: description se pasa a mayúsculas por ti (así que la coincidencia de subcadenas es en la práctica insensible a mayúsculas) y amount es la habitual cadena decimal.

Un ejemplo resuelto: "las transacciones de tarjeta de más de 100 $ en Whole Foods son Groceries" (recuerda que negativo = dinero que sale, así que más de 100 $ gastados significa < -100):

{
    "if": [
        {
            "and": [
                {
                    "in": [
                        "WHOLE FOODS",
                        {
                            "var": "transaction.description"
                        }
                    ]
                },
                {
                    "<": [
                        {
                            "var": "transaction.amount"
                        },
                        -100
                    ]
                }
            ]
        },
        "groceries_x7Pq2Rv9Zn",
        null
    ]
}

Operadores permitidos: var, missing, missing_some, if, ==, ===, !=, !==, !, !!, or, and, >, >=, <, <=, max, min, +, -, *, /, %, map, reduce, filter, all, none, some, merge, in, cat, substr. (log no está permitido.)

Límites por regla: 16 KB, profundidad de anidamiento 20 y un presupuesto de complejidad de 100 nodos de operador; los operadores de array (map, filter, reduce, all, none, some) cuentan 10× y no pueden anidarse entre sí. También hay un presupuesto agregado para todas tus reglas; si lo alcanzas, simplifica o elimina reglas.

POST /categorizer/sync

Encola una pasada completa de reglas más una exportación a hojas de cálculo (202, {"data": {"application": "queued"}}). Las ediciones de reglas encolan pasadas automáticamente, así que rara vez lo necesitarás: existe para "vuelve a ejecutarlo todo ahora".

GET /categorizer/status

La visión honesta de la tubería:

curl https://fintable.io/api/v2/categorizer/status \
  -H "Authorization: Bearer YOUR_TOKEN"
{
    "data": {
        "requested_version": 12,
        "completed_version": 12,
        "active_version": null,
        "settled": true,
        "failed_at": null,
        "destinations": [
            {
                "destination": "airtable",
                "requested_version": 12,
                "completed_version": 12,
                "failed_at": null
            },
            {
                "destination": "gsheet:184",
                "requested_version": 12,
                "completed_version": 12,
                "failed_at": null
            }
        ]
    }
}

Cada cambio solicitado incrementa requested_version; las pasadas y exportaciones van detrás. active_version es la pasada que se está ejecutando ahora mismo: null siempre que no haya ninguna en marcha. settled: true significa que todo lo que has pedido ha aterrizado por completo: en la base de datos y en cada destino de hoja de cálculo. Para esperar a que un cambio de regla surta efecto, consulta hasta que settled sea true.

Integración

Endpoint Qué hace
GET /integrations Estado y salud de tus integraciones de hojas de cálculo

Una Integración es un destino al que Fintable sincroniza: tu base de Airtable o tus hojas de Google Sheets. Es el puente entre esta API y el mundo de las hojas de cálculo: coge aquí el base_id o el spreadsheet_id y luego trabaja con las APIs propias de Airtable o de Google directamente sobre los datos sincronizados.

GET /integrations

curl https://fintable.io/api/v2/integrations \
  -H "Authorization: Bearer YOUR_TOKEN"
{
    "data": {
        "airtable": {
            "base_id": "appXk2fW9qLmN3vT8",
            "url": "https://airtable.com/appXk2fW9qLmN3vT8",
            "accounts_table_name": "Accounts",
            "transactions_table_name": "Transactions",
            "holdings_table_name": "Holdings",
            "transactions_enabled": true,
            "token_type": "OAUTH",
            "healthy": true,
            "error": null
        },
        "google_sheets": [
            {
                "spreadsheet_id": "1vQx8mP2kL9nR4tY7wZ3jB6cD5eF8gH0iJ2kL4mN6oP8",
                "url": "https://docs.google.com/spreadsheets/d/1vQx8mP2kL9nR4tY7wZ3jB6cD5eF8gH0iJ2kL4mN6oP8",
                "title": "Family finances",
                "tabs": {
                    "accounts": {
                        "sheet": "Accounts",
                        "range": "A1:Z"
                    },
                    "transactions": {
                        "sheet": "Transactions",
                        "range": "A1:Z"
                    },
                    "holdings": {
                        "sheet": null,
                        "range": null
                    }
                },
                "healthy": true,
                "error": null
            }
        ]
    }
}

El objeto airtable (null si no has conectado Airtable):

Campo Tipo Significado
base_id string La base de Airtable a la que sincroniza Fintable: úsala con la propia API de Airtable
url string Enlace directo a la base
accounts_table_name string Tabla configurada para cuentas
transactions_table_name string Tabla configurada para transacciones
holdings_table_name string | null Tabla configurada para posiciones, cuando está activada
transactions_enabled boolean Si la sincronización de transacciones a esta base está activa
token_type string OAUTH, PERSONAL o DEPRECATED
healthy boolean Si la última validación fue correcta
error string | null Qué falla, cuando healthy es false

Cada entrada de google_sheets[]:

Campo Tipo Significado
spreadsheet_id string La hoja de cálculo a la que sincroniza Fintable: úsala con la propia API de Google
url string Enlace directo a la hoja de cálculo
title string El título de la hoja de cálculo
tabs object Pestañas accounts / transactions / holdings configuradas, cada una {sheet, range} (null cuando no está configurada)
healthy boolean Si la última validación fue correcta
error string | null Qué falla, cuando healthy es false

La salud se sirve desde una caché de validación: la primera llamada tras un periodo de inactividad puede tardar unos segundos mientras valida en vivo. Configura las integraciones en Panel → Integraciones.

Institución

Endpoint Qué hace
GET /institutions Buscar en el directorio (público, paginado por desplazamiento)

Una Institución es un banco o bróker al que Fintable puede conectarse: una entrada en el directorio buscable de unas 50.000. El directorio es público —sin autenticación—, así que puedes usarlo en flujos de registro o en comprobaciones de disponibilidad. Sus valores slug alimentan POST /connections/link.

{
    "data": [
        {
            "slug": "12913262_chase",
            "name": "Chase",
            "domain": "chase.com",
            "supported": true,
            "countries": [
                "US"
            ],
            "coverage_url": "https://fintable.io/coverage/us/12913262_chase",
            "updated_at": "2026-07-19T02:11:36Z"
        }
    ],
    "meta": {
        "page": 1,
        "has_more": true
    }
}
Campo Tipo Significado
slug string El id de la institución: pásalo a POST /connections/link
name string Nombre visible
domain string | null El dominio web de la institución
supported boolean Si Fintable puede conectarse a ella ahora mismo
countries array of strings Códigos ISO de país en los que opera
coverage_url string | null Página pública de cobertura; null cuando no existe
updated_at string | null Cuándo cambió por última vez la entrada del directorio

GET /institutions

Parámetros de consulta:

Parámetro Significado
q Búsqueda difusa por nombre, mínimo 3 caracteres
domain Coincidencia por dominio web
country Código ISO de país, p. ej. US
provider PLAID, NORDIGEN, AKOYA, FINICITY, MERCURY, SNAPTRADE (GoCardless es NORDIGEN internamente)
page Número de página: siempre 10 resultados por página
curl "https://fintable.io/api/v2/institutions?q=chase&country=US"

Este es el único endpoint de la API paginado por desplazamiento: avanza con page hasta que has_more sea false.

La documentación y la guía como datos

Endpoint Qué devuelve
GET /guide La guía de usuario completa de Fintable en markdown
GET /docs Este documento en markdown
GET /openapi.json La descripción OpenAPI 3.1 de esta API

La propia documentación está disponible como markdown plano: práctico para alimentar un LLM o para renderizarla en tus propias herramientas. Todo público, sin autenticación.

GET /guide

La guía de usuario completa de Fintable en markdown. ?locale=main|uk|es selecciona el idioma.

GET /docs

Este documento en markdown. ?locale=main|uk|es selecciona el idioma.

GET /openapi.json

La descripción OpenAPI 3.1 de esta API: apunta a ella Swagger UI, Postman o un generador de código.


Convenciones de la API

Unas cuantas convenciones se aplican en todas partes, así que solo tienes que aprenderlas una vez.

El envoltorio de la respuesta

Las listas devuelven {"data": [...]} y los objetos individuales {"data": {...}}. Las listas de transacciones llevan además un next_cursor (consulta Paginación). La única excepción: el directorio público de instituciones está paginado por desplazamiento y usa meta: {page, has_more}.

Las peticiones deberían enviar Accept: application/json.

El dinero es una cadena

Los importes son cadenas decimales exactas"-4.50", "1234.56"—, nunca números en coma flotante, así que no pierdes ni un céntimo por redondeos. Los importes negativos son dinero que sale. Cada importe viaja con un campo currency aparte (la moneda efectiva, respetando cualquier anulación de moneda que hayas configurado). Los saldos de las cuentas siguen la misma convención.

Marcas de tiempo y fechas

Las marcas de tiempo son ISO-8601 en UTC, como 2026-07-26T15:04:05Z. Los campos date y auth_date de las transacciones son cadenas YYYY-MM-DD sin más.

Los ids de objeto son opacos

Los ids son cadenas opacas de hasta 64 caracteres. Guárdalos tal cual y no extraigas significado de ellos: las formas de abajo son para reconocerlos, no para parsearlos.

Objeto Qué aspecto tiene
Transacción tx_01J0AB... (las cuentas antiguas pueden tener cadenas numéricas heredadas como "48214321")
Cuenta acc_01J0AB... (aquí también existen cadenas numéricas heredadas)
Posición hol_01J0AB... o una cadena numérica heredada
Categoría {name-slug}_{10 alfanuméricos}, p. ej. dining-out_aB3xY9k2Lm
Regla UUID, p. ej. a25a374d-e4d7-4652-aca7-5dd3c3d02d15
Conexión conn_{provider}_{number}, p. ej. conn_plaid_1771845993762884095

Errores

Toda respuesta que no sea 2xx tiene exactamente una forma, así que un único manejador de errores cubre toda la API:

{
    "error": {
        "type": "not_found",
        "message": "No transaction with that id."
    }
}

Los fallos de validación (422) incluyen además mensajes por campo:

{
    "error": {
        "type": "validation_failed",
        "message": "The given data was invalid.",
        "errors": {
            "sync_start_date": [
                "Trial accounts can sync at most 30 days of history."
            ]
        }
    }
}
HTTP type Cuándo lo verás
400 bad_request / invalid_cursor Petición mal formada; o un cursor reutilizado con un orden distinto
401 unauthenticated Token ausente, caducado o revocado
403 forbidden Token válido, pero la acción no está permitida (p. ej. sincronizar en una cuenta gratuita)
404 not_found No existe ese objeto, incluidos los objetos de otra cuenta
405 method_not_allowed Verbo HTTP incorrecto
409 conflict La acción entra en conflicto con el estado actual (p. ej. eliminar una categoría que aún usan reglas)
413 payload_too_large Cuerpo de la petición por encima del límite
422 validation_failed La petición se entendió, pero algún campo es inválido
429 rate_limited Baja el ritmo: viene con una cabecera Retry-After
500 server_error Culpa nuestra; reinténtalo o escríbenos
503 service_unavailable Caída temporal o mantenimiento

Límites de tasa

Los límites son generosos para clientes educados y bien programados; solo los encontrarás si machacas un endpoint. Cada ruta tiene exactamente un cubo, y las llamadas a herramientas MCP consumen los mismos cubos que sus equivalentes REST. Cuando alcanzas un límite recibes un 429 con una cabecera Retry-After: respétala.

Cubo Límite
Lecturas autenticadas 300/min por token
Escrituras genéricas (PATCH/DELETE, categorías) 60/min por cuenta
Crear/actualizar reglas 12/hora por cuenta
POST /sync (y por conexión) Personal/Trial: 2/día · Office/Enterprise: 1/hora
POST /connections/link (y reconexión) 1/min por cuenta
PATCH /transactions/bulk 10/hora por cuenta
POST /categorizer/sync 6/día por cuenta
GET /institutions público 60/min por IP
/guide, /docs, openapi.json públicos 60/min por IP
Endpoint MCP 120/min por token
POST /oauth/register 5/hora por IP

Caché

Las respuestas autenticadas siempre se sirven frescas (Cache-Control: no-store). Los endpoints públicos (/institutions, /guide, /docs) se pueden cachear hasta una hora.


Paginación

Años de histórico de transacciones pueden ser decenas de miles de filas, así que GET /transactions (y su variante por cuenta) nunca lo devuelve todo de golpe: pagina con un cursor opaco. ¿Por qué un cursor y no números de página? Porque tus datos se mueven: una sincronización puede insertar o actualizar transacciones mientras paginas, y las páginas por desplazamiento se saltarían o duplicarían filas en silencio. Un cursor fija tu posición exacta en la secuencia, de modo que un recorrido completo ve cada fila exactamente una vez.

Pide una página y, si hay más, la respuesta te dice por dónde continuar:

curl "https://fintable.io/api/v2/transactions?limit=100" \
  -H "Authorization: Bearer YOUR_TOKEN"
{
    "data": [
        "... 100 transactions ..."
    ],
    "next_cursor": "eyJ2IjoxLCJvIjoiZGF0ZSIsazoi..."
}

Devuelve el cursor para obtener la página siguiente y sigue así hasta que next_cursor sea null:

curl "https://fintable.io/api/v2/transactions?cursor=eyJ2IjoxLC..." \
  -H "Authorization: Bearer YOUR_TOKEN"

Las reglas:

  • limit es 100 por defecto y llega como máximo a 500.
  • Los cursores son opacos y están ligados a su orden. Un cursor generado en un listado con order=date se rechaza (400 invalid_cursor) si se reutiliza con order=updated, y viceversa.
  • El orden por defecto es de más reciente a más antiguo por fecha de transacción.

Sincronización incremental

Si estás replicando transacciones en tu propia base de datos o aplicación, volver a descargar todo el histórico solo para recoger los cambios de ayer es lento y derrochador, y los límites de tasa no están dimensionados para eso. La sincronización incremental es la alternativa eficiente: cada transacción lleva una marca updated_at, y el endpoint de listado puede ordenar por ella, así que puedes pedir exactamente "todo lo que ha cambiado desde la última vez que miré".

Consultar los cambios

Consulta con ?order=updated&updated_since=<marca ISO>. Los resultados vuelven ordenados por updated_at ascendente, paginados con el mismo mecanismo de cursor de antes. La receta:

  1. Llama a GET /transactions?order=updated&updated_since=2026-07-25T00:00:00Z.
  2. Recorre las páginas con next_cursor, procesando cada transacción.
  3. Recuerda el updated_at más alto que hayas procesado; úsalo como el siguiente updated_since.

La letra pequeña honesta: las eliminaciones

Las eliminaciones son invisibles para la consulta incremental: no hay lápida ni registro de borrados. Dos situaciones que debes contemplar en tu diseño:

Estamos trabajando en una solución mejor que haga visibles las eliminaciones. Mientras tanto, nuestro mejor consejo es no descargar transacciones pendientes: usa pending=false al copiar transacciones a tu propia base de datos o aplicación.

  1. Rotación de transacciones pendientes. Las transacciones pendientes pueden sustituirse al contabilizarse (nuevo id, importe o fecha ajustados). Si aun así las importas, vuelve a descargar periódicamente una ventana de los últimos 30 días para detectarlo.
  2. Eliminaciones de cuentas completas. Cuando una cuenta desaparece de GET /accounts o pasa a enabled: false, descarta todas las transacciones que tuvieras cacheadas de esa cuenta.

Si necesitas más certeza que eso, vuelve a descargar todo periódicamente.


¿Preguntas o comentarios?

Si algo de aquí no queda claro, falta o directamente está mal, nos gustaría saberlo: escríbenos o usa la burbuja de soporte de cualquier página. Si estás construyendo algo sobre la API, estaremos encantados de ayudarte a que funcione.

Preferencias de visualización
Idioma

Hemos cambiado al idioma que tenías guardado. Elige otro y pulsa Hecho para volver a cambiarlo.

Moneda
Formato de números