WebhookTrigger NodeTypeCode: webhook-trigger
Start a workflow when an external system posts an HTTP request to a system-generated webhook URL. Supports HMAC-SHA256 payload verification, required-body enforcement, and field-level validation at the trigger boundary.
When to Use
- Payment processor callbacks: Stripe, PayPal, or Braintree posts a
payment.succeededorcharge.failedevent to your webhook URL. The workflow immediately captures the payload, validates the HMAC signature, and routes to fulfilment or refund processing nodes. - GitHub push and pull-request hooks: GitHub delivers a
pushevent on every commit tomain. The workflow extracts the repository, branch, and commit SHA, then triggers CI pipeline steps or deployment nodes downstream. - CRM lead notifications: HubSpot or Salesforce posts a lead-created event the moment a new contact is captured. The workflow enriches the record, assigns it to a sales rep based on territory, and sends a Slack notification to the team channel.
- IoT device events: Embedded sensors POST telemetry data at irregular intervals. The workflow stores readings, checks thresholds, and fires alerts when values exceed safe limits — all in real time without polling.
- Third-party SaaS integration events: Any SaaS tool that supports webhook delivery — Shopify order placement, Twilio inbound SMS status, PagerDuty incident creation — can drive a workflow without polling loops or scheduled pulls.
https://app.bizfirstai.com/webhooks/wf/{workflowId}/{instanceKey}. The URL is displayed in FlowStudio after the workflow is published. No manual endpoint registration is required on the BizFirstAI side.
Configuration
| Setting | Required | Description |
|---|---|---|
WebhookSecret |
Optional | A shared secret string used for HMAC-SHA256 signature verification. When set, every inbound request must include an X-Hub-Signature-256 header containing sha256=<hex>. Requests with a missing or invalid signature are rejected with HTTP 401 and routed to the error port. The secret is never exposed in FlowStudio logs. |
RequireBody |
Optional | Boolean, default false. When true, HTTP requests with an empty or missing body are rejected with HTTP 400 and routed to the error port. Prevents downstream nodes from receiving null input data. |
RequiredFields |
Optional | Comma-separated list of top-level field names that must be present in the request body (e.g. orderId,customerId,amount). If any listed field is absent or null, the request is routed to the error port with a descriptive validation message identifying the missing field. Supports top-level fields only — use a downstream DataMapping node for nested field validation. |
WebhookSecret and require your sending system to sign payloads with HMAC-SHA256. Stripe, GitHub, Shopify, and most modern SaaS providers support this natively with zero additional effort.
Output Ports
| Port | When It Fires |
|---|---|
main |
The inbound request passes all validation checks: signature is valid (or not required), body is present (if RequireBody is true), and all RequiredFields are present. The system returns HTTP 200 to the caller immediately and the workflow continues on this port. |
error |
Any validation failure: invalid HMAC signature, empty body when required, or one or more required fields are missing from the body. The error port receives a structured payload including error_code, error_message, and the raw request headers. |
Output Fields
On the main port, all InputData (the HTTP request body parsed as JSON) is passed through unchanged. The trigger node appends these system fields:
| Field | Type | Description |
|---|---|---|
__webhook_received_at | string | ISO 8601 UTC timestamp of when the request was received by the platform. |
__webhook_instance_key | string | The instance key component of the webhook URL — useful for correlation and idempotency checks. |
__webhook_method | string | HTTP method of the inbound request (POST, PUT, etc.). |
__webhook_headers | object | All HTTP request headers as key-value pairs, normalized to lowercase keys. |
Sample Configuration
{
"nodeType": "webhook-trigger",
"settings": {
"WebhookSecret": "whsec_a7b3c9d2e5f1234567890abcdef",
"RequireBody": true,
"RequiredFields": "event,data.orderId,data.customerId"
}
}
id field, GitHub's X-GitHub-Delivery header) immediately after the trigger and store it with a VariableAssignment node. Use this ID as an idempotency key in your database write nodes to safely handle webhook retries without duplicate processing.
Sample Output
Success Port
{
"headers": {
"content-type": "application/json",
"x-webhook-source": "shopify",
"x-shopify-hmac-sha256": "abc123...",
"user-agent": "Shopify-Webhooks/1.0"
},
"body": {
"id": 820982911946154508,
"email": "jon@example.com",
"total_price": "409.94",
"currency": "USD",
"fulfillment_status": null,
"line_items": [
{ "id": 866550311766439020, "title": "IPod Nano - 8gb", "quantity": 1, "price": "199.00" }
]
},
"queryParams": {
"source": "shopify",
"event": "orders/create"
},
"method": "POST",
"path": "/webhooks/trigger/wf_order_created",
"receivedAt": "2025-03-15T12:30:00.000Z",
"requestId": "req_abc123xyz"
}
Expression Reference
After the WebhookTrigger fires, downstream nodes reference the payload using the node's output name as set in FlowStudio (shown here as webhookTrigger).
| Expression | Value |
|---|---|
{{ $output.webhookTrigger.event }} | The event field from the posted JSON body. |
{{ $output.webhookTrigger.data.orderId }} | Nested field access using dot notation. |
{{ $output.webhookTrigger.__webhook_received_at }} | ISO timestamp of when the webhook arrived at the platform. |
{{ $output.webhookTrigger.__webhook_headers['x-stripe-signature'] }} | Access a specific request header by name (lowercase). |
{{ $output.webhookTrigger.__webhook_instance_key }} | Instance key for deduplication or correlation audit logs. |
Node Policies & GuardRails
| Policy | Rationale |
|---|---|
Always configure WebhookSecret in production | Unsigned webhooks can be spoofed by any caller on the internet. HMAC-SHA256 verification ensures only your trusted sender can trigger the workflow. |
Validate at the trigger boundary with RequiredFields | Catching missing fields at the entry point prevents downstream nodes from receiving incomplete data and producing silent failures deep in the workflow. |
| HTTP 200 is returned immediately on acceptance | The platform returns 200 as soon as the request passes validation. This prevents retry storms from senders that interpret slow responses as failures. All workflow steps run asynchronously afterward. |
| Log the raw payload during integration testing | Connect a CodeExecute or VariableAssignment node immediately after the trigger to capture __webhook_headers and the body to a debug log during initial integration. Remove or gate behind a feature flag before production. |
Always handle the error port | Connect the error port to a Slack or Email notification node so your team is alerted when unauthorized or malformed requests arrive. This often signals a misconfiguration on the sending system. |
Use __webhook_instance_key as an idempotency key | Store processed instance keys in a cache or database table on arrival and check before processing. This safely handles duplicate webhook deliveries from retry-happy senders. |
Pattern Examples
Pattern 1 — Stripe Payment Webhook with Signature Verification
Stripe posts payment_intent.succeeded events signed with HMAC-SHA256. The workflow verifies the signature, normalizes the payload to an internal schema, and routes to fulfilment.
// WebhookTrigger settings
{
"WebhookSecret": "whsec_your_stripe_webhook_signing_secret",
"RequireBody": true,
"RequiredFields": "type,data.object.id,data.object.amount,data.object.currency"
}
// Downstream VariableAssignment — capture idempotency key
{
"VariableName": "stripeEventId",
"Value": "{{ $output.webhookTrigger.id }}"
}
// Downstream DataMapping — normalize to internal order payment schema
{
"Mappings": [
{ "SourceField": "data.object.id", "TargetField": "paymentIntentId" },
{ "SourceField": "data.object.amount", "TargetField": "amountCents", "Transform": "toInt" },
{ "SourceField": "data.object.currency", "TargetField": "currency", "Transform": "uppercase" },
{ "SourceField": "data.object.metadata.orderId", "TargetField": "internalOrderId" }
]
}
Pattern 2 — GitHub Push Hook for Deployment Trigger
GitHub delivers a push event on every commit. The workflow filters for main-branch pushes, captures the commit SHA, and initiates a deployment pipeline.
// WebhookTrigger settings
{
"WebhookSecret": "github_webhook_secret_abc123",
"RequireBody": true,
"RequiredFields": "ref,repository.full_name,head_commit.id"
}
// Downstream IfCondition — only process commits to main branch
// Condition expression:
"{{ $output.webhookTrigger.ref }}" === "refs/heads/main"
// Downstream VariableAssignment — store commit SHA for deployment
{
"VariableName": "deployCommitSha",
"Value": "{{ $output.webhookTrigger.head_commit.id }}"
}
Pattern 3 — IoT Sensor Alert with Field Validation
Edge devices POST temperature and humidity readings. Validation ensures required fields are present. A downstream CodeExecute node checks thresholds and routes an alert if readings are out of range.
// WebhookTrigger settings (no secret — internal network, IP-restricted)
{
"RequireBody": true,
"RequiredFields": "deviceId,temperature,humidity,timestamp"
}
// Downstream CodeExecute — threshold check
var data = input;
var alert = false;
var reason = "";
if (data.temperature > 85) {
alert = true;
reason = "Temperature exceeded 85C on device " + data.deviceId;
}
if (data.humidity > 95) {
alert = true;
reason = reason + " Humidity exceeded 95% threshold.";
}
result = { alert: alert, reason: reason.trim(), deviceId: data.deviceId };