Webhook Triggers
Execute workflows automatically when external systems send HTTP requests to a unique webhook URL. Perfect for integrating with third-party services, processing real-time events, and building event-driven automation.
Overview
Webhook triggers create a secure HTTP endpoint that external systems can call to start your workflow. When the webhook receives a request, it automatically creates a new workflow run with the request data as input.
Key Features:
Unique, secure webhook URL for each trigger
Multiple authentication methods (None, Basic, Bearer)
Configurable HTTP methods (GET, POST, PUT, DELETE)
Custom response codes
Immediate response with workflow run tracking
Full event history and logging
How Webhook Triggers Work
Execution Flow
External System → HTTP Request → Webhook URL → Trigger Validation →
→ Workflow Run Created → Immediate Response → Workflow ExecutesExternal system sends HTTP request to webhook URL
Platform validates authentication and HTTP method
Trigger creates new workflow run with request data
Immediate response returned with run ID and status
Workflow executes asynchronously in background
Event logged with full request/response details
Response Behavior
Webhooks use immediate response mode:
HTTP response returned within milliseconds
Response includes workflow run ID
Workflow continues executing asynchronously
External system doesn't wait for workflow completion
Example webhook response:
{
"workflow_run_id": "01HXXX123456789ABCDEF",
"workflow_run_status": "QUEUED"
}Understanding Webhook Input Data
CRITICAL CONCEPT: The webhook request body is passed directly as your workflow's input. Understanding how to configure your input schema and access webhook data is essential for successful integration.
How Webhook Data Becomes Workflow Input
When a webhook receives a request, the entire request body is automatically passed as the workflow's input data.
The flow:
External system sends JSON data to webhook URL
Platform receives the request body
Request body becomes workflow input
Fields defined in your input schema are accessible using
{{field_name}}
Configuring Workflow Input Schema for Webhooks
Your workflow's input schema defines what data the workflow expects. For webhook triggers, you must define each field you want to access in your workflow.
Supported field types:
string- Text datanumber- Numeric valuesboolean- True/false valuesarray- Lists of itemsobject- Nested objects (accepts any structure)
Important: Object Type Limitation
You must define each top-level field, but object fields accept any internal structure:
✅ You must list each field in
properties✅ You can specify a field is type
object❌ You cannot define the internal structure/properties of an
objectfield✅ All nested data within
objectfields is accessible via dot notation
Input Schema Examples
Example 1: Simple Fields
Webhook payload:
{
"customer_email": "[email protected]",
"order_id": "ORD-12345",
"amount": 99.99,
"premium": true
}Workflow input schema (you must define all fields):
{
"type": "object",
"properties": {
"customer_email": {
"type": "string",
"title": "Customer Email"
},
"order_id": {
"type": "string",
"title": "Order ID"
},
"amount": {
"type": "number",
"title": "Amount"
},
"premium": {
"type": "boolean",
"title": "Premium Customer"
}
}
}Access in workflow:
{{customer_email}} → "[email protected]"
{{order_id}} → "ORD-12345"
{{amount}} → 99.99
{{premium}} → trueExample 2: Object Fields (No Internal Schema Needed)
Webhook payload:
{
"order_id": "ORD-789",
"customer": {
"id": "cust_123",
"name": "Jane Smith",
"email": "[email protected]",
"address": {
"city": "New York",
"zip": "10001"
}
}
}Workflow input schema:
{
"type": "object",
"properties": {
"order_id": {
"type": "string",
"title": "Order ID"
},
"customer": {
"type": "object",
"title": "Customer Data"
}
}
}Key point:
We must define
customeras a field in propertiesWe specify
customeris typeobjectWe don't need to define its internal properties (
id,name,email,address)The system automatically accepts any structure inside the
customerobject
Access nested data with dot notation:
{{order_id}} → "ORD-789"
{{customer.id}} → "cust_123"
{{customer.name}} → "Jane Smith"
{{customer.email}} → "[email protected]"
{{customer.address.city}} → "New York"
{{customer.address.zip}} → "10001"Even though we didn't define id, name, email, or address in the schema, we can still access them because customer is type object!
Example 3: Array Fields
Webhook payload:
{
"order_id": "ORD-456",
"items": [
{"sku": "PROD-001", "quantity": 2, "price": 29.99},
{"sku": "PROD-002", "quantity": 1, "price": 49.99}
],
"tags": ["urgent", "vip", "international"]
}Workflow input schema:
{
"type": "object",
"properties": {
"order_id": {
"type": "string",
"title": "Order ID"
},
"items": {
"type": "array",
"title": "Order Items"
},
"tags": {
"type": "array",
"title": "Tags"
}
}
}Access in workflow:
{{order_id}} → "ORD-456"
{{items}} → Full array of objects
{{items[0].sku}} → "PROD-001"
{{items[0].quantity}} → 2
{{items[1].price}} → 49.99
{{tags}} → ["urgent", "vip", "international"]
{{tags[0]}} → "urgent"Strategy: Define Top-Level Fields You Need
Best Practice: Define each top-level field from the webhook payload that your workflow will access. Use type object for complex nested structures.
Example - Stripe webhook:
Webhook sends this payload:
{
"id": "evt_123",
"type": "charge.succeeded",
"data": {
"object": {
"id": "ch_456",
"amount": 5000,
"currency": "usd",
"customer": "cus_789",
"receipt_email": "[email protected]",
"metadata": {
"order_id": "ORD-12345",
"product": "Premium Plan"
}
}
},
"created": 1234567890,
"livemode": false
}Your workflow input schema (define what you'll use):
{
"type": "object",
"properties": {
"id": {
"type": "string",
"title": "Event ID"
},
"type": {
"type": "string",
"title": "Event Type"
},
"data": {
"type": "object",
"title": "Event Data"
}
}
}Even though we only defined id, type, and data (as object), you can still access all nested data:
{{type}} → "charge.succeeded"
{{data.object.amount}} → 5000
{{data.object.receipt_email}} → "[email protected]"
{{data.object.metadata.order_id}} → "ORD-12345"
{{data.object.metadata.product}} → "Premium Plan"The data field is defined as type object, so all its nested content is automatically accessible!
Accessing Webhook Data in Workflow Nodes
Once your input schema is configured, reference webhook data using parameter substitution syntax: {{field_name}}
Simple Fields
{{customer_email}}
{{order_id}}
{{amount}}
{{premium}}Nested Fields (Dot Notation)
{{customer.name}}
{{customer.email}}
{{customer.address.city}}
{{data.object.amount}}
{{metadata.order_id}}Array Elements
{{items[0].sku}}
{{items[1].price}}
{{tags[0]}}Use in Node Configurations
Email node example:
{
"to": "{{customer.email}}",
"subject": "Order {{order_id}} Confirmation",
"body": "Hello {{customer.name}}, your order total is ${{amount}}"
}API call node example:
{
"url": "https://api.example.com/orders",
"method": "POST",
"body": {
"order_id": "{{order_id}}",
"customer_email": "{{customer.email}}",
"total": "{{amount}}"
}
}Processing Complex Data with JavaScript
For complex transformations or accessing deeply nested data, use JavaScript nodes:
JavaScript node example:
// Access the full customer object
const customer = {{customer}};
// Extract specific fields
const fullName = customer.name;
const email = customer.email;
const city = customer.address.city;
// Process arrays
const items = {{items}};
const total = items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const productNames = items.map(item => item.sku).join(", ");
// Return processed data
return {
fullName,
email,
city,
total,
productNames,
itemCount: items.length
};Real-World Integration Examples
Example 1: Stripe Payment Webhook
Stripe payload structure:
{
"id": "evt_1ABC123",
"type": "charge.succeeded",
"data": {
"object": {
"id": "ch_3XYZ789",
"amount": 5000,
"currency": "usd",
"receipt_email": "[email protected]",
"metadata": {
"order_id": "ORD-12345"
}
}
}
}Your workflow input schema:
{
"type": "object",
"properties": {
"id": {
"type": "string",
"title": "Event ID"
},
"type": {
"type": "string",
"title": "Event Type"
},
"data": {
"type": "object",
"title": "Event Data"
}
}
}Workflow logic:
Node 1 - Validate event type:
const eventType = {{type}}; if (eventType !== "charge.succeeded") { throw new Error("Unsupported event type: " + eventType); }Node 2 - Send confirmation email:
To: {{data.object.receipt_email}} Subject: Payment Received - Order {{data.object.metadata.order_id}} Body: Thank you! We received your payment of ${{data.object.amount}}.Node 3 - Update database with order status:
Order ID: {{data.object.metadata.order_id}} Amount: {{data.object.amount}} Currency: {{data.object.currency}} Status: "paid"
Example 2: GitHub Pull Request Webhook
GitHub payload:
{
"action": "opened",
"number": 42,
"pull_request": {
"title": "Add new feature",
"user": {
"login": "developer123"
},
"head": {
"ref": "feature-branch",
"sha": "abc123"
},
"base": {
"ref": "main"
}
},
"repository": {
"full_name": "org/my-project"
}
}Your workflow input schema:
{
"type": "object",
"properties": {
"action": {
"type": "string",
"title": "Action"
},
"number": {
"type": "number",
"title": "PR Number"
},
"pull_request": {
"type": "object",
"title": "Pull Request Data"
},
"repository": {
"type": "object",
"title": "Repository"
}
}
}Access data in workflow:
{{action}} → "opened"
{{number}} → 42
{{pull_request.title}} → "Add new feature"
{{pull_request.user.login}} → "developer123"
{{pull_request.head.ref}} → "feature-branch"
{{pull_request.head.sha}} → "abc123"
{{repository.full_name}} → "org/my-project"Example workflow:
Node 1 - Post PR comment:
Message: "Thanks @{{pull_request.user.login}} for PR #{{number}}! Automated checks are running..."Node 2 - Notify team on Slack:
Channel: #pull-requests Message: "New PR in {{repository.full_name}}: {{pull_request.title}} Branch: {{pull_request.head.ref}} → {{pull_request.base.ref}}"
Example 3: Form Submission
Form payload:
{
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"company": "Acme Corp",
"message": "I'm interested in your services"
}Your workflow input schema:
{
"type": "object",
"properties": {
"first_name": {
"type": "string",
"title": "First Name"
},
"last_name": {
"type": "string",
"title": "Last Name"
},
"email": {
"type": "string",
"title": "Email"
},
"company": {
"type": "string",
"title": "Company"
},
"message": {
"type": "string",
"title": "Message"
}
}
}Use in workflow:
Full Name: {{first_name}} {{last_name}}
Email: {{email}}
Company: {{company}}
Inquiry: {{message}}Example workflow:
Node 1 - Send auto-reply:
To: {{email}} Subject: Thanks for contacting us, {{first_name}}! Body: We received your message and will get back to you soon.Node 2 - Create CRM lead:
Name: {{first_name}} {{last_name}} Email: {{email}} Company: {{company}} Source: "Website Contact Form"Node 3 - Notify sales team:
Channel: #new-leads Message: "New inquiry from {{first_name}} {{last_name}} at {{company}}"
Common Mistakes and Solutions
Mistake 1: Trying to Define Object Properties
Problem (❌ This doesn't work):
{
"type": "object",
"properties": {
"customer": {
"type": "object",
"properties": { // ❌ NOT supported!
"name": {"type": "string"},
"email": {"type": "string"}
}
}
}
}Solution (✅ Correct):
{
"type": "object",
"properties": {
"customer": {
"type": "object", // ✅ Just define as object
"title": "Customer Data"
}
}
}You can still access {{customer.name}} and {{customer.email}} - you just don't define them in the schema!
Mistake 2: Not Defining a Field at All
Problem:
// Webhook sends: {"order_id": "123", "customer": {...}}
// Input schema (missing customer field):
{
"type": "object",
"properties": {
"order_id": {
"type": "string"
}
// ❌ customer field not defined
}
}
// In workflow:
{{customer.name}} // ❌ Won't work - customer not definedSolution (✅ Define all top-level fields):
{
"type": "object",
"properties": {
"order_id": {
"type": "string"
},
"customer": {
"type": "object" // ✅ Now customer.name is accessible
}
}
}Mistake 3: Field Name Mismatch
Problem:
Webhook sends: {"customer_email": "[email protected]"}
Schema defines: {"user_email": {"type": "string"}}
Workflow uses: {{user_email}} // ❌ Returns undefinedSolution: Match field names exactly:
{
"type": "object",
"properties": {
"customer_email": { // ✅ Exact match
"type": "string",
"title": "Customer Email"
}
}
}Mistake 4: Case Sensitivity
Problem:
Webhook sends: {"CustomerEmail": "[email protected]"}
Schema defines: {"customeremail": {...}}
Workflow uses: {{customeremail}} // ❌ Case doesn't matchSolution: Field names are case-sensitive:
{
"type": "object",
"properties": {
"CustomerEmail": { // ✅ Match exact case
"type": "string"
}
}
}Use in workflow:
{{CustomerEmail}} ✅ Correct
{{customeremail}} ❌ Wrong caseMistake 5: Wrong Data Type
Problem:
Webhook sends: {"amount": "99.99"} (string)
Schema defines: {"amount": {"type": "number"}}
// May cause type mismatch issuesSolution: Match the actual type the webhook sends:
{
"type": "object",
"properties": {
"amount": {
"type": "string" // ✅ Match webhook's type
}
}
}Then convert in workflow if needed:
const amountNumber = parseFloat({{amount}});Testing Your Webhook Integration
Step 1: Identify Webhook Payload Structure
Before creating your input schema, understand what data the webhook will send:
Check third-party documentation (Stripe, GitHub, etc.)
Capture a test webhook using tools like:
webhook.site
RequestBin
ngrok
Note all top-level field names
Identify which fields are objects, arrays, or primitives
Step 2: Create Input Schema
Based on the payload structure, create your input schema:
{
"type": "object",
"properties": {
"field1": {"type": "string"},
"field2": {"type": "number"},
"field3": {"type": "object"}, // For nested data
"field4": {"type": "array"} // For lists
}
}Step 3: Send Test Request
curl -X POST https://api.agenticflow.com/webhook/{your-path-id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_token" \
-d '{
"field1": "test_value",
"field2": 123,
"field3": {
"nested": "data"
},
"field4": ["item1", "item2"]
}'Step 4: Check Trigger Event Log
Workflow → Triggers → Your webhook → Events tab
Find your test request
Inspect
request_bodyVerify all fields are present
Step 5: Verify Workflow Execution
Click
workflow_run_idfrom eventCheck workflow run "Input Data"
Confirm fields are accessible
Review node execution logs
Step 6: Add Debug Node
Add a JavaScript node to test field access:
console.log("field1:", {{field1}});
console.log("field2:", {{field2}});
console.log("field3.nested:", {{field3.nested}});
console.log("field4[0]:", {{field4[0]}});
return {
field1: {{field1}},
field2: {{field2}},
nested_value: {{field3.nested}},
first_item: {{field4[0]}}
};Creating a Webhook Trigger
Step 1: Navigate to Triggers
Open your workflow
Click "Triggers" tab
Click "Create Trigger"
Select "Webhook" type
Step 2: Configure Basic Settings
Name (required):
Example: "Stripe Payment Webhook"Description (optional):
Example: "Processes payment.succeeded events from Stripe"Step 3: Configure HTTP Settings
HTTP Method:
POST (recommended) - Data in request body
GET - Data in query parameters
PUT - Update operations
DELETE - Delete operations
Response Code:
200 - Standard success (default)
201 - Resource created
202 - Accepted for processing
204 - Success, no content
Response Mode:
Immediate - Returns response immediately with workflow run ID
Step 4: Configure Authentication
Bearer Token (Recommended for production):
{
"auth_type": "BEARER",
"token": "your_secret_token"
}Callers must include:
Authorization: Bearer your_secret_tokenBasic Authentication:
{
"auth_type": "BASIC",
"username": "user",
"password": "pass"
}Callers must include:
Authorization: Basic <base64(username:password)>No Authentication (Testing only):
{
"auth_type": "NONE"
}⚠️ Not recommended for production.
Step 5: Save and Get Webhook URL
Click "Create Trigger"
Copy generated webhook URL:
https://api.agenticflow.com/webhook/{unique-path-id}Configure URL in external system
Webhook is immediately active
Using Your Webhook
Making Requests
Basic POST request:
curl -X POST https://api.agenticflow.com/webhook/{path-id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_token" \
-d '{
"customer_email": "[email protected]",
"order_id": "ORD-123",
"amount": 99.99
}'Response:
{
"workflow_run_id": "01HXXX123456789ABCDEF",
"workflow_run_status": "QUEUED"
}Security Best Practices
Always use authentication in production (Bearer token recommended)
Use strong, random tokens (32+ characters minimum)
Rotate credentials regularly (every 90 days)
Monitor webhook events for suspicious activity
Validate input data in workflow nodes
Use HTTPS (enforced automatically)
Never commit tokens to version control
Managing Webhooks
Enable/Disable:
Active: Accepts requests, creates workflow runs
Inactive: Returns 404, doesn't execute
Update:
Change name, description
Update authentication credentials
Modify HTTP method or response code
Toggle active status
Delete:
Permanent action - cannot be undone
Webhook URL becomes invalid immediately
External systems will receive 404 errors
Webhook Events
Every webhook request is logged with complete details:
Event information:
Timestamp of request
HTTP method, URL, headers
Full request body
Response status code and body
Execution status (success/failed)
Workflow run ID (if created)
Error messages (if any)
View events: Workflow → Triggers → Select webhook → Events tab
Use event logs for:
Debugging integration issues
Monitoring webhook activity
Auditing workflow executions
Investigating failed requests
Troubleshooting
Field Returns Undefined
Check:
Is the field defined in input schema properties?
Does the field name match exactly (case-sensitive)?
Is the webhook actually sending that field?
Check trigger event logs to see actual payload received
Nested Data Not Accessible
Problem: Can't access {{customer.email}}
Check:
Is
customerdefined as typeobjectin schema?Are you using correct dot notation?
Did webhook actually send nested data?
Type Mismatch Errors
Solution: Ensure schema type matches what webhook sends:
If webhook sends
"123"(string), usetype: "string"If webhook sends
123(number), usetype: "number"Convert types in JavaScript node if needed
API Reference
Create Webhook Trigger
POST /workflows/{workflow_id}/triggers
Content-Type: application/json
Authorization: Bearer your_api_keyRequest:
{
"name": "My Webhook",
"description": "Webhook description",
"trigger_type": "webhook",
"trigger_config": {
"auth_config": {
"auth_type": "BEARER",
"token": "secret_token"
},
"method": "POST",
"response_code": 200,
"response_mode": "immediate"
}
}Response:
{
"id": "01HXXX123456789ABCDEF",
"workflow_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Webhook",
"trigger_config": {
"path": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"method": "POST",
"response_code": 200
},
"is_active": true,
"created_at": "2024-01-15T10:30:00Z"
}Related Documentation
Triggers Overview - All trigger types
Schedule Triggers - Time-based triggers
Workflow Inputs - Input configuration guide
Data Flow & Types - Working with data in workflows
Ready to integrate external systems? Create your first webhook trigger and configure your workflow inputs to match your webhook payload structure.
Last updated
Was this helpful?