Automating n8n Workflows with Code: Programmatic Workflow Creation via API
n8n is powerful for visual automation. But building workflows programmatically
lets you create, clone, and manage them at scale.
n8n API Setup
# Enable API in n8n (self-hosted)
N8N_API_KEY=your-api-key
N8N_PUBLIC_API=true
// lib/n8n-client.ts
const N8N_BASE = process.env.N8N_URL || 'http://localhost:5678'
const N8N_API_KEY = process.env.N8N_API_KEY!
const n8nHeaders = {
'X-N8N-API-KEY': N8N_API_KEY,
'Content-Type': 'application/json',
}
export const n8n = {
async getWorkflows() {
const r = await fetch(`${N8N_BASE}/api/v1/workflows`, { headers: n8nHeaders })
return r.json()
},
async triggerWebhook(webhookPath: string, data: unknown) {
const r = await fetch(`${N8N_BASE}/webhook/${webhookPath}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
return r.json()
},
async createWorkflow(workflow: N8nWorkflow) {
const r = await fetch(`${N8N_BASE}/api/v1/workflows`, {
method: 'POST',
headers: n8nHeaders,
body: JSON.stringify(workflow),
})
return r.json()
},
}
Triggering Workflows
// Trigger a webhook-based workflow
async function notifyOnStripeEvent(event: Stripe.Event) {
await n8n.triggerWebhook('stripe-events', {
type: event.type,
customerId: event.data.object.customer,
amount: event.data.object.amount,
timestamp: event.created,
})
}
// After a new user signs up
async function onUserSignup(user: User) {
await n8n.triggerWebhook('new-user', {
userId: user.id,
email: user.email,
plan: user.plan,
source: user.referralSource,
})
}
Checking Execution Status
async function waitForExecution(executionId: string, timeoutMs = 30000) {
const start = Date.now()
while (Date.now() - start < timeoutMs) {
const r = await fetch(`${N8N_BASE}/api/v1/executions/${executionId}`, {
headers: n8nHeaders
})
const execution = await r.json()
if (execution.finished) {
return execution.status === 'success'
? { success: true, data: execution.data }
: { success: false, error: execution.data?.resultData?.error }
}
await new Promise(resolve => setTimeout(resolve, 500))
}
throw new Error(`Execution ${executionId} timed out`)
}
Useful n8n Webhook Patterns
// Error alerting from any script
async function alertError(script: string, error: Error) {
await fetch(`${N8N_BASE}/webhook/error-alert`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
script,
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
}),
}).catch(() => {}) // non-blocking
}
// Stripe product delivery
// On checkout.session.completed:
await fetch(`${N8N_BASE}/webhook/stripe-delivery`, {
method: 'POST',
body: JSON.stringify({
email: session.customer_email,
product: session.metadata.product,
downloadUrl: `https://github.com/Wh0FF24/${session.metadata.repo}`,
})
})
n8n as an Automation Hub
The pattern that works:
Your App (events)
| webhook calls
v
n8n (orchestration)
| connects to
v
Email / Slack / CRM / Sheets / Analytics
Your app stays clean — no direct integrations with 10 services.
n8n handles the routing and transformation.
Atlas uses n8n for Stripe delivery, error alerting, and CRM sync.
The Workflow Automator MCP connects Claude directly
to Make.com, Zapier, and n8n via natural language. $15/mo.
Top comments (0)