Webhook trigger
Receive provider events on a webhook trigger, verify their signatures and map the event payload into the input of your workflow run.
A webhook trigger starts a run when an event reaches Loopfour over HTTP: from a provider your company has connected, or from any system that posts to your custom webhook URL. This page is about events coming in. To have Loopfour send run events to your own endpoint, see the Webhooks API.
Configuration
{
"trigger": {
"type": "webhook",
"path": "vendor-portal",
"provider": "stripe"
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
type | "webhook" | Yes | |
path | string | Yes | The match key for the custom route. Required by the schema even when provider is set |
provider | string | No | Match events that arrived from this provider, such as stripe |
events | string array | No | Accepted, but not used for matching. See Filter events |
verifySignature | boolean | No | Accepted, but not read. Each route decides how it verifies |
The webhook trigger has no Studio block. Set it in the definition through the API.
Inbound routes
These routes sit at the API host root, outside /api/v1, and do not take an API key.
| Route | Used for | Verification |
|---|---|---|
POST /webhooks/custom/:companyId/:path | Any system you control | None. The URL is the shared secret |
POST /webhooks/stripe | Stripe Connect events | When the request has a stripe-signature header and the platform's Stripe secret is set: HMAC-SHA256 over <timestamp>.<raw body>, within five minutes |
POST /webhooks/hubspot | HubSpot events for a connected portal | A Standard Webhooks signature (svix-id, svix-timestamp, svix-signature). Refused when no signing secret is configured |
POST /webhooks/airwallex | Airwallex events for a connected account | x-signature header: HMAC-SHA256 over <x-timestamp><raw body>, within five minutes |
POST /webhooks/nango | Events forwarded for Stripe, Salesforce, QuickBooks, PandaDoc, NetSuite, Slack and Gmail connections | HMAC-SHA256 of the raw body. Refused when the secret is missing or the signature is wrong |
Any other provider name on POST /webhooks/:provider returns 404 with { "error": "Unknown provider: <name>" }. A failed signature returns 401 with { "error": "Invalid signature" }.
The routes are limited per sending IP address to 10,000 requests a minute.
Which workflows start
An event starts every active workflow in the receiving company whose trigger matches:
- Custom route: the trigger's
pathequals the URL's:pathsegment. The comparison ignores case and treats.,-and_as the same, sobill.receivedmatchesbill-received. Do not startpathwith a slash. - Provider routes: the trigger's
providerequals the provider the event came from. Withoutprovider, a trigger whosepathequals the provider name also matches.
For HubSpot and Airwallex, the dedicated trigger types give event-level matching; see App event triggers.
Provider events are tied to a company through the connected account they name. A Stripe event with no account field, or for an account no company has connected, is answered { "received": true, "ignored": true } and starts nothing.
Run input
Each matched workflow gets a run with triggerType: "webhook" and this input:
{
"webhookEvent": {
"id": "a3f1c2d4-...",
"provider": "custom",
"eventType": "vendor-portal",
"payload": {
"billNumber": "B-2291",
"vendor": "Northwind Supplies",
"amount": 4180.5
}
}
}| Field | Meaning |
|---|---|
webhookEvent.id | Loopfour's id for the stored event |
webhookEvent.provider | custom, stripe, hubspot and so on |
webhookEvent.eventType | The custom :path, or the provider's event type |
webhookEvent.payload | The parsed JSON body. A body that is not JSON arrives as { "rawBody": "<text>" } |
Request headers are not passed to the run. Steps read the body with {{input.webhookEvent.payload.<path>}}.
Responses
The custom and Stripe routes answer:
{ "received": true, "eventId": "a3f1c2d4-...", "workflowsTriggered": 1 }POST /webhooks/hubspot and POST /webhooks/airwallex answer { "received": true, "count": 1 }, where count is the number of events in the delivery that matched a connected account.
The route answers after the runs are queued; it does not wait for them to finish.
Filter events
The events field is not applied. Every event that reaches a matching route starts the workflow. To narrow it:
- Subscribe only to the events you need in the provider's own webhook settings.
- Put a Condition step first and branch on
{{input.webhookEvent.eventType}}or a payload field.
Repeated events
Loopfour stores each event and its provider event id, but a redelivered event starts the workflow again. Make the workflow safe to repeat: look the record up before you create it, or use an action that updates a record by its number.
Test a webhook workflow
The custom route needs no signature:
curl -X POST https://workflow.loopfour.ai/webhooks/custom/$COMPANY_ID/vendor-portal \
-H "Content-Type: application/json" \
-d '{ "billNumber": "B-2291", "vendor": "Northwind Supplies", "amount": 4180.5 }'For a provider workflow, call POST /api/v1/workflows/:id/run with an input.webhookEvent object shaped like the one above. See API trigger.
Anyone who has a custom webhook URL can start the workflow. Share it only with the system that needs it, and check the payload in the first steps before the workflow writes to another system.
Loopfour