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ámetro | Qué hace |
|---|---|
limit | Número máximo de elementos a devolver. |
offset | Desplazamiento (para paginar). |
from | Fecha inicial del rango (ISO-8601). |
to | Fecha 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) devuelve409ydetailpasa de texto a objeto (code: "period_closed",reason,message,year,quarter,entry_number,filed_303,side,alternatives). En compras, el 409 traerequires_confirmation: trueyconfirm_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 convat_deduction_date(el 409 traededuction_paramysuggested_vat_deduction_date; enPOST /purchases/{id}/issueva como query, enPOST/PATCH /purchasesen 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 admitenvat_deduction_date(422). Solo cuenta un trimestre ya terminado: una liquidación hecha antes de que acabe el trimestre no lo cierra (aparece comoprematureenGET /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:
409concode: "period_closed",reason: "period_filed",modelsyrequires_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_dateautomático, art. 99 LIVA);confirm_settled_periodya no vale para periodos presentados. Si la compra ya se incluyó en lo presentado (histórico, gestor), contabilízala condeclared_in_filed_period=true(query dePOST /purchases/{id}/issueo cuerpo dePOST/PATCH /purchasesen borrador): cuenta en su periodo y su IVA no se vuelve a deducir. Las importaciones CSV no importan ventas de periodos presentados salvo condeclared_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ñadepremature,filed_303_premature,can_revert,ledger_staleyperiod_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-movementssolo en tesorerías de caja (kind: cash); en bancos, tarjetas o pasarelas responde422 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 sudestination(factura, cuenta o traspaso).external_idse guarda y deduplica: repetirlo en la misma caja devuelve el movimiento existente conduplicate: truey estado200(en vez de201).POST /accountsyPATCH /accounts/{id}validan el número: solo dígitos (629.1se 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 devuelve422y un duplicado409.GET /accountsy 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ámetronumber, p. ej.?number=43000001).include_contacts=true|falsefuerza el comportamiento. La herramienta MCPlist_accountsaceptainclude_contacts,numberyparent_id, yaikount ledger account 43000001las encuentra.GET /accounting/financial-statementsaceptacompare=previous|last_yeary devuelve422sifrom_datees posterior ato_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) yopening_warning(más una entrada enwarnings) cuando la cuenta puente555de saldos de apertura tiene saldo. Las claves planas antiguas se mantienen;ingresos_excepcionalesygastos_excepcionalesvalen siempre 0. Los saldos iniciales de tesorería de los tenants con el plan anterior siguen contra la120y 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 enwarnings; una línea en430/400/410con subcuentas por contacto devuelve422(usa la subcuenta del contacto o la genérica «varios»).- Contactos:
DELETE /contacts/{id}devuelve409 contact_in_usesi el contacto tiene documentos o apuntes en su subcuenta (fusiónalo con otro);POST /contacts/bulk-deletelos omite conreason: "has_documents" | "has_postings".POST /contacts/{id}/mergetraslada también las subcuentas contables del duplicado (camposubaccountsen 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 enwarnings, 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
409de trimestre liquidado. POST /reconciliation/dismissaceptacounterpart_movement_id(en lugar dedocument_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.