Documentación de la API
Endpoints REST expuestos por n8n para el portal de gestión Yurest. Base URL: https://n8n-soporte.data.yurest.dev/webhook
Introducción
Esta API se expone vía workflows de n8n y persiste en Supabase (Postgres). Todos los endpoints comparten el prefijo:
https://n8n-soporte.data.yurest.dev/webhook
El frontend usa YurestConfig.apiFetch(url, opts) que automáticamente añade headers de autenticación y maneja sesiones expiradas (401/403 → redirige a login).
200 OK con un objeto JSON. Operaciones de escritura devuelven al menos { success: boolean } y, donde aplica, datos de diagnóstico (filas afectadas, errores específicos).
Autenticación
El portal usa Basic Auth almacenado en sessionStorage tras un login interno. El header se añade automáticamente vía YurestConfig.apiFetch():
Authorization: Basic <base64(usuario:contraseña)>
Content-Type: application/json
Si la sesión expira, cualquier endpoint responde 401 y el portal redirige al login.
Endpoints públicos (sin auth)
| Endpoint | Por qué es público |
|---|---|
responderSolicitud | El cliente lo invoca desde el email sin tener cuenta. |
completarFicha?t=<token> | Para precargar datos al rellenar la solicitud (validado por token aleatorio). |
Errores y diagnóstico
| Status | Significado | Cuándo |
|---|---|---|
200 | OK · revisa body.success | Casi todas las respuestas (incluso fallos lógicos vienen 200). |
401 / 403 | Sesión expirada | Frontend redirige a login.html. |
500 | Error interno del workflow | Excepción no controlada en n8n. |
eliminarFicha, grabadoA3) devuelven además { success, affected/ficha_count/sol_count, errores: [] } para detectar UPDATEs sin efecto (RLS bloqueando, ID inexistente, etc.).
CORS
Todos los endpoints aceptan peticiones desde cualquier origen y responden con los siguientes headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
📂 Auth y listado
Workflow 04-fichas-alta. Devuelve la lista completa de fichas. El portal lo usa también como verificador de sesión en el login.
Aliases en config.js
ENDPOINTS.login · ENDPOINTS.altas
Respuesta 200
{
"clientes": [
{
"id": "uuid",
"denominacion": "Test SL",
"cif": "B40597437",
"email": "contacto@test.es",
"tipo_cliente": "planes",
"estado": "rellenado | completada",
"grabado_a3": false,
"grabado_a3_at": null,
"fecha_solicitud": "2026-04-17T...",
"fecha_rellenado": "2026-04-17T...",
"fecha_completado": "2026-04-17T...",
"sepa_mandato": { ... },
"adjuntos": [ ... ],
"paquetes_carrito": { ... },
"deleted_at": null
// ... resto de columnas
}
]
}
Filtrado backend
El workflow excluye filas con deleted_at != NULL.
📋 Fichas
Workflow 04-fichas-alta. Crea una ficha nueva (sin id) o actualiza una existente (con id). En modo edición solo actualiza los campos enviados — no destruye los demás.
Body (todos opcionales en edición)
| Campo | Tipo | Notas |
|---|---|---|
id | uuid | Si presente → UPDATE; ausente → INSERT |
Nombre Sociedad | string | Mapea a denominacion |
CIF/NIF | string | Mapea a cif |
Email · Email Factura · Email CC | string | |
Tipo Cliente | string | lite · planes · corporate |
Estado | string | "rellenado" cuando comercial completa |
JP * · Firmante * · TPV * | strings | Bloques de datos |
Lite · Distribuidor | "Sí" / "" | Booleanos como string |
Adjuntos | array | PDF/JPG/PNG en base64 |
SEPA | object | Mandato firmado (datos + firma_base64) |
paquetes_carrito | object | Snapshot del carrito (módulos, precios, periodos) |
locales | array | Locales de la ficha (insertados aparte) |
Respuesta 200 (éxito)
{ "id": "uuid-de-la-ficha", "success": true }
Respuesta 200 (error en INSERT Locales)
{ "error": "..." }
El nodo INSERT Locales tiene continueOnFail: true, así que un fallo en locales no rompe el INSERT/UPDATE de la ficha principal pero sí aparece en el body.
Workflow 12-completar-ficha. Devuelve los datos de una ficha o solicitud para precargar el formulario. Acepta tres formas de identificación.
Query params
| Param | Tipo | Uso |
|---|---|---|
t | string (16-128 chars) | Token aleatorio público (preferente) |
id | uuid o número | UUID de ficha o ID-Solicitud numérico (uso interno) |
Respuesta 200 (encontrado)
{
"found": true,
"id": "uuid",
"ID Solicitud": 5,
"Nombre Sociedad": "Test SL",
"Email": "contacto@test.es",
"Tipo Cliente": "planes",
"SEPA": { "iban": "ES...", "deudor": {...}, "firma_base64": "..." },
// ... resto de campos
}
Respuesta 200 (no encontrado)
{ "found": false, "error": "Solicitud no encontrada" }
Workflow 10-eliminar. Soft-delete (UPDATE deleted_at = NOW()) en fichas_alta y solicitudes. Como los UUIDs son únicos entre tablas, sólo afecta a la que contiene el ID.
Body
{
"action": "delete",
"entity": "ficha" | "solicitud",
"id": "uuid",
"row_number": "uuid" // alias por compat
}
Respuesta 200
{
"success": true,
"entity": "ficha",
"id": "uuid",
"ficha_count": 1,
"sol_count": 0,
"errores": []
}
errores (problemas Supabase) o si ficha_count + sol_count == 0 → el id ya no existía.📨 Solicitudes
Workflow 08-solicitudes. Inserta solicitud en estado pendiente y envía email al cliente con la URL del formulario.
Body
{
"ID Solicitud": 5,
"access_token": "32-chars-uuid-sin-guiones",
"Nombre Sociedad": "Empresa SL",
"Nombre": "Ana García",
"Email": "ana@empresa.com",
"Comercial": "Pedro Martin",
"Tipo Cliente": "planes",
"Fecha": "2026-04-17",
"Estado": "Pendiente",
"email_to": "ana@empresa.com",
"email_subject": "Solicitud de creación de ficha de alta",
"email_body": "Hola Ana, te mando este formulario...",
"form_url": "https://.../solicitud.html?t=..."
}
Si access_token no viene, el workflow lo genera con crypto.randomUUID().
Respuesta 200
{ "id": "uuid", "success": true }
Workflow 08-solicitudes. Lista solicitudes que no estén en estado completado (las completadas se mueven a la pestaña "Rellenado cliente").
Respuesta 200
{
"solicitudes": [
{
"id": "uuid",
"access_token": "...",
"ID Solicitud": 5,
"Nombre Sociedad": "...",
"Email": "...",
"Estado": "pendiente",
"Fecha": "2026-04-17T..."
}
]
}
Workflow 09-rellenado-cliente. Lista solicitudes con estado=eq.completada (= clientes que ya rellenaron su parte y esperan que el comercial las complete).
Respuesta 200
{
"items": [{ "id": "uuid", "Nombre Sociedad": "...", "Email": "...", "Comercial": "..." }]
}
Workflow 11-auxiliares. El cliente envía sus datos desde solicitud.html. Crea la ficha, carpeta Drive, marca solicitud completada y dispara emails + tarea Asana si TPV no integrado.
Body (todos los datos del formulario)
{
"ID Solicitud": 5,
"access_token": "...",
"Estado": "Rellenado cliente",
"Nombre Sociedad": "...", "CIF/NIF": "...",
"JP Nombre": "...", "Firmante DNI": "...",
"TPV": "Revo",
"TPV No Integrado": "Sí", // si checkbox marcado
"TPV NI Nombre": "...", "TPV NI Contacto": "...", "TPV NI Email": "...",
"SEPA": {
"iban": "ES91...",
"swift": "CAIXESBB",
"deudor": { "nombre": "...", "direccion": "...", ... },
"tipo_pago": "recurrente",
"firma_base64": "data:image/png;base64,...",
"firmado_at": "2026-04-17T..."
}
}
Efectos
- INSERT en
fichas_altaconestado=completada+ SEPA persistido. - Crea carpeta en Google Drive y guarda
carpeta_driveen la ficha. - Email al cliente con enlace al Drive.
- Email al comercial avisando.
- UPDATE solicitudes:
estado=completado+ficha_id(dispara trigger que copiafecha_solicitud). - Si TPV no integrado: tarea en Asana (proyecto Integraciones
1207920061546505) + email a soporte/a.jareno/luis.
Respuesta 200
{ "success": true }
📒 Contabilidad
Workflow 13-grabado-a3. Toggle del flag grabado_a3 en una ficha. Trigger SQL setea grabado_a3_at al pasar de FALSE a TRUE.
Body
{ "id": "uuid", "grabado_a3": true | false }
Respuesta 200
{
"success": true,
"id": "uuid",
"grabado_a3": true,
"affected": 1,
"errores": []
}
📁 Proyectos
Workflow 01-proyectos-crud. CRUD de proyectos de implementación.
| Método | Body | Respuesta |
|---|---|---|
| GET | — | { proyectos: [...] } |
| POST | { proyecto: {...} } | { data: {...}, success: true } |
| PUT | { proyecto: { id, ...campos } } | id devuelto |
| DELETE | { id: "uuid" } | Soft-delete |
El POST/PUT acepta asanaProjectId y asanaProjectUrl para vincular un tablero Asana.
Workflow 02-proyectos-tareas. Actualiza una tarea/sección dentro de un proyecto (toggle completada, edición, etc.).
Body
{
"proyectoId": "uuid",
"seccionNombre": "Puesta en Marcha / Finalización",
"tarea": { "id": "...", "completada": true, ... }
}
Respuesta 200
{ "success": true }
Mueve una tarea entre secciones (drag & drop kanban).
Body
{ "proyectoId": "uuid", "tareaId": "...", "seccionOrigen": "...", "seccionDestino": "..." }
📉 Bajas
Workflow 05-bajas. Gestión de bajas de clientes (registro, edición de campos individuales y borrado).
| Endpoint | Operación |
|---|---|
bajas | GET listado |
bajaCliente · bajaLocal · bajaModulos · bajaEditar | POST campos específicos (mismo webhook con action) |
bajaBorrar | POST borra una baja |
📊 Distribución
Workflow 06-distribucion. Asigna un implementador a una ficha.
Body
{ "fichaId": "uuid", "implementador": "Carlos Aparicio" }
📁 Drive
Workflow 11-auxiliares. getDrive devuelve la URL de la carpeta Drive de una ficha; docsSubidos consulta si hay documentos subidos.
Query
?id=<ficha_uuid>
🔌 Integraciones externas (proxy)
Workflow 07-calendar-asana. Proxy a la API de Asana para evitar exponer credenciales en el frontend. Devuelve tareas de un proyecto o historias (comentarios) de una tarea.
Crea un evento en Google Calendar (sesiones de implementación).
Body
{ "summary": "...", "start": "ISO", "end": "ISO", "attendees": [...] }
Apéndice A · Tipos de datos
Objeto SEPA
{
"referencia": "YUREST-5",
"acreedor": {
"identificador": "ES##ZZZB40597437",
"nombre": "Yurest Solutions Sociedad Limitada",
"direccion": "Calle Transits, 6",
"cp": "46002", "poblacion": "Valencia", "provincia": "Valencia",
"pais": "España"
},
"deudor": {
"nombre": "...", "direccion": "...",
"cp": "...", "poblacion": "...", "provincia": "...", "pais": "..."
},
"swift": "CAIXESBB",
"iban": "ES9121000418450200051332",
"tipo_pago": "recurrente" | "unico",
"fecha_firma": "2026-04-17",
"localidad": "Valencia",
"firma_base64": "data:image/png;base64,...",
"firmado_at": "2026-04-17T14:33:33.152Z"
}
Objeto Adjunto
{
"id": "adj_xxx",
"nombre": "contrato.pdf",
"tipo": "application/pdf" | "image/png" | "image/jpeg",
"size": 12345,
"data": "data:application/pdf;base64,...",
"fecha": "2026-04-17T..."
}
Objeto paquetes_carrito
{
"items": [{ "id": "plan_pro", "precio": 1580 }],
"descuentos": { "cart": 0, "planes_setup": 0, "planes_recur": 0 },
"periodos": { "planes": "mensual" | "anual" },
"corp_module_locales": { "modulo_x": [0, 1] },
"locales_mensual": [25, 30]
}
Apéndice B · Tabla de estados
fichas_alta.estado
| Estado | Significado | Quién lo asigna |
|---|---|---|
pendiente | Inicial (poco usado) | — |
completada | Cliente rellenó su parte (workflow 11) | Cliente vía solicitud.html |
rellenado | Comercial completó la ficha (workflow 04) | Comercial vía index.html |
solicitudes.estado
| Estado | Significado |
|---|---|
pendiente | Esperando que el cliente la rellene |
completado | Cliente rellenó (genera ficha) |
fichas_alta ≠ "completado" en solicitudes. Los triggers SQL ya alinean fechas con esta semántica (fecha_rellenado, fecha_completado, grabado_a3_at) para que la analítica sea coherente.