Skip to content

N8N Integration

N8N is used as the workflow orchestration engine for document processing, AI extraction, and embedding generation.

Architecture

mermaid
sequenceDiagram
    participant App as PIP AI Server
    participant N8N as N8N Workflow
    participant AI as OpenAI / LLM
    participant DB as Supabase DB
    participant Store as Supabase Storage

    App->>N8N: Webhook trigger (with secret)
    N8N->>Store: Download document (signed URL)
    N8N->>AI: OCR / Extract / Embed
    N8N->>DB: Upsert structured data
    N8N->>App: Callback (status + results)

Workflows

1. Spec Processing

Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-spec-upsert

Payload:

json
{
  "spec_upload_id": "uuid",
  "document_id": "uuid",
  "storage_path": "specs/brand/upload_id/file.pdf",
  "brand_name": "Holiday Inn Express",
  "area": "guest-room",
  "property_name": "San Francisco Airport",
  "job_id": "uuid"
}

Steps:

  1. Download spec PDF via signed URL
  2. OCR/LLM extraction → structured sections
  3. Upsert pip_ai_spec_sections with unique (spec_upload_id, spec_number)
  4. Generate embeddings via OpenAI text-embedding-3-small
  5. Update processing status
  6. Callback to app

2. PIP Processing

Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-pip-processor

Payload:

json
{
  "document_id": "uuid",
  "project_id": "uuid",
  "storage_path": "pips/project_id/doc_id/file.pdf",
  "job_id": "uuid",
  "callback_url": "https://app.example/api/pip/callback"
}

Steps:

  1. Resolve the Supabase project from the Supabase Projects data table by callback_url.extractDomain()
  2. Validate inbound x-webhook-secret against Supabase Projects.Webhook_Secret
  3. Download PIP PDF
  4. OCR/LLM extraction → structured line items
  5. Upsert pip_ai_pip_items with unique (document_id, code)
  6. For each item, query pip_ai_search_specs() (filtered by brand + areas)
  7. Upsert candidate matches into pip_ai_matches with unique (pip_item_id, spec_section_id)
  8. Update processing status
  9. Callback to app with x-webhook-secret and { document_id, project_id, job_id, status, items_count }

The PIP workflow resolves Supabase config from the Supabase Projects data table by callback_url.extractDomain(). The row must include Webhook_Secret, which must match the app-side N8N_WEBHOOK_SECRET. The workflow intentionally does not read $env.* in n8n.

3. Floor Plan Processing

Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-floor-plan-processor

Steps:

  1. Download floor plan
  2. Render to PNG + generate thumbnail
  3. OCR visible labels → extract spec codes
  4. Update pip_ai_floor_plans.extracted_spec_codes[]
  5. Link to known spec sections
  6. Callback to app

4. Submittal PDF Export

Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-submittal-exportWorkflow JSON: instructions/n8n-workflows/pip-ai-submittal-export.json

Payload:

json
{
  "job_id": "uuid",
  "project_id": "uuid",
  "format": "pdf",
  "storage_bucket": "pip-ai-docs",
  "storage_path": "exports/submittals/project_id/job_id.pdf",
  "callback_url": "https://app.example/api/submittal-export/callback"
}

Worker contract:

  1. Resolve the Supabase project from the Supabase Projects data table by callback_url.extractDomain()
  2. Validate x-webhook-secret against Supabase Projects.Webhook_Secret
  3. Load pip_ai_submittal_export_jobs by job_id through PIP AI - Supabase Router
  4. Read manifest_snapshot as the immutable export source
  5. Render the PDF through Supabase Projects.Gotenberg_URL and upload it to storage_bucket/storage_path
  6. Mark pip_ai_submittal_export_jobs as completed or failed through PIP AI - Supabase Router
  7. Call callback_url with x-webhook-secret as a best-effort notification

The Supabase Projects data-table row for the callback domain must include Domain, Supabase_URL, Webhook_Secret, and Gotenberg_URL. The workflow intentionally does not read $env.* in n8n. The direct Supabase Router update is the authoritative job state; callback delivery must not turn a successful storage upload into a failed export.

Callback payloads:

json
{
  "job_id": "uuid",
  "project_id": "uuid",
  "status": "completed",
  "storage_path": "exports/submittals/project_id/job_id.pdf"
}
json
{
  "job_id": "uuid",
  "project_id": "uuid",
  "status": "failed",
  "error": "Renderer failed"
}

The callback also accepts status: "processing" and normalizes legacy N8N status: "succeeded" to completed.

5. Legacy Document Builder PDF Export

Handles the original document builder PDF generation.

6. AI Image Generation (Nano Banana)

See Nano Banana integration.

Webhook Security

All webhooks use a shared secret for authentication:

Header: x-webhook-secret: <N8N_WEBHOOK_SECRET>

Use the same header in both directions: Nuxt server routes send it when triggering n8n workers, and n8n sends it back when calling Nuxt callbacks. Never expose N8N webhook URLs or secrets through NUXT_PUBLIC_* runtime config.

Job Queue Pattern

N8N can also poll the pip_ai_upload_jobs table:

sql
-- Claim a job
UPDATE pip_ai_upload_jobs
SET status = 'processing', locked_at = now(), locked_by = 'n8n-worker'
WHERE id = '<job_id>' AND status = 'queued'
RETURNING *;

Idempotency

All N8N workflows are designed to be safely re-runnable:

  • Upserts use unique constraints
  • Job status tracking prevents double-processing
  • retry_count tracks reprocessing attempts

Configuration

ini
N8N_BASE_URL=https://your-n8n-instance.com
N8N_WEBHOOK_SPEC_PROCESSOR=/webhook/pip-ai-spec-upsert
N8N_WEBHOOK_PIP_PROCESSOR=/webhook/pip-ai-pip-processor
N8N_WEBHOOK_FLOOR_PLAN_PROCESSOR=/webhook/pip-ai-floor-plan-processor
N8N_WEBHOOK_SUBMITTAL_EXPORT=/webhook/pip-ai-submittal-export
N8N_WEBHOOK_SECRET=your-shared-secret
SUPABASE_SERVICE_ROLE_KEY=server-only-service-role-key

These Nuxt variables are server-side only. The submittal export n8n workflow itself does not use $env.*; configure the matching secret in the n8n Supabase Projects data table.

Built with VitePress