n8n-workflow

N8N Workflow Deployment

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "n8n-workflow" with this command: npx skills add funnelenvy/agents_webinar_demos/funnelenvy-agents-webinar-demos-n8n-workflow

N8N Workflow Deployment

Deploy workflows to N8N using the REST API.

Environment Variables

N8N_HOST="https://your-n8n-instance.com" # Or http://localhost:5678 N8N_API_KEY="your-api-key" # From N8N Settings > API

Quick Deploy

import os import json from urllib.request import Request, urlopen from urllib.error import HTTPError

def deploy_n8n_workflow(workflow: dict, activate: bool = False) -> dict: """ Deploy a workflow to N8N.

Args:
    workflow: Complete workflow JSON with nodes, connections, settings
    activate: Whether to activate the workflow after creation

Returns:
    dict with id, name, and URL of created workflow
"""
host = os.environ.get('N8N_HOST', 'http://localhost:5678')
api_key = os.environ.get('N8N_API_KEY')

if not api_key:
    raise ValueError("N8N_API_KEY environment variable not set")

# Ensure workflow has required fields
if 'name' not in workflow:
    workflow['name'] = 'Untitled Workflow'
if 'nodes' not in workflow:
    workflow['nodes'] = []
if 'connections' not in workflow:
    workflow['connections'] = {}
if 'settings' not in workflow:
    workflow['settings'] = {}

# Remove 'active' field if present - it's read-only on creation
workflow.pop('active', None)

url = f"{host.rstrip('/')}/api/v1/workflows"

request = Request(
    url,
    data=json.dumps(workflow).encode('utf-8'),
    headers={
        'Content-Type': 'application/json',
        'X-N8N-API-KEY': api_key
    },
    method='POST'
)

with urlopen(request, timeout=30) as response:
    result = json.loads(response.read().decode('utf-8'))

workflow_id = result.get('id')
workflow_url = f"{host}/workflow/{workflow_id}"

print(f"✅ Workflow deployed to N8N!")
print(f"   ID: {workflow_id}")
print(f"   Name: {result.get('name')}")
print(f"   URL: {workflow_url}")

# Activate if requested (requires separate PATCH call)
is_active = False
if activate:
    is_active = set_workflow_active(workflow_id, True).get('active', False)
    print(f"   Active: {is_active}")
else:
    print(f"   Active: False (not activated)")

return {
    'id': workflow_id,
    'name': result.get('name'),
    'active': is_active,
    'url': workflow_url
}

Activate/Deactivate Workflow

def set_workflow_active(workflow_id: str, active: bool = True) -> dict: """Activate or deactivate an existing workflow.""" host = os.environ.get('N8N_HOST', 'http://localhost:5678') api_key = os.environ.get('N8N_API_KEY')

url = f"{host.rstrip('/')}/api/v1/workflows/{workflow_id}"

request = Request(
    url,
    data=json.dumps({'active': active}).encode('utf-8'),
    headers={
        'Content-Type': 'application/json',
        'X-N8N-API-KEY': api_key
    },
    method='PATCH'
)

with urlopen(request, timeout=30) as response:
    result = json.loads(response.read().decode('utf-8'))

status = "activated" if active else "deactivated"
print(f"✅ Workflow {workflow_id} {status}")
return result

List Workflows

def list_n8n_workflows(active_only: bool = False) -> list: """List all workflows in N8N instance.""" host = os.environ.get('N8N_HOST', 'http://localhost:5678') api_key = os.environ.get('N8N_API_KEY')

url = f"{host.rstrip('/')}/api/v1/workflows"
if active_only:
    url += "?active=true"

request = Request(
    url,
    headers={
        'Content-Type': 'application/json',
        'X-N8N-API-KEY': api_key
    }
)

with urlopen(request, timeout=30) as response:
    result = json.loads(response.read().decode('utf-8'))

workflows = result.get('data', [])
print(f"Found {len(workflows)} workflows")
for wf in workflows:
    status = "🟢" if wf.get('active') else "⚪"
    print(f"  {status} [{wf['id']}] {wf['name']}")

return workflows

Example: Anomaly Detection Workflow

Build an anomaly detection workflow

anomaly_workflow = { "name": "Daily Anomaly Detection", "nodes": [ { "id": "schedule", "name": "Daily 9am", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1, "position": [250, 300], "parameters": { "rule": { "interval": [{"field": "hours", "hoursInterval": 24}] } } }, { "id": "bigquery", "name": "Query Metrics", "type": "n8n-nodes-base.googleBigQuery", "typeVersion": 2, "position": [450, 300], "parameters": { "operation": "executeQuery", "projectId": "={{ $env.BIGQUERY_PROJECT_ID }}", "sqlQuery": "SELECT date, registration_starts, paid_conversions FROM metrics WHERE date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)" } }, { "id": "code", "name": "Detect Anomalies", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [650, 300], "parameters": { "jsCode": ''' const data = $input.all(); const values = data.map(d => d.json.registration_starts); const mean = values.reduce((a,b) => a+b, 0) / values.length; const std = Math.sqrt(values.map(x => Math.pow(x - mean, 2)).reduce((a,b) => a+b, 0) / values.length);

const anomalies = data.filter(d => { const zscore = Math.abs((d.json.registration_starts - mean) / std); return zscore > 2; });

return anomalies.length > 0 ? anomalies : []; ''' } }, { "id": "if", "name": "Has Anomaly?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [850, 300], "parameters": { "conditions": { "number": [{ "value1": "={{ $json.length }}", "operation": "larger", "value2": 0 }] } } }, { "id": "slack", "name": "Send Alert", "type": "n8n-nodes-base.slack", "typeVersion": 2, "position": [1050, 250], "parameters": { "channel": "#alerts", "text": "🔴 Anomaly detected in registration_starts" } } ], "connections": { "Daily 9am": {"main": [[{"node": "Query Metrics", "type": "main", "index": 0}]]}, "Query Metrics": {"main": [[{"node": "Detect Anomalies", "type": "main", "index": 0}]]}, "Detect Anomalies": {"main": [[{"node": "Has Anomaly?", "type": "main", "index": 0}]]}, "Has Anomaly?": {"main": [[{"node": "Send Alert", "type": "main", "index": 0}], []]} }, "settings": { "executionOrder": "v1" } }

Deploy it

result = deploy_n8n_workflow(anomaly_workflow, activate=False) print(f"Workflow ready at: {result['url']}")

cURL Examples

Create Workflow

curl -X POST "$N8N_HOST/api/v1/workflows"
-H "Content-Type: application/json"
-H "X-N8N-API-KEY: $N8N_API_KEY"
-d @workflow.json

List Workflows

curl -X GET "$N8N_HOST/api/v1/workflows"
-H "X-N8N-API-KEY: $N8N_API_KEY"

Activate Workflow

curl -X PATCH "$N8N_HOST/api/v1/workflows/WORKFLOW_ID"
-H "Content-Type: application/json"
-H "X-N8N-API-KEY: $N8N_API_KEY"
-d '{"active": true}'

Error Handling

from urllib.error import HTTPError

try: result = deploy_n8n_workflow(workflow) except HTTPError as e: error_body = e.read().decode('utf-8') print(f"N8N API error: {e.code}") print(f" {error_body}") except ValueError as e: print(f"Configuration error: {e}")

Getting Your N8N API Key

  • Open your N8N instance

  • Go to Settings (gear icon)

  • Click API in the left menu

  • Click Create API Key

  • Copy the key and set it as N8N_API_KEY

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

bq-query-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

playwright-browser

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

hubspot-crm

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

gcp-bq-data-loading

No summary provided by upstream source.

Repository SourceNeeds Review