Skip to content
Expedify
7 min

Webhook trigger

Let another system start your workflow by posting to a URL. Where the URL comes from, how to read the payload, and how to find out what actually arrived.

The triggers so far have watched your data or listened for a person. This one waits for another system — a form tool, a payment provider, a partner's CRM — to send you something.

Expedify gives the workflow a URL. Anything that can make an HTTP request can start it.

A worked example

A partner posts a lead

The body of the request becomes a contact.

You do not type the URL — the product gives it to you

Five fields, and three of them are filled in for you.

webhook_id

What it holds
ID of the incoming webhook to use

webhook_slug

What it holds
Slug of the selected webhook

webhook_url

What it holds
URL of the selected webhook

http_method

What it holds
HTTP method filter One of: GET · POST · PUT · PATCH · DELETE Defaults to POST.

description

What it holds
Description of this trigger

Save first, then copy. webhook_id, webhook_slug and webhook_url are generated when the node is saved. The sequence is always: place the node, save the workflow, copy the URL out of the panel, paste it into the other system. Trying to fill them in yourself is the first thing people attempt and it is not how it works.

http_method defaults to POST, which is what nearly every sender uses. GET exists for systems that can only fetch a URL.

Reading what arrived

{{webhooktrigger_1.body}}

Holds
The parsed request body. What you want almost always.

{{webhooktrigger_1.headers}}

Holds
The request headers — where a sender's signature or API key lives.

{{webhooktrigger_1.params}}

Holds
Query-string parameters, for GET-style senders.

{{webhooktrigger_1.payload}}

Holds
The raw payload.

{{webhooktrigger_1.method}}

Holds
Which HTTP method was used.

So a request like this:

POST body
{
  "email": "priya@example.com",
  "first_name": "Priya",
  "utm": { "source": "partner-site" }
}
Reads as {{webhooktrigger_1.body.email}} and {{webhooktrigger_1.body.utm.source}}.

Nesting works the way it does everywhere else — dot your way in. The thing to get right is the body prefix: the payload is not at the top level of the trigger, and leaving it out is the most common broken reference on this node.

Finding out what the sender actually sends

Do not build against documentation. Build against a real request. Every sender's payload differs from what its docs imply — an extra wrapper object, a field that is a string where you expected a number, a name in snake_case instead of camelCase. Wire the trigger to a single node that records the whole body, fire one real request, and read what came in. Then build the rest.

The product keeps a log of incoming requests against the webhook, which is the other place to look when a workflow did not run: it tells you whether the request arrived at all — which separates “their problem” from “yours” in about ten seconds.

A URL that anyone could call

A webhook endpoint is reachable by anything that knows the address. Its secrecy is the protection, so treat the URL as a credential: do not paste it into a public issue, a shared document or a screenshot.

For senders that support it, the stronger option is verifying a signature — the sender signs each request and you check the header before trusting it. That belongs to the Webhooks path, along with regenerating a URL that has leaked.

Try it

  1. Add a Webhook trigger, save the workflow, and copy the URL out of the panel.
  2. Wire it to a single node that writes {{webhooktrigger_1.body}} into a note.
  3. Send it a request from any tool you like, then read the note. That is the real shape of the payload.
  4. Only now build the rest of the workflow — against what arrived, not against what you expected.

Next: Google Calendar — the same “another system has news” family, wearing an integration instead of a URL.

Related lessons