Convenciones de la API

Reglas transversales que aplican a todos los endpoints. Conocerlas evita los errores más comunes al escribir un agente o un script.

Dinero

Los importes van en euros decimales, no en céntimos. Mil doscientos euros son 1200.00, no 120000. Usa punto decimal y dos decimales cuando corresponda.

{ "base": 1000.00, "iva": 210.00, "total": 1210.00 }

Fechas

Las fechas van en ISO-8601 (AAAA-MM-DD, por ejemplo 2026-07-08). Las marcas de tiempo siguen el mismo estándar. No uses formatos locales como 08/07/2026.

Identificadores

Los IDs de los recursos son UUID (por ejemplo 3f2a…). Esto vale para facturas, compras, tesorerías, movimientos, documentos y tipos de impuesto. En las líneas de factura/compra, el impuesto se referencia por su tax_type_id (un UUID que obtienes de /api/v1/taxes).

Paginación y filtros

Los endpoints de listado aceptan estos parámetros de consulta:

ParámetroQué hace
limitNúmero máximo de elementos a devolver.
offsetDesplazamiento (para paginar).
fromFecha inicial del rango (ISO-8601).
toFecha final del rango (ISO-8601).

Ejemplo:

curl "https://api.aikount.com/api/v1/bank-movements?treasury_id=<uuid>&from=2026-04-01&to=2026-06-30&limit=50" \
  -H "Authorization: Bearer agl_tu_clave_aqui"

Errores

Un error llega como estado HTTP más un cuerpo JSON con la clave detail:

{ "detail": "..." }

Los más habituales de autenticación son 401 (token ausente, inválido o revocado) y 403 (token válido sin el alcance necesario). Ver Autenticación.

detail puede ser un texto o un objeto con, como mínimo, code (identificador estable, para programar contra él) y message (texto para mostrar a una persona). Trata siempre ambos casos: si detail es un objeto, muestra detail.message.

{ "detail": { "code": "period_closed", "reason": "vat_settled", "message": "El 3T 2026 tiene la liquidación del IVA contabilizada…", "year": 2026, "quarter": 3, "side": "sale", "alternatives": [ … ] } }
- **Liquidaciones del IVA desfasadas.** `GET /taxes/vat-settlement-alerts` lista las liquidaciones asentadas que ya no cuadran con sus documentos (`stale`, con `difference`) o que se hicieron antes de acabar el trimestre (`premature`), con `action` (`redo` | `regularize` | `revert`). Exportar el 303 (`/aeat/303`, `/aeat/303/{año}/{trimestre}/export`, `/taxes/model-303/{año}/{trimestre}/export`) o marcarlo/subirlo como presentado con la liquidación desfasada devuelve `409 vat_settlement_stale` salvo `?confirm_stale_settlement=true`.
- **Facturas emitidas → no se borran.** `DELETE /invoices/{id}` y `POST /invoices/bulk-delete` solo borran una factura emitida si es la **última de su serie**, no se ha enviado ni cobrado (ni tiene enlace público) y no está registrada en VERI*FACTU (su número queda libre, sin hueco). Si no, `409` con `code: "issued_invoice_not_deletable"`, `reason` (`not_last` | `sent` | `verifactu` | `filed_period`) y `alternatives` (`rectify` → `POST /invoices/{id}/rectify`; `cancel` si se emitió por error y no tiene cobros). `force` ya no salta esta regla (RD 1619/2012 arts. 6 y 15; RD 1007/2023 art. 8).

Cambios recientes de la API (septiembre 2026)

  • Trimestres liquidados → 409 period_closed. Crear, editar, anular o borrar una venta (factura, ticket, rectificativa) con fecha en un trimestre cuyo IVA ya está liquidado (o con el 303 presentado) devuelve 409 y detail pasa de texto a objeto (code: "period_closed", reason, message, year, quarter, entry_number, filed_303, side, alternatives). En compras, el 409 trae requires_confirmation: true y confirm_param: "confirm_settled_period": lo normal es registrarla con su fecha y deducir su IVA en el periodo abierto (art. 99 LIVA): repite la llamada con vat_deduction_date (el 409 trae deduction_param y suggested_vat_deduction_date; en POST /purchases/{id}/issue va como query, en POST/PATCH /purchases en el cuerpo). El trimestre liquidado no cambia. Si prefieres deducirla en el trimestre original, repite con ?confirm_settled_period=true (la liquidación queda desactualizada). Las compras con IVA autorrepercutido (ISP, intracomunitarias, importación diferida) o en criterio de caja no admiten vat_deduction_date (422). Solo cuenta un trimestre ya terminado: una liquidación hecha antes de que acabe el trimestre no lo cierra (aparece como premature en GET /taxes/vat-settlement/{año}/{trimestre}).
  • Periodos presentados → nunca cambian. Si un periodo tiene presentada una declaración de la familia del IVA (303, 369, 349, 390, IGIC), sus ventas no se crean, editan (importes, impuestos, fecha, cliente), anulan ni borran, y no hay confirmación posible: 409 con code: "period_closed", reason: "period_filed", models y requires_confirmation: false; corrígelo con una rectificativa con fecha de hoy. Una compra fechada en un periodo con el IVA presentado se registra con su fecha y su IVA se deduce hoy (vat_deduction_date automático, art. 99 LIVA); confirm_settled_period ya no vale para periodos presentados. Si la compra ya se incluyó en lo presentado (histórico, gestor), contabilízala con declared_in_filed_period=true (query de POST /purchases/{id}/issue o cuerpo de POST/PATCH /purchases en borrador): cuenta en su periodo y su IVA no se vuelve a deducir. Las importaciones CSV no importan ventas de periodos presentados salvo con declared_history=true (histórico ya declarado). El 111/115, los pagos a cuenta (130/202) y las informativas no bloquean compras, bancos ni reglas; el 200 congela el resultado de su ejercicio. Para corregir un periodo presentado: POST /taxes/filings/{id}/reopen (propietario/administrador, reason), POST /taxes/reopens/{id}/close (rectificativa, corrected_reference) o /cancel (sólo si nada cambió). Las pantallas y exportaciones de los modelos de un periodo presentado devuelven lo presentado (filed.frozen: true), no un recálculo.
  • GET /taxes/vat-settlement/{año}/{trimestre} añade premature, filed_303_premature, can_revert, ledger_stale y period_drift (skipped_count, posted_count, items): documentos que cambiaron o se registraron después de cerrar el trimestre por procesos automáticos (sincronizaciones, importaciones) sin rehacer su asiento.
  • Fecha futura → 422 future_issue_date. Una factura de venta no se emite con fecha posterior a hoy (margen de un día por husos horarios). Los borradores y las compras con fecha futura solo reciben un aviso.
  • POST /bank-movements solo en tesorerías de caja (kind: cash); en bancos, tarjetas o pasarelas responde 422 treasury_not_cash (sus movimientos entran por importación del extracto o por la integración). El movimiento se contabiliza en el mismo paso contra su destination (factura, cuenta o traspaso). external_id se guarda y deduplica: repetirlo en la misma caja devuelve el movimiento existente con duplicate: true y estado 200 (en vez de 201).
  • POST /accounts y PATCH /accounts/{id} validan el número: solo dígitos (629.1 se expande), una subcuenta empieza por el número de su cuenta madre (que no puede ser a su vez una subcuenta) y tiene la longitud del plan del tenant o cualquier otra longitud que el tenant ya use (planes con subcuentas de 7 y 8 dígitos mezcladas); el grupo sale del primer dígito. Un número inválido devuelve 422 y un duplicado 409.
  • GET /accounts y las subcuentas de contacto (430xxxxx/400xxxxx/410xxxxx, auto_kind: "contact"): el listado general las deja fuera, pero se incluyen automáticamente al buscar (search), al pedir los hijos de una cuenta (parent_id) o un número exacto (nuevo parámetro number, p. ej. ?number=43000001). include_contacts=true|false fuerza el comportamiento. La herramienta MCP list_accounts acepta include_contacts, number y parent_id, y aikount ledger account 43000001 las encuentra.
  • GET /accounting/financial-statements acepta compare=previous|last_year y devuelve 422 si from_date es posterior a to_date. Claves nuevas: pnl.partidas (PyG del modelo oficial del PGC, partidas 1-17 y subtotales A.1-A.4), pnl.gestion (margen bruto, % sobre la cifra de negocios y comparativa) y opening_warning (más una entrada en warnings) cuando la cuenta puente 555 de saldos de apertura tiene saldo. Las claves planas antiguas se mantienen; ingresos_excepcionales y gastos_excepcionales valen siempre 0. Los saldos iniciales de tesorería de los tenants con el plan anterior siguen contra la 120 y no generan aviso.
  • POST /journal (asiento manual): una línea en una cuenta de agrupación (2-4 dígitos) se lleva a su subcuenta por defecto y la respuesta lo explica en warnings; una línea en 430/400/410 con subcuentas por contacto devuelve 422 (usa la subcuenta del contacto o la genérica «varios»).
  • Contactos: DELETE /contacts/{id} devuelve 409 contact_in_use si el contacto tiene documentos o apuntes en su subcuenta (fusiónalo con otro); POST /contacts/bulk-delete los omite con reason: "has_documents" | "has_postings". POST /contacts/{id}/merge traslada también las subcuentas contables del duplicado (campo subaccounts en la respuesta).
  • Importación CSV de ventas (POST /invoices/import-csv): las facturas con fecha en un trimestre liquidado ya no se omiten; se importan como históricas, con un aviso en warnings, y la liquidación de ese trimestre queda desactualizada.
  • Editar un documento emitido solo rehace su asiento si cambia algo fiscal (líneas, descuentos, contacto, fecha, moneda, arrendamiento): cambiar notas, etiquetas, proyecto o vencimiento nunca devuelve el 409 de trimestre liquidado.
  • POST /reconciliation/dismiss acepta counterpart_movement_id (en lugar de document_id) para descartar una propuesta de traspaso.

La fuente de la verdad

Esta documentación describe las convenciones estables, pero la especificación OpenAPI es la referencia autoritativa sobre parámetros exactos, tipos, campos y respuestas de cada endpoint:

https://api.aikount.com/openapi.json

También puedes explorarla en Swagger UI (/docs) o Redoc (/redoc). Si algo aquí discrepa del openapi.json, manda el openapi.json.

Ver también

Cookies y privacidad

Usamos analítica propia sin cookies. Con tu permiso, medimos los registros y pagos procedentes de anuncios de Google y ChatGPT. Más información · Privacidad