packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger.mdx
Webhook triggers allow external services to start your workflows by sending data to a unique URL. Use them to connect forms, third-party apps, and custom integrations.
| Use Case | Example |
|---|---|
| Web forms | Contact form submissions create leads |
| Third-party apps | Stripe payment → create customer record |
| Custom integrations | Your app → Twenty automation |
| No-code tools | Zapier, Make, n8n connections |
https://api.twenty.com/webhooks/workflow/abc123...
For POST requests, define the expected body structure:
{
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"company": "Acme Inc",
"message": "Interested in your product"
}
Now add actions that use the webhook data:
Example: Create a Person record
| Field | Value |
|---|---|
| First Name | {{trigger.body.firstName}} |
| Last Name | {{trigger.body.lastName}} |
{{trigger.body.email}} | |
| Company | Search or create based on {{trigger.body.company}} |
Before activating, test your webhook:
Using cURL:
curl -X POST https://api.twenty.com/webhooks/workflow/abc123... \
-H "Content-Type: application/json" \
-d '{"firstName":"Test","lastName":"User","email":"[email protected]"}'
Using Postman or similar:
application/jsonOnce tested, click Activate to make the workflow live.
If your webhook sends nested data:
{
"contact": {
"name": "John Doe",
"email": "[email protected]"
},
"source": "website"
}
Reference with: {{trigger.body.contact.email}}
If data includes arrays:
{
"items": [
{"name": "Product A", "qty": 2},
{"name": "Product B", "qty": 1}
]
}
How you handle arrays depends on your use case:
Unknown number of items → Use Iterator
If you need to process each item in the array (e.g., create a record for each), add a Code action to parse the array, then use Iterator:
export const main = async (params: { items: any }) => {
const items = typeof params.items === "string"
? JSON.parse(params.items)
: params.items;
return { items };
};
Then use Iterator to loop through: {{code.items}}
Known/specific fields → Extract to named fields
If the array contains specific fields you want to access individually (e.g., form answers where position 0 is always "first name", position 1 is always "last name"), add a Code action to extract them:
export const main = async (params: { items: any }) => {
const items = typeof params.items === "string"
? JSON.parse(params.items)
: params.items;
return {
product: {
name: items[0]?.name || "",
qty: items[0]?.qty || 0
}
};
};
Now you can select product.name and product.qty individually in subsequent steps.