Integration Guide

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

1

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)
2

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
};
3

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)
4

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 tweetnacl

For 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!