Skip to main content

n8n Workflow Operations

n8n Instance

PropertyValue
URLhttps://hab.so1.io
VPSsrv1140896.hstgr.cloud (72.61.201.142)
Health checkGET /healthz
API basehttps://hab.so1.io/api/v1/

API Key Usage

The Escaped Variable Problem

When using $N8N_API_KEY in shell commands, ensure the $ is not escaped:
# WRONG -- escaped dollar sign, variable not expanded:
curl -s -H "X-N8N-API-KEY: \$N8N_API_KEY" ...
# Result: sends literal "$N8N_API_KEY" string, gets empty/error response

# CORRECT -- variable expanded:
curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" ...
# Result: sends the actual JWT token

Setting the API Key

export N8N_API_KEY="eyJhbGciOiJIUzI1NiIs..."
Store it in your shell profile or a sourced env file. The BFF’s .env.local also contains this key.

Verifying API Access

# Check if the key works:
curl -sf -H "X-N8N-API-KEY: $N8N_API_KEY" \
  "https://hab.so1.io/api/v1/workflows?limit=1" | \
  python3 -c "import sys,json; d=json.load(sys.stdin); print(f'OK: {len(d.get(\"data\",[]))} workflows')"

Credential Safety

n8n API PUT operations silently detach all credentials. If you deploy or update a workflow via the API since the last manual save, credentials will be gone.

The Problem

When you PUT a workflow via the n8n REST API, n8n strips credential bindings from all nodes. The workflow will look correct in the UI, but HTTP Request nodes, SSH nodes, etc. will have no credential selected.

How to Detect

Open the workflow in hab.so1.io > click any HTTP Request or SSH node > check that the credential dropdown is not blank.

After Any API Deployment

WorkflowCheck These Nodes
FORGE (mSJmBzpIcuCKz1WT)All HTTP Request nodes: GitHub credential FhglvXmXMeC2SQTl
TOMMY (MasflGBKdowUZwpJ)All HTTP Request nodes: GitHub credential tSg1ejqnd5r3clEg
TOMMYSSH: Execute Task-let node: SSH credential bound

Prevention

Always save workflows via the n8n UI after API deployments. Or use the API only for reads, never for writes.

Workflow Verification

Quick Health Check

# n8n alive?
curl -sf https://hab.so1.io/healthz && echo "n8n alive" || echo "n8n down"

Verify Workflows Are Active

# FORGE
curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" \
  "https://hab.so1.io/api/v1/workflows/mSJmBzpIcuCKz1WT" | \
  python3 -c "import sys,json; w=json.load(sys.stdin); print(f'FORGE: {w[\"name\"]} -- active={w[\"active\"]}')"

# TOMMY
curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" \
  "https://hab.so1.io/api/v1/workflows/MasflGBKdowUZwpJ" | \
  python3 -c "import sys,json; w=json.load(sys.stdin); print(f'TOMMY: {w[\"name\"]} -- active={w[\"active\"]}')"

Check Recent Executions

# Last 5 FORGE executions:
curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" \
  "https://hab.so1.io/api/v1/executions?workflowId=mSJmBzpIcuCKz1WT&limit=5" | \
  python3 -c "
import sys, json
data = json.load(sys.stdin)['data']
for e in data:
    print(f'{e[\"id\"]} | {e[\"status\"]:10} | {e.get(\"startedAt\",\"?\")[:19]}')
"

Webhook Endpoints

These are public — no API key needed to trigger:
WorkflowWebhookMethod
FORGEhttps://hab.so1.io/webhook/forge-resolve-next-ticketPOST
TOMMYhttps://hab.so1.io/webhook/atomiserPOST

FORGE Payload

{
  "gh_org": "traceo-ai",
  "gh_repo": "traceo-mcp-server",
  "epic_issue_number": 22,
  "execution_mode": "manual"
}
Execution modes: manual (returns prompt, no execution), tommy (full autonomous run), api (returns JSON for external consumption).

TOMMY Payload

{
  "repo": "traceo-ai/traceo-mcp-server",
  "branch": "main",
  "dry_run": true,
  "project_path": "/root/projects/traceo-mcp-server",
  "ssh_host": "root@vps.devarno.cloud"
}

Timeout Recovery

If a webhook call times out but n8n continues executing:
# Find the running execution:
curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" \
  "https://hab.so1.io/api/v1/executions?workflowId=mSJmBzpIcuCKz1WT&status=running&limit=1" | \
  python3 -m json.tool

# Check status of a specific execution:
curl -s -H "X-N8N-API-KEY: $N8N_API_KEY" \
  "https://hab.so1.io/api/v1/executions/{EXEC_ID}" | \
  python3 -c "
import sys, json
e = json.load(sys.stdin)
print(f'Status:   {e[\"status\"]}')
print(f'Finished: {e.get(\"stoppedAt\", \"still running\")}')
"
If it errored at respondToWebhook — that’s expected (HTTP connection already closed). The upstream work still completed. Check GitHub issues manually.

Environment Variables

# Required for n8n API calls (monitoring, not triggering):
export N8N_API_KEY="your-n8n-api-key"

# Source: platform-tools/so1-control-plane-api/.env.local (GITHUB_TOKEN can also be found here)
Webhook triggers are unauthenticated — no env vars needed for triggering workflows.