10 KiB
Especificación y Contrato de API — Integraciones n8n y Claude
Esta documentación describe todos los endpoints disponibles en https://app.4ventures.es/api/integrations/... para la ingesta de métricas de Meta Ads, detección de fatiga, relevo creativo con Claude, aprobaciones y publicación.
1. Autenticación y Seguridad
Todas las peticiones a la API de integraciones deben incluir la cabecera X-Api-Key:
- Para n8n: Clave asignada en
N8N_API_KEY - Para Claude: Clave asignada en
CLAUDE_API_KEY
X-Api-Key: <TU_API_KEY>
Content-Type: application/json
Códigos de estado HTTP globales
200 OK: Petición procesada correctamente.400 Bad Request: Parámetros obligatorios faltantes o payload JSON malformado.401 Unauthorized: CabeceraX-Api-Keyausente o no válida.403 Forbidden: El cliente (client_id/tenant_id) no tiene activo el flagcreatives_enabled = true.404 Not Found: El cliente o recurso solicitado no existe.500 Internal Server Error: Error inesperado en el servidor.
2. Endpoints para n8n (Ingesta, Fatiga y Publicación)
2.1 Obtener Clientes Activos
Obtiene la lista de clientes que tienen activado el módulo de creatividades y su cuenta de anuncios de Meta.
- Método:
GET - Ruta:
/api/integrations/clients?creatives_enabled=true - Headers:
X-Api-Key: <N8N_API_KEY>
Respuesta de ejemplo (200 OK):
[
{
"id": "8bec977a-6032-4759-aa7f-b5042081f450",
"name": "Blue Parrot School",
"slug": "bps",
"meta_ad_account_id": "act_1052328112282270",
"slack_channel_id": null,
"drive_folder_id": null,
"creatives_enabled": true,
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"tenant_id": "8bec977a-6032-4759-aa7f-b5042081f450"
}
]
2.2 Ingesta Diaria de Métricas (Bulk Upsert)
Inserta o actualiza las métricas por anuncio y fecha. Si el anuncio (meta_ad_id) no existía en la base de datos, lo crea automáticamente en estado publicada.
- Método:
POST - Ruta:
/api/integrations/metrics/daily - Headers:
X-Api-Key: <N8N_API_KEY>,Content-Type: application/json
Payload de ejemplo (Request Body):
{
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"metrics": [
{
"meta_ad_id": "1202058493829102",
"date": "2026-10-11",
"campaign_name": "Matrículas Octubre 2026",
"impressions": 4200,
"reach": 3800,
"clicks": 135,
"spend": 54.20,
"results": 6,
"raw": {
"cpm": 12.90,
"ctr": 3.21
}
}
]
}
Respuesta de ejemplo (200 OK):
{
"ok": true,
"count": 1,
"rows": [
{
"id": "7e417520-6089-4cc8-9e44-f08b4e948b2a",
"meta_ad_id": "1202058493829102",
"date": "2026-10-11"
}
]
}
2.3 Obtener Candidatos de Fatiga
Devuelve las creatividades actualmente publicadas con sus métricas dentro de la ventana de análisis (lookback_days) y las reglas de fatiga del cliente.
- Método:
GET - Ruta:
/api/integrations/fatigue/candidates?client_id=8bec977a-6032-4759-aa7f-b5042081f450 - Headers:
X-Api-Key: <N8N_API_KEY>
Respuesta de ejemplo (200 OK):
{
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"tenant_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"lookback_days": 7,
"rules": {
"lookback_days": 7,
"min_impressions": 2000,
"max_frequency": 3.0,
"ctr_drop_pct": 30.0,
"cpa_rise_pct": 25.0,
"signals_required": 2,
"auto_request_relief": true
},
"candidates": [
{
"id": "c05d4143-f19d-421a-b8d9-9b03d6b0889a",
"meta_ad_id": "1202058493829102",
"format": "estatico",
"status": "publicada",
"metrics": [
{
"date": "2026-10-10",
"impressions": 3000,
"clicks": 90,
"spend": 45.0,
"results": 5
}
]
}
]
}
2.4 Marcar Creatividad Fatigada
Cambia el estado de la creatividad a fatigada, guarda el evento de auditoría y, si auto_request_relief está activo, crea automáticamente una petición de relevo en generation_requests.
- Método:
POST - Ruta:
/api/integrations/fatigue/mark - Headers:
X-Api-Key: <N8N_API_KEY>,Content-Type: application/json
Payload de ejemplo (Request Body):
{
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"creative_id": "c05d4143-f19d-421a-b8d9-9b03d6b0889a",
"signals": {
"ctr_drop_pct": 32.5,
"frequency": 3.4
}
}
Respuesta de ejemplo (200 OK):
{
"ok": true,
"creative_id": "c05d4143-f19d-421a-b8d9-9b03d6b0889a",
"status": "fatigada",
"signals": { "ctr_drop_pct": 32.5, "frequency": 3.4 },
"generation_request": {
"id": "377cf30e-81e5-4d80-8f4f-f30a8dd2d239",
"status": "pendiente",
"reason": "fatiga",
"brief": {
"client_slug": "bps",
"variants_requested": 2,
"avoid_angles": ["objecion_precio"],
"format": "estatico",
"aspect_ratio": "4:5"
}
}
}
2.5 Listar Creatividades Aprobadas para Publicar
Permite a n8n consultar las creatividades aprobadas pendientes de subirse a Meta Ads.
- Método:
GET - Ruta:
/api/integrations/creatives?status=aprobada&client_id=8bec977a-6032-4759-aa7f-b5042081f450 - Headers:
X-Api-Key: <N8N_API_KEY>
Respuesta de ejemplo (200 OK):
[
{
"id": "1800fa1e-e969-469c-9913-6c973acba346",
"headline": "Aprende a tu ritmo",
"primary_text": "Clases de 25 minutos adaptadas a tu agenda laboral con nativos.",
"cta": "Empezar gratis",
"asset_url": "https://storage.4ventures.es/creatives/bps_v1.jpg",
"status": "aprobada",
"format": "estatico"
}
]
2.6 Notificar Publicación de Anuncio en Meta
Tras crear el anuncio en Meta Ads, n8n actualiza la creatividad con su identificador oficial y la pasa a publicada.
- Método:
PATCH - Ruta:
/api/integrations/creatives/:id - Headers:
X-Api-Key: <N8N_API_KEY>,Content-Type: application/json
Payload de ejemplo (Request Body):
{
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"meta_ad_id": "1202059998123456",
"status": "publicada"
}
Respuesta de ejemplo (200 OK):
{
"id": "1800fa1e-e969-469c-9913-6c973acba346",
"meta_ad_id": "1202059998123456",
"status": "publicada",
"updated_at": "2026-10-12T11:47:10.455Z"
}
3. Endpoints para Claude (Generación de Relevo Creativo)
3.1 Obtener Contexto de la Creatividad Fatigada
Devuelve a Claude todos los datos necesarios para generar el relevo: el anuncio fatigado, sus métricas, las 3 mejores creatividades históricas del cliente y las reglas de fatiga.
- Método:
GET - Ruta:
/api/integrations/creatives/:id/context?client_id=8bec977a-6032-4759-aa7f-b5042081f450 - Headers:
X-Api-Key: <CLAUDE_API_KEY>
3.2 Crear Variantes Generadas
Inserta las variantes generadas por Claude. Nacen en estado borrador, con visibilidad agency y created_by = 'claude'.
- Método:
POST - Ruta:
/api/integrations/creatives - Headers:
X-Api-Key: <CLAUDE_API_KEY>,Content-Type: application/json
Payload de ejemplo:
{
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"generation_request_id": "377cf30e-81e5-4d80-8f4f-f30a8dd2d239",
"creatives": [
{
"format": "estatico",
"angle": "objecion_horarios",
"hook": "¿Sin tiempo para aprender inglés?",
"primary_text": "Clases de 25 minutos adaptadas a tu agenda.",
"headline": "Aprende a tu ritmo",
"cta": "Empezar gratis",
"asset_url": "https://storage.4ventures.es/creatives/bps_v1.jpg"
}
]
}
3.3 Completar Petición de Generación
Actualiza el estado de la tarea en la cola de Claude (completada o fallida), anotando los IDs generados y el coste estimado en tokens/créditos.
- Método:
PATCH - Ruta:
/api/integrations/generation-requests/:id - Headers:
X-Api-Key: <CLAUDE_API_KEY>,Content-Type: application/json
Payload de ejemplo:
{
"client_id": "8bec977a-6032-4759-aa7f-b5042081f450",
"status": "completada",
"result": {
"creatives": ["1800fa1e-e969-469c-9913-6c973acba346"],
"notes": "Variante enfocada en flexibilidad horaria",
"skills_used": ["cliente-blue-parrot", "formato-estatico-4-5"]
},
"cost_estimate": { "tokens": 8500, "credits": 1 }
}
4. Webhooks Salientes hacia n8n
La aplicación emite llamadas HTTP POST hacia la URL configurada en N8N_WEBHOOK_BASE (https://n8n-agencia.4ventures.es/webhook/creative-...).
Cada webhook se envía con la cabecera:
X-Signature: <hex_digest_hmac_sha256>
Eventos emitidos:
creative.approved: Un usuario cliente o de agencia aprueba la creatividad.creative.rejected: Un usuario rechaza la creatividad (requiere comentario obligatorio).creative.sent_to_client: La agencia envía la creatividad al cliente para su revisión.
5. Verificación de Firma HMAC en n8n (Nodo Code)
En el flujo de n8n que recibe el webhook (Webhook Node), agrega un nodo Code en modo Run Once for Each Item con el siguiente código JavaScript para verificar la autenticidad antes de procesar la petición:
const crypto = require('crypto');
// 1. Obtener la firma enviada en la cabecera
const signature = $input.item.headers['x-signature'];
if (!signature) {
throw new Error('Cabecera X-Signature no proporcionada en el Webhook');
}
// 2. Secreto compartido (obtenido de las credenciales de n8n o variables de entorno)
const sharedSecret = $env['N8N_WEBHOOK_SECRET'] || 'whsec_4v_7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d';
// 3. Obtener el cuerpo recibido (raw string exacto o serializado)
const bodyPayload = typeof $input.item.body === 'string'
? $input.item.body
: JSON.stringify($input.item.body);
// 4. Calcular el HMAC esperado
const expectedSignature = crypto
.createHmac('sha256', sharedSecret)
.update(bodyPayload)
.digest('hex');
// 5. Comparación segura
const isValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
if (!isValid) {
throw new Error('Firma HMAC no válida: webhook rechazado');
}
return {
json: {
verified: true,
event: $input.item.body.event,
data: $input.item.body.data
}
};