n8n Workflow Integration
For No-Code Builders
🔗 Why n8n?
n8n is a powerful workflow automation tool (like Zapier, but self-hostable). It's perfect for building AI agents without writing backend code.
The Concept: n8n doesn't have a native "Amorce Node" yet, so we use a Code Node to verify signatures.
Step-by-Step Setup
Add Webhook Trigger
Create a new workflow and add a Webhook node as your trigger.
- • HTTP Method:
POST - • Path:
/webhook/amorce - • Authentication: None (we handle it in the next step)
Add Code Node (Verification)
Add a Code node immediately after the Webhook.
Copy-paste this code:
// Amorce Signature Verification (n8n Code Node)
// Install tweetnacl: npm install tweetnacl
const nacl = require('tweetnacl');
// Get headers and body from webhook
const headers = $input.item.headers;
const body = $input.item.body;
// Extract Amorce headers
const signature = headers['x-agent-signature'];
const agentId = headers['x-amorce-agent-id'];
const timestamp = headers['x-amorce-timestamp'];
if (!signature || !agentId || !timestamp) {
throw new Error('Missing Amorce headers');
}
// Check timestamp freshness (< 5 mins old)
const now = Math.floor(Date.now() / 1000);
const ts = parseInt(timestamp);
if (Math.abs(now - ts) > 300) {
throw new Error('Timestamp too old');
}
// Fetch public key from Trust Directory
const directoryUrl = 'https://directory.amorce.io';
const response = await fetch(`${directoryUrl}/agents/${agentId}`);
const agentData = await response.json();
const publicKeyPem = agentData.public_key;
// Convert PEM to Uint8Array (Ed25519 expects 32 bytes)
const publicKeyBase64 = publicKeyPem
.replace(/-----BEGIN PUBLIC KEY-----/, '')
.replace(/-----END PUBLIC KEY-----/, '')
.replace(/\s/g, '');
const publicKeyBytes = Buffer.from(publicKeyBase64, 'base64').slice(-32);
// Prepare message for verification
const message = JSON.stringify(body) + timestamp;
const messageBytes = Buffer.from(message, 'utf8');
const signatureBytes = Buffer.from(signature, 'base64');
// Verify signature
const isValid = nacl.sign.detached.verify(
messageBytes,
signatureBytes,
publicKeyBytes
);
if (!isValid) {
throw new Error('Invalid signature');
}
// If we get here, signature is valid!
return {
verified: true,
agent_id: agentId,
payload: body
};Add Your Business Logic
If verification passes, continue to your workflow:
- • Send Email (Gmail node)
- • Post to Slack (Slack node)
- • Update Database (MySQL/Postgres node)
- • Call External API (HTTP Request node)
Handle Errors
Add an Error Trigger node to catch verification failures:
// Error Handler Node
if ($input.item.error.message.includes('signature')) {
return {
status: 401,
message: 'Unauthorized: Invalid signature'
};
}
return {
status: 500,
message: 'Internal error'
};Visual Workflow
┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Webhook │ ───> │ Code Node │ ───> │ Business │
│ Trigger │ │ (Verify) │ │ Logic Nodes │
│ (POST) │ │ │ │ (Email, etc) │
└─────────────┘ └──────────────┘ └────────────────┘
│
│ (if error)
v
┌──────────────┐
│ Error Node │
│ Return 401 │
└──────────────┘⚠️ Important: Install Dependencies
For self-hosted n8n, install tweetnacl in your n8n container:
docker exec -it n8n npm install tweetnaclFor n8n Cloud, dependencies are auto-installed when you use require().
🎯 Use Case: AI Email Assistant
Example: An AI agent calls your n8n webhook with "send_email" intent. Your workflow verifies the signature, then sends the email via Gmail. No backend code required!