Files
Agente-Marketing/prisa-yachts/n8n_workflows_spec.md
T

9.9 KiB

n8n Workflows — Prisa Yachts LLC

Instancia: n8n.crewinghunters.com

Versión: 1.0 | 2026-05-04


RESUMEN DE WORKFLOWS

Workflow Trigger Qué hace
WF1: Content Buffer Publisher Cron 9AM / 12PM / 5PM ET diario Lee Google Sheet → publica en Instagram y Facebook automáticamente
WF2: LinkedIn Reminder Cron Lu/Mié/Vie 12PM ET Envía email con el texto del día listo para copiar en LinkedIn
WF3: Weekly Analytics Report Cron Domingo 7PM ET Jala métricas de Meta API → guarda en Sheet → envía resumen por email
WF4: Content Prep Reminder Cron Domingo 8AM ET Detecta posts sin imagen para la semana y alerta por email

VARIABLES DE ENTORNO (configurar en n8n antes de todo)

PRISA_META_PAGE_ACCESS_TOKEN=EAA...   # Long-lived Page Access Token (60 días)
PRISA_IG_USER_ID=17841400000000000    # Instagram Business Account ID (numérico)
PRISA_FB_PAGE_ID=100000000000000      # Facebook Page ID (numérico)
PRISA_CONTENT_SHEET_ID=1BxiMVs...    # ID del Google Sheet (del URL)
PRISA_CONTENT_SHEET_NAME=ContentCalendar
PRISA_NOTIFY_EMAIL=alro65@gmail.com

GOOGLE SHEETS — ESTRUCTURA

Tab 1: ContentCalendar

Col Header Tipo Valores permitidos
A post_id Texto PY-2026-001
B scheduled_date Fecha ISO 2026-05-06
C scheduled_time Hora 24h 11:00
D platform Texto fijo instagram / facebook / both
E caption_EN Texto largo Caption en inglés (max 2200 chars)
F caption_ES Texto largo Caption en español
G hashtags Texto #tag1 #tag2 #tag3
H image_url URL URL directa pública (ver nota crítica abajo)
I pillar Texto electrical / battery / education / safety / promo
J status Texto fijo draft / scheduled / publishing / published / failed / skipped
K published_at Datetime Lo escribe WF1 automáticamente
L ig_media_id Texto Lo escribe WF1 automáticamente
M fb_post_id Texto Lo escribe WF1 automáticamente
N error_message Texto Lo escribe WF1 si hay error
O linkedin_copy Texto largo Caption adaptado para LinkedIn (lo usa WF2)

Tab 2: Analytics

Columnas A-R: report_date, post_id, platform, published_date, pillar, métricas IG (impressions, reach, likes, comments, saved, shares), métricas FB, engagement rates. WF3 appenda filas aquí cada domingo.


WF1: CONTENT BUFFER PUBLISHER

Flujo completo

[Schedule Trigger: 9AM / 12PM / 5PM ET]
  → [Google Sheets: Read ALL rows de ContentCalendar]
  → [Code: Filter — status=scheduled AND fecha=hoy AND hora±30min]
  → ¿Hay filas? NO → [NoOp Exit] FIN
  → ¿Hay filas? SÍ → [Split In Batches: 1 por vez]
      → [Google Sheets: Update status="publishing"] ← lock anti-duplicado
      → [Switch por platform:]
          instagram → [Code: Build caption] → [HTTP: Create IG Container] → [Wait 10s] → [HTTP: Publish IG Container]
          facebook  → [Code: Build caption] → [HTTP: POST /photos a Facebook Page]
          both      → ambas ramas secuencial (IG primero, luego FB)
      → [SUCCESS] → [Google Sheets: Update status="published", published_at, ig_media_id, fb_post_id]
      → [FAILURE] → [Google Sheets: Update status="failed", error_message] → [Gmail: Notify alro65@gmail.com]

API Calls exactas

Instagram — Crear container:

POST https://graph.facebook.com/v21.0/{PRISA_IG_USER_ID}/media
  ?image_url={image_url}
  &caption={caption_EN}\n\n{caption_ES}\n\n{hashtags}
  &access_token={PRISA_META_PAGE_ACCESS_TOKEN}

Respuesta: { "id": "container_id" } → esperar 10s → publicar

Instagram — Publicar container:

POST https://graph.facebook.com/v21.0/{PRISA_IG_USER_ID}/media_publish
  ?creation_id={container_id}
  &access_token={PRISA_META_PAGE_ACCESS_TOKEN}

Respuesta: { "id": "published_media_id" } → guardar en columna L

Facebook — Post con imagen:

POST https://graph.facebook.com/v21.0/{PRISA_FB_PAGE_ID}/photos
  ?url={image_url}
  &message={caption_EN}\n\n{caption_ES}\n\n{hashtags}
  &access_token={PRISA_META_PAGE_ACCESS_TOKEN}

Respuesta: { "post_id": "...", "id": "..." } → guardar en columna M

Manejo de errores

Error Acción
Token expirado (code 190) Halt todo, email crítico a alro65@gmail.com
imagen_url inválida (code 100) Marcar fila failed, email, continuar con siguiente
Container no listo (code 9007) Retry 4x con delay 15s, luego failed
Rate limit (429) Retry 3x con delay 60s, luego failed
Sheet no accesible Halt todo, email crítico

Estados del row (ciclo completo)

draft → (operador promueve) → scheduled
scheduled → (WF1 bloquea) → publishing
publishing → (éxito) → published
publishing → (error) → failed
failed → (operador resetea) → scheduled

WF2: LINKEDIN REMINDER

[Schedule Trigger: Lun/Mié/Vie 12PM ET]
  → [Google Sheets: Read ContentCalendar]
  → [Code: Filter — fecha=hoy AND status=scheduled/published]
  → ¿Hay post? NO → [Gmail: "No hay post de LinkedIn hoy"]
  → ¿Hay post? SÍ → [Code: Build email — usar linkedin_copy si existe, sino caption_EN+ES]
      → [Gmail: Enviar a alro65@gmail.com con texto listo para copiar/pegar]

Formato del email:

Asunto: [Prisa Yachts] LinkedIn post listo — 2026-05-06

LinkedIn post de hoy:
---
[texto del post]
---

Instrucciones:
1. Ir a LinkedIn
2. Crear nuevo post
3. Copiar texto arriba
4. Subir imagen desde Google Drive
5. Publicar

WF3: WEEKLY ANALYTICS REPORT

[Schedule Trigger: Domingo 7PM ET]
  → [Google Sheets: Read ContentCalendar]
  → [Code: Filter — status=published AND published_at últimos 7 días]
  → ¿Posts? NO → [Gmail: "Sin publicaciones esta semana"]
  → ¿Posts? SÍ → [Split In Batches: 1 por vez]
      → [IF ig_media_id existe] → [HTTP GET /{ig_media_id}/insights?metric=impressions,reach,likes,comments,saved,shares]
      → [IF fb_post_id existe]  → [HTTP GET /{fb_post_id}/insights?metric=post_impressions,post_impressions_unique,...]
      → [Code: Calcular engagement rate = (likes+comments+saves+shares)/reach*100]
      → [Google Sheets: Append row a Analytics tab]
  → [Merge: Esperar todos los items]
  → [Code: Build reporte — ordenar por engagement desc, top post, tabla completa]
  → [Gmail: Enviar reporte a alro65@gmail.com]

Instagram insights endpoint:

GET https://graph.facebook.com/v21.0/{ig_media_id}/insights
  ?metric=impressions,reach,likes,comments,saved,shares
  &access_token={token}

WF4: CONTENT PREP REMINDER

[Schedule Trigger: Domingo 8AM ET]
  → [Google Sheets: Read ContentCalendar]
  → [Code: Filter — scheduled_date próximos 7 días AND status=scheduled/draft]
  → ¿Hay posts? NO → [Gmail: "Sin posts programados para la semana"]
  → ¿Hay posts? SÍ → [Code: Separar los que tienen image_url vs los que no]
      → [Code: Build email]
          SI hay faltantes → "ACTION REQUIRED: X posts sin imagen"
          SI todos tienen → "Todo listo para la semana"
      → [Gmail: Enviar a alro65@gmail.com]

GUÍA DE IMPLEMENTACIÓN — ORDEN DE PASOS

Paso 1: Credenciales en n8n

  1. Google Sheets OAuth2 — autorizar con la cuenta que tiene el Sheet
  2. Gmail OAuth2 — autorizar con alro65@gmail.com
  3. Meta API — Header Auth: Bearer {PRISA_META_PAGE_ACCESS_TOKEN}

Paso 2: Obtener los IDs de Meta

Page Access Token (long-lived):

1. developers.facebook.com → Graph API Explorer
2. Seleccionar App + Facebook Page
3. Pedir permisos: instagram_content_publish, pages_manage_posts, pages_read_engagement, instagram_manage_insights
4. GET /me/accounts → copiar access_token de tu página
5. Convertir a long-lived:
   GET https://graph.facebook.com/v21.0/oauth/access_token
     ?grant_type=fb_exchange_token
     &client_id={APP_ID}
     &client_secret={APP_SECRET}
     &fb_exchange_token={SHORT_TOKEN}

Instagram Business Account ID:

GET https://graph.facebook.com/v21.0/{PAGE_ID}
  ?fields=instagram_business_account
  &access_token={LONG_TOKEN}
→ respuesta: { "instagram_business_account": { "id": "ESTE_ES_EL_IG_USER_ID" } }

Paso 3: Crear el Google Sheet

  1. Crear spreadsheet con 2 tabs: ContentCalendar y Analytics
  2. Agregar headers exactos según tabla arriba
  3. Agregar fila de prueba con status=scheduled y fecha=mañana

Paso 4: Orden de construcción (de menor a mayor riesgo)

  1. WF4 primero — solo lectura, envía email → probar sin riesgo
  2. WF2 segundo — solo lectura + email → probar sin riesgo
  3. WF1 tercero — publicación real → probar con 1 fila de prueba primero
  4. WF3 último — requiere posts publicados con IDs reales para probar

⚠️ NOTA CRÍTICA: URLs DE IMÁGENES

Meta Graph API NO acepta links de Google Drive del tipo:

❌ https://drive.google.com/file/d/{ID}/view

Formato correcto (compartir como "Cualquiera con el link"):

✅ https://drive.google.com/uc?export=download&id={FILE_ID}

Para obtener el FILE_ID: en el link de compartir de Drive, el ID es el string alfanumérico largo.

Alternativa recomendada para producción: subir fotos a Google Cloud Storage con acceso público — URLs más estables y sin límites de descarga.


TOKEN REFRESH (importante)

El Page Access Token expira en 60 días. Antes de que expire:

  • Opción A: Agregar WF5 "Token Expiry Reminder" que envía email cada 30 días
  • Opción B (recomendada): Usar System User Token en Meta Business Manager — no expira nunca

PREGUNTAS A RESOLVER ANTES DEL PRIMER DEPLOY

  1. ¿Tienes Meta Developer App creada para Prisa Yachts?
  2. ¿Instagram está como cuenta Business vinculada a tu Facebook Page?
  3. ¿Las fotos irán a Google Drive o a otro storage?
  4. ¿Los posts serán bilingües (EN+ES en el mismo post) o separados?