API e integraciones (CRM, Make, n8n)
Conecta tu CRM o tu ERP con Sattotal mediante claves de API: sincroniza clientes y proveedores de forma automática y segura
La API de Sattotal permite que otro programa —tu CRM, tu ERP, Make, n8n, Zapier o un script propio— lea y cree clientes y proveedores en tu organización sin que nadie tenga que importar un CSV a mano. Se controla con claves de API que el administrador crea en Configuración → API, cada una con nombre propio y con permisos por recurso, y que se pueden revocar en cualquier momento. Aquí tienes qué hace, cómo crear la clave, cómo llamar a la API y cómo montar una sincronización con Make paso a paso.
Conecta tu CRM y tus automatizaciones
Cualquier herramienta capaz de hacer una petición HTTP (Make, n8n, Zapier, tu propio CRM o ERP) puede leer, crear y actualizar clientes y proveedores.
Claves con nombre y permisos
Una clave por integración, y dentro de cada clave un permiso por recurso: puedes dar lectura de proveedores sin dar escritura de clientes. Hasta 10 claves activas por organización.
Sincronización incremental
Con el parámetro actualizadoDesde solo se traen los clientes o proveedores que han cambiado desde la última pasada: ideal para un escenario que corre cada pocos minutos.
Segura por diseño
La clave se enseña una única vez y se guarda cifrada de forma irreversible. Cada clave solo accede a los datos de su organización y se revoca al instante.
Quién puede usarla
Las claves las crean y revocan los administradores de la organización. La API está incluida en los planes de pago (Basic, Pro y Enterprise) y durante el periodo de prueba; en el plan gratuito la pantalla muestra un candado con la opción de cambiar de plan. Una clave siempre actúa en nombre de la organización, no de una persona: no hereda los permisos de ningún técnico ni aparece como usuario en el equipo.
Cómo crear una clave
Entra en Configuración → API
Desde el menú lateral, Configuración, tarjeta «API». Verás la lista de claves de tu organización (activas y revocadas) y una tarjeta «Cómo conectar» con la URL base y un ejemplo.
Pulsa «Nueva clave»
Ponle un nombre que identifique la integración («CRM de la tienda», «Make», «n8n»). Así, si algún día tienes que revocarla, sabrás cuál es.
Elige los permisos
Marca los recursos que necesite la integración —Clientes, Proveedores o los dos— y para cada uno elige «Solo lectura» (consultar) o «Lectura y escritura» (consultar, crear, actualizar y archivar). Un recurso sin marcar es un recurso al que la clave no llega. Elige el mínimo que necesite.
Copia la clave y guárdala en tu herramienta
La clave completa (empieza por sat_) se enseña una única vez. Cópiala con el botón y pégala en Make, n8n o tu CRM. Si la pierdes no se puede recuperar: se revoca y se crea otra.
Configuración → API: lista de claves y clave recién creada
CRM Make
sat_Ab3k…x9Zq
n8n
sat_Qm7t…p2Lk
Clave creada
sat_Ab3k9Zq2Xv8Lp1Mn4Rt7Wy0Cd5Fg6Hj3Kl8Sx9ZqCopiarEsta es la única vez que verás la clave completa. Si la pierdes, revócala y crea otra.
Permisos de una clave
Solo lectura
Puede listar y consultar ese recurso. Cualquier intento de crear, modificar o archivar recibe una error 403 con el código PERMISO_DENEGADO y el permiso que le falta.
Lectura y escritura
Además de consultar, puede crear, actualizar y archivar en ese recurso. Es el permiso que necesita una sincronización bidireccional.
Los permisos son por recurso
Los permisos son por recurso, y eso ya se ha notado: al añadir los proveedores, las claves que existían —todas de clientes— NO ganaron acceso a ellos. Hubo que marcarlo. Lo mismo valdrá para cualquier recurso que se añada después: una integración nunca ve más de lo que le concediste.
Cómo autenticarse
Envía la clave en cada petición, de servidor a servidor, en la cabecera Authorization: Bearer sat_…. Si tu herramienta no permite cabeceras de autorización, también se acepta en la cabecera x-api-key. La URL base es la de tu Sattotal seguida de /api/v1 (la tienes copiada en la pantalla de Configuración → API).
GET /api/v1/me Authorization: Bearer sat_Ab3k9…x9Zq
La API no tiene CORS a propósito: está pensada para servidores y herramientas de automatización, no para páginas web ni apps que corran en el navegador de tus clientes. Una clave nunca debe llegar a un navegador.
Qué se puede hacer (endpoints)
Todas las respuestas llevan la forma success + data (y pagination en los listados). A un cliente puedes pedirlo por su id o por su código (CLI-0007); a un proveedor, solo por su id.
| Método | Ruta | Qué hace | Permiso |
|---|---|---|---|
| GET | /me | Devuelve tu organización y la clave con la que llamas. Úsalo para «probar la conexión» en Make o n8n. | Cualquiera |
| GET | /clientes | Lista paginada de clientes. Filtros: busqueda, tipo, activo y actualizadoDesde. Sin activo devuelve también los archivados. | Lectura |
| POST | /clientes | Crea un cliente con las mismas reglas que el formulario (identificador fiscal según tu país, sin duplicados de NIF ni de email). | Escritura |
| GET | /clientes/{id} | Devuelve un cliente por id o por código. | Lectura |
| PATCH | /clientes/{id} | Actualiza solo los campos enviados. PUT se acepta como sinónimo. | Escritura |
| DELETE | /clientes/{id} | Archiva el cliente (activo = false). No borra nada y se puede repetir sin error. | Escritura |
| GET | /proveedores | Lista paginada de proveedores. Filtros: busqueda, activo, tipoProveedor, codigo y actualizadoDesde. Sin activo devuelve también los archivados. | Lectura |
| POST | /proveedores | Crea un proveedor. Solo el nombre es obligatorio. Si ya hay uno con el mismo identificador fiscal o el mismo nombre, responde 409 con el id del existente. | Escritura |
| GET | /proveedores/{id} | Devuelve un proveedor por su id. Aquí el código NO vale: mira el aviso de más abajo. | Lectura |
| PATCH | /proveedores/{id} | Actualiza solo los campos enviados. La lista de contactos se reemplaza entera. PUT se acepta como sinónimo. | Escritura |
| DELETE | /proveedores/{id} | Archiva el proveedor (activo = false). No borra nada y se puede repetir sin error. | Escritura |
| GET | /reparaciones | Lista paginada de fichas, de la entrada más reciente a la más antigua. Filtros: cliente, estado, entradaDesde, entradaHasta y actualizadoDesde. | Lectura |
| GET | /reparaciones/{id} | Devuelve una ficha por su id o por su número de ficha. | Lectura |
| GET | /clientes/{id}/reparaciones | Las fichas de un cliente (por su id o su código), con los mismos filtros. | Lectura |
| GET | /clientes/{id}/resumen | Resumen de actividad del cliente: cuántas reparaciones tiene (en total, abiertas y por estado), cuánto se le ha presupuestado y cuándo vino por última vez. | Lectura |
Campos del cliente
Los campos son los mismos que en la ficha del cliente: nombre y tipo (particular o empresa) son obligatorios; nif_cif, apellidos, razonSocial, email, telefono, telefonoSecundario, direccion (calle, numero, piso, codigoPostal, localidad, provincia, pais) y notas son opcionales. El identificador fiscal se guarda en mayúsculas y el email en minúsculas. En la respuesta todas las claves están siempre presentes, con null cuando no hay valor, para que el mapeo de campos en tu herramienta no se rompa. Ojo con el nombre: nombre es el nombre de pila (o el nombre comercial si es una empresa) y el apellido va aparte, en apellidos, en plural.
Campos que la API no reconoce
Si el cuerpo trae una clave que no existe (por ejemplo firstName en vez de nombre, o apellido en singular en vez de apellidos), la petición no se rechaza, pero ese dato no se guarda. Para que no pase desapercibido, la respuesta de alta y de edición de clientes incluye avisos.camposIgnorados con la lista de esas claves; las de la dirección llevan su ruta, como direccion.ciudad. Si te aparece, revisa el mapeo de campos de tu integración. Los campos que devuelve la propia API (id, codigo, createdAt…) no generan aviso, así que puedes leer un cliente, cambiarlo y devolverlo entero.
POST /api/v1/clientes
{ "firstName": "Daniel", "nombre": "Florea", "tipo": "particular" }
201 Created
{
"success": true,
"data": { "nombre": "Florea", "apellidos": null, … },
"avisos": { "camposIgnorados": ["firstName"] }
}Ejemplo: crear un cliente
Petición
POST /api/v1/clientes
Authorization: Bearer sat_Ab3k9…x9Zq
Content-Type: application/json
{
"nombre": "Daniel",
"apellidos": "Florea",
"tipo": "empresa",
"razonSocial": "Assista Tech SRL",
"nif_cif": "RO12345678",
"codigoPersonalizado": "801",
"email": "daniel@example.com",
"telefono": "+40 700 000 000",
"direccion": { "localidad": "București", "pais": "RO" }
}Respuesta (201)
{
"success": true,
"data": {
"id": "64b0…0001",
"codigo": "CLI-0042",
"codigoPersonalizado": "801",
"codigoVisible": "801",
"tipo": "empresa",
"nombre": "Daniel",
"apellidos": "Florea",
"razonSocial": "Assista Tech SRL",
"nif_cif": "RO12345678",
"email": "daniel@example.com",
"activo": true,
"createdAt": "2026-09-18T10:00:00.000Z",
"updatedAt": "2026-09-18T10:00:00.000Z"
}
}Proveedores
Además de los clientes, la API expone el catálogo de proveedores: los mismos cinco endpoints, los mismos códigos de error y la misma sincronización incremental. Es solo el catálogo: las compras y las facturas de proveedor se quedan donde ya estén, en tu ERP o en Sattotal.
Campos del proveedor
Solo nombre es obligatorio. Opcionales: codigo, cif, email, telefono, telefonoSecundario, web, direccion (en una sola línea, no es un objeto como en clientes), ciudad, provincia, codigoPostal, pais, contactos, tipoProveedor (general, producto, servicio, logistica u otro), formaPago, plazoPago (en días; 0 es al contado), cuentaCliente y notas. Cada contacto lleva nombre —obligatorio—, cargo, telefono, email y notas; los contactos no tienen identificador propio.
Cómo se actualizan los contactos
La lista que envías REEMPLAZA la que había. Si envías una lista vacía, se borran todos los contactos; si no envías la clave (o envías null), se quedan como estaban. Es lo que hace que puedas leer un proveedor, cambiarle un campo y devolverlo entero sin efectos raros.
Petición
POST /api/v1/proveedores
Authorization: Bearer sat_Ab3k9…x9Zq
Content-Type: application/json
{
"nombre": "Distribuciones Norte",
"cif": "B12345678",
"tipoProveedor": "producto",
"plazoPago": 30,
"cuentaCliente": "C-4471",
"contactos": [
{ "nombre": "Ana Ruiz", "cargo": "Ventas", "email": "ana@norte.es" }
]
}Respuesta (201)
{
"success": true,
"data": {
"id": "64b0…0009",
"codigo": "PROV-004",
"nombre": "Distribuciones Norte",
"cif": "B12345678",
"tipoProveedor": "producto",
"plazoPago": 30,
"cuentaCliente": "C-4471",
"contactos": [
{ "nombre": "Ana Ruiz", "cargo": "Ventas",
"telefono": null, "email": "ana@norte.es", "notas": null }
],
"excluidoRecargoEquivalencia": false,
"activo": true,
"createdAt": "2026-09-19T08:00:00.000Z",
"updatedAt": "2026-09-19T08:00:00.000Z"
}
}Los datos bancarios no salen por la API
El IBAN y las cuentas bancarias del proveedor no se devuelven ni se aceptan, a propósito: si una clave se filtrara, no serviría para el fraude de cambio de cuenta, que es el más común con proveedores. Sí sale cuentaCliente, que es TU número de cliente en ese proveedor y con el que un ERP concilia sus compras.
El recargo de equivalencia es de solo lectura
El campo excluidoRecargoEquivalencia se devuelve y puedes reenviarlo con el mismo valor (para poder devolver el objeto entero), pero cambiarlo por API responde 400: decide si a tus compras a ese proveedor se les aplica el recargo, o sea que mueve la base imponible de tus facturas de compra. Se cambia desde la ficha del proveedor. Fuera de España no tiene ningún efecto.
El código de proveedor no localiza
A diferencia del de cliente, el código del proveedor (PROV-004) no es único: puede repetirse incluso dentro de tu propio taller. Por eso GET /proveedores/{id} solo acepta el id. Si tu ERP solo guarda el código, usa el filtro del listado: GET /proveedores?codigo=PROV-004, que devuelve todos los que casen y decides tú.
Fichas de reparación (solo lectura)
La API también deja consultar las fichas de reparación: número de ficha, estado, fechas, el aparato (tipo, marca, modelo, número de serie, IMEI) y el presupuesto. Es solo lectura: las fichas se siguen creando y cambiando de estado desde Sattotal, que es donde se firman el resguardo y la entrega. La clave necesita el recurso Reparaciones marcado; las claves de clientes o proveedores no llegan a ellas.
Campos de la ficha
Cada ficha trae numeroFicha, estado, prioridad, ubicacion, averiaDeclarada, diagnostico, las fechas del ciclo (entrada, inicio y fin del diagnóstico y de la reparación, aviso al cliente, entrega y ultimoCambioEstado, cuándo pasó a su estado actual), un resumen del cliente (id, codigo, codigoVisible, nombre, apellidos, razonSocial), el aparato (id, codigo, tipo, marca, modelo, numeroSerie, imei, color), el presupuesto (numero, total, estado, fechaEnvio y fechaRespuesta, o null si no tiene), el técnico asignado (solo su nombre) y plazoEntregaEstimado, el plazo que se le indicó al cliente en el resguardo. Nunca salen las notas internas, las firmas, las fotos, los documentos ni las contraseñas del aparato.
Petición
GET /api/v1/clientes/CLI-0042/reparaciones?estado=reparado Authorization: Bearer sat_Ab3k9…x9Zq
Respuesta (201)
{
"success": true,
"data": [{
"id": "64b0…0042",
"numeroFicha": "ORD-2026-0042",
"estado": "reparado",
"prioridad": "normal",
"averiaDeclarada": "No carga",
"diagnostico": "Conector de carga dañado",
"fechas": {
"entrada": "2026-09-20T09:00:00.000Z",
"finReparacion": "2026-09-22T17:30:00.000Z",
"entrega": null
},
"cliente": { "id": "64b0…0001", "codigoVisible": "801", "nombre": "Daniel" },
"dispositivo": {
"tipo": "movil", "marca": "Apple", "modelo": "iPhone 13",
"numeroSerie": "F2LXX0000", "imei": "356789012345678"
},
"presupuesto": { "numero": "PRES-2026-0010", "total": 89.9, "estado": "aprobado" },
"tecnico": { "nombre": "Andrei Popescu" },
"plazoEntregaEstimado": "3 días laborables"
}],
"pagination": { "total": 1, "page": 1, "limit": 25, "totalPages": 1 }
}Localizar al cliente por el teléfono que llama
Si tu CRM o tu centralita abre la ficha del cliente al entrar una llamada, usa GET /clientes?telefono=<número>. Busca en el teléfono principal y en el secundario e ignora cómo esté escrito: espacios, guiones, el prefijo internacional de tu país (+34 o 0034) y el 0 inicial. Así «612 345 678» encuentra a un cliente guardado como «+34 612-345-678». Hacen falta al menos 6 dígitos.
Resumen del cliente para tu CRM
GET /clientes/{id}/resumen devuelve en una sola llamada lo que suele enseñar un CRM en la ficha del cliente: totalReparaciones, reparacionesAbiertas (el aparato sigue en el taller), porEstado, totalPresupuestado y totalPresupuestosAprobados (en la moneda del taller, que llega en moneda), primeraReparacion, ultimaReparacion y ultimaActividad (el último cambio en cualquiera de sus fichas). Necesita el recurso Reparaciones, igual que las fichas.
Petición
GET /api/v1/clientes?telefono=0722 123 456
→ { "data": [{ "id": "64b0…0001", "codigoVisible": "801", "telefono": "+40 722 123 456", … }] }
GET /api/v1/clientes/801/resumen
{
"success": true,
"data": {
"cliente": { "id": "64b0…0001", "codigoVisible": "801" },
"moneda": "RON",
"totalReparaciones": 7,
"reparacionesAbiertas": 1,
"porEstado": { "entregado": 6, "en_reparacion": 1 },
"totalPresupuestosAprobados": 1240.5,
"ultimaReparacion": "2026-10-02T09:15:00.000Z",
"ultimaActividad": "2026-10-06T16:40:00.000Z",
…
}
}Sincronizar solo lo que ha cambiado
No hace falta traerse todo en cada pasada. Guarda en tu instrumento la fecha y hora de la última ejecución y pide únicamente los clientes o proveedores modificados desde entonces con el parámetro actualizadoDesde. La respuesta viene ordenada por fecha de modificación ascendente y con un desempate estable, así que puedes paginarla sin saltarte registros. Los archivados también aparecen (con activo = false), para que tu CRM pueda reflejar el archivo.
GET /api/v1/clientes?actualizadoDesde=2026-09-18T10:00:00Z&limit=100&page=1 Authorization: Bearer sat_Ab3k9…x9Zq
Primera pasada
Recorre GET /clientes con limit=100 y page=1, 2, 3… hasta que totalPages se agote. Guarda la hora de inicio.
Pasadas siguientes
Pide GET /clientes?actualizadoDesde=<hora guardada> y procesa solo lo que llegue. Vuelve a guardar la hora de inicio de esta pasada.
Enlaza, no dupliques
Guarda el id de Sattotal junto al registro de tu CRM. Si al crear recibes un 409 DUPLICADO, la respuesta trae existenteId: enlaza ese en vez de crear otro.
Paginación y búsqueda
Los listados aceptan page (desde 1) y limit (25 por defecto, 100 como máximo; si pides más se recorta a 100). El campo busqueda busca en nombre, apellidos, razón social, identificador fiscal, email, código y teléfono.
Códigos de error y qué hacer
Todas las respuestas de error llevan success: false, un texto orientativo y un code estable pensado para decidir por programa. Estos son los que puedes recibir:
NO_AUTORIZADOFalta la clave, tiene un formato que no es nuestro o no existe. Revisa la cabecera Authorization.
CLAVE_REVOCADALa clave era válida pero un administrador la revocó. Crea una nueva en Configuración → API y actualízala en tu herramienta.
PLAN_REQUERIDOLa organización está en el plan gratuito. La API vuelve a funcionar al cambiar a un plan de pago.
PERMISO_DENEGADOLa clave no tiene el permiso necesario para esa operación. La respuesta indica en ambitoRequerido cuál falta: crea una clave con ese permiso.
NO_ENCONTRADONo hay ningún cliente o proveedor con ese id en tu organización. Los de otras organizaciones nunca son visibles, y no se distingue «no existe» de «no es tuyo».
DUPLICADOYa existe un registro con ese dato: identificador fiscal o email en clientes; identificador fiscal, nombre o código en proveedores. La respuesta trae campo y existenteId para que puedas enlazarlo en vez de crear otro.
VALIDACIONAlgún campo no pasa la validación (o el JSON está mal formado). En details va el campo y el motivo, igual que en el formulario.
IDENTIFICADOR_FISCAL_REQUERIDOEse cliente necesita identificador fiscal: en tu país es obligatorio para el tipo de cliente enviado (por ejemplo, siempre para empresas).
RATE_LIMITDemasiadas peticiones. Espera los segundos que indique la cabecera Retry-After y reintenta.
API_DESACTIVADALa API está desactivada temporalmente por mantenimiento. Reintenta más tarde.
Límites
120 peticiones por minuto y clave (de sobra para una sincronización periódica; frena un bucle accidental). 10 claves activas por organización. Los listados devuelven como máximo 100 registros por página. Si la organización está en el plan gratuito con el cupo mensual agotado, el alta de clientes se corta igual que en la aplicación.
Paso a paso: sincronizar clientes con Make
Un escenario típico: cada 15 minutos, traer a tu CRM los clientes y proveedores nuevos o modificados en Sattotal. En n8n es equivalente con el nodo HTTP Request y un nodo Schedule.
Crea la clave en Sattotal
Configuración → API → Nueva clave, permiso «Solo lectura» si solo vas a leer, «Lectura y escritura» si también vas a crear clientes desde el CRM. Copia la clave.
Módulo HTTP «Make a request»
URL: tu URL base + /clientes. Método GET. Cabecera Authorization con valor Bearer y tu clave. Marca «Parse response» para trabajar con el JSON.
Prueba la conexión
Antes de nada, ejecuta una vez una petición a /me: si devuelve tu organización y el nombre de la clave, la autenticación está bien.
Añade el filtro incremental
Guarda la fecha de la última ejecución en un Data store o una variable y pásala como actualizadoDesde en la URL. Programa el escenario cada 15 minutos.
Mapea los campos hacia tu CRM
Itera data[] y mapea id, codigo, nombre, apellidos, email, telefono, nif_cif y direccion. Guarda el id de Sattotal en tu CRM para actualizar en vez de duplicar.
Para crear clientes desde el CRM, otro módulo HTTP con método POST a /clientes y el cuerpo JSON del cliente. Si recibes 409, usa existenteId para enlazar.
Buenas prácticas de seguridad
Una clave por integración
Así puedes revocar una sin romper las demás, y en la lista ves cuándo se usó cada una por última vez.
Nunca en el navegador ni en un repositorio público
Guárdala en el almacén de credenciales de tu herramienta (conexiones de Make, credenciales de n8n, variables de entorno). Si la subes a un repositorio o a una web, considérala filtrada.
Si se filtra, revoca y crea otra
La revocación es inmediata: la clave antigua empieza a recibir 401 CLAVE_REVOCADA. Actualiza la nueva en tu herramienta y listo.
Especificación API
La referencia técnica completa (rutas, parámetros, esquemas y códigos de error) está publicada en formato abierto en /api/v1/openapi.json, sin necesidad de clave. Sin más sale en español; añade ?lang= con tu idioma para tenerla traducida (por ejemplo /api/v1/openapi.json?lang=en o ?lang=ro). Puedes importarla en Postman, Insomnia, Make o n8n para tener todas las llamadas preparadas.
Preguntas frecuentes
He perdido la clave, ¿puedo volver a verla?
No. Solo se enseña al crearla y después se guarda de forma irreversible. Revócala en Configuración → API y crea otra.
¿Hay webhooks para que Sattotal avise a mi CRM cuando cambia algo?
Todavía no. La forma recomendada es consultar periódicamente con el parámetro actualizadoDesde, que solo devuelve lo que ha cambiado.
¿Qué datos expone la API?
Clientes y proveedores: listar, crear, consultar, actualizar y archivar. Los permisos son por recurso, así que una clave creada antes de que existieran los proveedores no accede a ellos hasta que un administrador se lo marque. Además, las fichas de reparación en solo lectura (estado, fechas, aparato y presupuesto), con su propio permiso.
¿Puedo borrar un cliente por API?
No, solo archivarlo (activo = false), igual que en la aplicación. Vale tanto para clientes como para proveedores. Un registro archivado sigue apareciendo en la sincronización para que tu CRM lo refleje.
¿La API está en el plan gratuito?
No. Está incluida en Basic, Pro y Enterprise y durante el periodo de prueba. En el plan gratuito puedes seguir viendo y revocando las claves que creaste.
Solo me llega el apellido del cliente, ¿por qué no se guarda el nombre?
Casi siempre es el mapeo de campos: el nombre de pila tiene que ir en nombre y el apellido en apellidos. Si tu herramienta manda el nombre con otra clave (firstName, name, apellido…), la API la descarta y te lo indica en avisos.camposIgnorados de la respuesta. Corrige el mapeo y vuelve a enviar el cliente con un PATCH.
¿Puedo encontrar al cliente con el número que me está llamando?
Sí. Pide GET /api/v1/clientes?telefono= con el número tal como te llega: da igual que traiga prefijo internacional, espacios o guiones, y busca también en el teléfono secundario. Con su id puedes pedir después sus fichas (/clientes/{id}/reparaciones) y su resumen (/clientes/{id}/resumen).
