API pública del ERP
iEnTop incluye una API REST pública para que su tienda online, su TPV o cualquier software a medida trabaje directamente con los datos del ERP: clientes y proveedores, direcciones, catálogo y stock, documentos de venta y cobros. Cada llamada ejecuta la misma lógica de negocio que usa el propio ERP — mismas validaciones, mismas relaciones entre datos y mismo ciclo fiscal — por lo que un cliente o una factura creados por la API son indistinguibles de los creados a mano.
La API está incluida en la suscripción, sin coste adicional.
Para quién es esta página
Está pensada para la persona (interna o externa) que va a programar la integración. No se necesita ningún conocimiento del ERP más allá de lo que se explica aquí.
1. Obtención del token
Las credenciales se generan desde el propio ERP, sin tickets de soporte:
📍 SISTEMA › Configuración Empresa › Identidad › sección Acceso API
- Pulse Generar token.
- Escriba un nombre descriptivo (por ejemplo, "Tienda online" o "TPV mostrador"). Aparecerá en el registro de auditoría de cada operación que haga esa integración.
- Elija la caducidad: sin caducidad, 90 días, 180 días o 1 año.
- Marque los permisos del token — lectura o escritura por cada área (ver permisos). Conceda solo lo que la integración necesite.
- Pulse Generar token y cópielo en ese momento: por seguridad, el token completo no se vuelve a mostrar nunca. Si lo pierde, revóquelo y genere otro.
El token tiene esta forma:
iek_MXwzfDd8MTR8N2E4… (una sola línea, ~120 caracteres)Trátelo como una contraseña
El token da acceso a los datos de su empresa. No lo comparta por canales inseguros, no lo publique en repositorios de código y guárdelo en la configuración segura de su aplicación. Desde la misma pantalla puede revocarlo en cualquier momento: deja de funcionar en menos de un minuto.
2. Autenticación
Todas las peticiones se autentican con el token en la cabecera Authorization, esquema Bearer:
GET /tms/xdata/tenant/terceros/v1/list?text=&offset=0&limit=25&filterTipo=Cliente HTTP/1.1
Host: terceros.xdata.formaticati.com
Authorization: Bearer iek_MXwzfDd8MTR8N2E4…- El token identifica a su empresa (no a un usuario) y opera con visibilidad completa del tenant.
- No hay que renovar sesiones ni hacer login: cada petición viaja autenticada por sí misma.
- Una petición sin token, con token revocado o caducado recibe 401; una petición a un recurso para el que el token no tiene permiso recibe 403.
3. Permisos (scopes)
Cada token lleva una lista de permisos por área. La escritura incluye siempre la lectura de su misma área.
| Permiso | Concede |
|---|---|
terceros | Lectura de clientes/proveedores, sus direcciones, contactos y maestros de pago |
terceros:write | Alta y edición de clientes y proveedores (con direcciones embebidas) y contactos |
catalogo | Lectura de productos, precios y stock |
catalogo:write | Alta y edición de productos |
ventas | Lectura de documentos, maestros de facturación y cálculo previo |
ventas:write | Crear, emitir y convertir documentos; venta TPV; rectificativas |
cobros | Lectura de vencimientos |
cobros:write | Registro de cobros (liquidar vencimientos) |
contabilidad | Lectura de diario, mayor, balance, PyG, plan de cuentas y ejercicios |
contabilidad:write | Creación de asientos (con sus apuntes) y validación |
Las direcciones viajan con el tercero
No existe un dominio de direcciones: una dirección solo tiene sentido ligada a su tercero. En el alta se envían embebidas como array de textos y el servidor resuelve país, provincia, población y vía por búsqueda; la lectura es siempre por tercero. Ver 5.2.
4. Convenciones generales
Hosts. Cada dominio funcional se sirve desde su propio host. La base de todas las rutas es https://<host>/tms/xdata:
| Dominio | Host |
|---|---|
| Terceros, direcciones, geografía, maestros de pago | terceros.xdata.formaticati.com |
| Facturación, tesorería, venta TPV | facturacion.xdata.formaticati.com |
| Catálogo y stock | catalogo.xdata.formaticati.com |
| Contabilidad (asientos, mayor, informes) | contafin.xdata.formaticati.com |
Formato. Peticiones y respuestas en JSON (Content-Type: application/json). Muchas respuestas de listado envuelven el resultado en un campo value que contiene un JSON serializado — decodifíquelo con su librería JSON habitual.
Parámetros GET. Pase todos los parámetros de consulta del endpoint aunque vayan vacíos (el servidor los exige). Atención a las mayúsculas: Terceros y Facturación usan minúsculas (filter, order_by, offset, limit…) y Catálogo los usa capitalizados (Filter, OrderBy, Offset, Limit).
Identificadores. Los id son enteros de 64 bits. Las altas devuelven el id del registro creado en {"value": <id>}.
5. Endpoints
5.1 Clientes y proveedores — tenant/terceros/v1
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| GET | list | text, offset, limit, filterTipo (Cliente|Proveedor) | Listado paginado con búsqueda |
| GET | get | id | Ficha completa del tercero |
| GET | get-by-cifnif | cifnif | Búsqueda exacta por NIF — útil para no duplicar antes de crear |
| GET | validate-cifnif | cifnif, pais (ES) | Valida el NIF y avisa si ya existe |
| GET | tipos | area (vacío = todos) | Catálogo de tipos/roles; el campo nombre es el valor que espera add-role |
| POST | clientes/create | body: razon_social, cifnif, email, telefono, movil, direcciones (array, opcional) | Alta de cliente en una llamada: crea el tercero con todas sus relaciones, el rol de cliente y sus direcciones embebidas |
| POST | proveedores/create | body: ídem | Alta de proveedor en una llamada (con direcciones embebidas) |
| POST | create | body: ídem | Alta del tercero sin rol comercial (se asigna después con add-role) |
| POST | add-role | body: tercero_id, tipo (nombre del tipo, p. ej. Cliente) | Asigna un rol a un tercero existente |
| POST | detail/save | body: ficha completa (id = 0 para alta) | Edición completa del tercero |
| GET | personas-contacto/list-by-tercero | tercerosId | Personas de contacto del tercero |
| POST | personas-contacto/create-and-assign | body: datos de la persona + tercerosId | Crea una persona de contacto y la asigna |
Maestros de pago — tenant/pagos/v1 (permiso terceros):
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| GET | payment-methods/list | only_active | Formas de pago de la empresa |
| GET | payment-terms/list | only_active | Condiciones de pago |
5.2 Direcciones embebidas en el alta
Las direcciones se envían dentro de clientes/create / proveedores/create, en el campo direcciones (array). Cada elemento es texto plano — no hay que consultar ningún catálogo ni enviar identificadores: el servidor resuelve el país, la comunidad, la provincia, la población y la vía por búsqueda (tolerante a mayúsculas y tildes), compone el texto de la dirección y garantiza una única dirección Principal y una Fiscal por tercero.
"direcciones": [{
"tipo_via": "Calle", // código ('CL', 'AV'…) o nombre
"via": "San Juan del Puerto",
"numero": "19",
"complemento": "", "bloque": "", "escalera": "",
"piso": "3", "puerta": "B",
"cp": "10195",
"poblacion": "Cáceres",
"provincia": "Cáceres",
"region": "Extremadura", // opcional
"pais": "ES", // código o nombre; vacío = España
"es_principal": true,
"es_fiscal": true
}]Reglas: la primera dirección del tercero queda marcada automáticamente como Principal y Fiscal; los tipos de vía y las calles se crean si no existen; las provincias y poblaciones se buscan en los maestros del ERP — si no hay coincidencia razonable, la dirección se guarda sin ese componente (no se crean duplicados en los catálogos).
Lectura de las direcciones de un tercero:
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| GET | tenant/direcciones/v1/by-tercero | tercero_id | Direcciones del tercero (permiso terceros) |
5.3 Catálogo y stock — almacen-svc/v1
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| GET | products | Filter, OrderBy, Offset, Limit | Listado de productos |
| GET | products/{id} | — | Ficha del producto |
| GET | products/lookup | q | Autocompletado por texto |
| GET | pricing/resolve/{id} | qty, clienteId | Motor de precios: mejor tarifa para ese cliente y cantidad |
| GET | stock/actual | filtros opcionales | Stock físico |
| GET | stock/disponible/{id} | — | Disponible (físico − reservas) |
| POST | products | body: datos del producto | Alta de producto |
| PUT | products/{id} | body: datos del producto | Edición de producto |
5.4 Documentos de venta — facturacion-svc
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| POST | documentos/save | body: cabecera + líneas (+ tipo) | Creación transaccional del documento con impuestos y vencimientos. El mismo endpoint crea presupuestos, pedidos, albaranes y facturas según el tipo |
| POST | documentos/cambiar-estado | body: id, estado destino | Emisión fiscal (borrador → validado): numeración de serie, VeriFactu, libro y asiento |
| POST | documentos/convertir | body: id, tipo destino | Presupuesto → pedido → albarán → factura |
| POST | tpv/emitir | body: venta de mostrador | Venta TPV completa en una llamada |
| POST | tesoreria/crear-rectificativa | doc_id, motivo, modalidad, vf_tipo | Rectificativa (la vía legal para anular una factura emitida) |
| GET | documentos/list | filter, order_by, offset, limit, search, grupo, estado | Listado de documentos |
| GET | documentos/get | id | Documento completo |
| POST | documentos/generate-taxes | body: líneas | Previsualización de impuestos y totales, sin guardar nada |
| POST | documentos/generate-vencimientos | body: condiciones | Previsualización de vencimientos |
| GET | config/impuestos/list | solo_activos | Tipos de IVA de la empresa |
| GET | catalogos/series · tipos-doc · monedas · estados | — | Maestros necesarios para montar documentos |
5.5 Cobros — facturacion-svc/tesoreria
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| GET | tesoreria/vencimientos | es_cobro=1 + filtros | Vencimientos (cartera de cobros) |
| POST | tesoreria/liquidar-vencimiento | body: vencimiento + datos del cobro | Registra el cobro con su asiento. Caso típico: su pasarela de pago confirma un cobro y la integración lo anota en el ERP |
5.6 Contabilidad: asientos y apuntes — contabilidad-svc
Para software contable y asesorías: volcar asientos en el ERP y extraer el diario, el mayor y los informes. El alta es transaccional — cabecera y apuntes viajan juntos, y el sistema controla la cuadratura (debe = haber).
| Método | Ruta | Parámetros | Descripción |
|---|---|---|---|
| POST | diario/asiento | body (ver ejemplo) | Crea el asiento con sus apuntes. Devuelve {id, numero, cuadrado} |
| POST | diario/validar | body: {id} | Pasa el asiento de BORRADOR a VALIDADO |
| GET | diario/list | filter, estado, origen, periodo, fecha_desde, fecha_hasta, solo_descuadrados, orden_campo, orden_dir, offset, limit, filtro_apunte | Diario paginado |
| GET | diario/asiento | id | Asiento completo con sus apuntes (data.lineas) |
| GET | informes/mayor | cuenta, periodo, fecha_desde, fecha_hasta | Libro mayor: apuntes de una cuenta |
| GET | informes/balance · informes/pyg · informes/sumas-saldos | (nivel en sumas-saldos) | Informes de situación |
| GET | pgc/list | nivel_max, grupo, solo_con_saldo | Plan de cuentas |
| GET | pgc/search | q, solo_auxiliares, prefijos, solo_mayores, min_len=0, max_len=0 | Búsqueda de cuentas |
| GET | pgc/cuenta | id | Ficha de la cuenta |
| GET | ejercicios/list | — | Ejercicios contables |
Ejemplo de alta de asiento:
POST contabilidad-svc/diario/asiento
{
"fecha": "12/07/2026",
"concepto": "Traspaso de caja a banco",
"lineas": [
{ "cuenta_codigo": "5720000000", "concepto": "Ingreso en banco", "debe": 100, "haber": 0 },
{ "cuenta_codigo": "5700000000", "concepto": "Salida de caja", "debe": 0, "haber": 100 }
]
}Las cuentas se indican por su código (o por cuenta_id); si una cuenta auxiliar de 10 dígitos no existe, se crea automáticamente colgando de su mayor. La fecha va siempre en formato español DD/MM/YYYY. No se pueden eliminar, desvalidar ni sellar asientos por la API, ni cerrar ejercicios: esas operaciones se reservan al ERP.
6. Errores
Las respuestas de error tienen siempre este cuerpo:
{ "success": false, "error": "<código>", "message": "<explicación>" }| HTTP | error | Significado |
|---|---|---|
| 401 | invalid_api_token | Token mal formado, firma inválida o inexistente |
| 401 | api_token_expired | Token caducado |
| 401 | api_token_revoked | Token revocado desde el ERP |
| 403 | not_in_public_api | La ruta no forma parte de la API pública |
| 403 | insufficient_scope | Al token le falta el permiso indicado en message |
| 429 | rate_limited | Superado el límite de peticiones — espere unos segundos y reintente |
| 503 | api_unavailable | Incidencia temporal del servicio; reintente |
7. Límites y buenas prácticas
- Límite de peticiones: 120 por minuto y por token. Al superarlo,
429. - Revocación: efectiva en menos de un minuto.
- Un token por integración: facilita auditar cada aplicación y revocar una sin afectar a las demás.
- Permisos mínimos: si la integración solo lee stock, no le conceda escrituras.
- Idempotencia: antes de crear un cliente, consulte
get-by-cifnifpara no duplicarlo. - Sin borrados: la API no permite eliminar registros. La anulación de una factura emitida es la rectificativa, como exige la normativa.
- Los entornos de demostración rechazan las escrituras (error
DEMO_…).
8. Ejemplo completo
Alta de un cliente y consulta de su ficha:
BASE="https://terceros.xdata.formaticati.com/tms/xdata"
TOKEN="iek_…" # generado en Sistema › Configuración Empresa › Identidad
# ¿Existe ya? (búsqueda exacta por NIF)
curl -s "$BASE/tenant/terceros/v1/get-by-cifnif?cifnif=B12345678" \
-H "Authorization: Bearer $TOKEN"
# Alta de cliente en una llamada, con su dirección fiscal embebida
# (textos, sin identificadores) → {"value": <id>}
curl -s -X POST "$BASE/tenant/terceros/v1/clientes/create" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"razon_social":"ACME SL","cifnif":"B12345678","email":"admin@acme.es",
"telefono":"","movil":"",
"direcciones":[{
"tipo_via":"Calle","via":"Mayor","numero":"5","cp":"28001",
"poblacion":"Madrid","provincia":"Madrid","pais":"ES",
"es_principal":true,"es_fiscal":true
}]
}'
# Su ficha y sus direcciones
curl -s "$BASE/tenant/terceros/v1/get?id=1042" \
-H "Authorization: Bearer $TOKEN"
curl -s "$BASE/tenant/direcciones/v1/by-tercero?tercero_id=1042" \
-H "Authorization: Bearer $TOKEN"¿Necesita ayuda con su integración?
Escríbanos a saas@ientop.es y le acompañamos: ejemplos en su lenguaje, revisión del diseño de la integración y resolución de dudas.

