n8n Workflow Operations
n8n Instance
| Property | Value |
|---|
| URL | https://hab.so1.io |
| VPS | srv1140896.hstgr.cloud (72.61.201.142) |
| Health check | GET /healthz |
| API base | https://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
| Workflow | Check These Nodes |
|---|
FORGE (mSJmBzpIcuCKz1WT) | All HTTP Request nodes: GitHub credential FhglvXmXMeC2SQTl |
TOMMY (MasflGBKdowUZwpJ) | All HTTP Request nodes: GitHub credential tSg1ejqnd5r3clEg |
| TOMMY | SSH: 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:
| Workflow | Webhook | Method |
|---|
| FORGE | https://hab.so1.io/webhook/forge-resolve-next-ticket | POST |
| TOMMY | https://hab.so1.io/webhook/atomiser | POST |
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.