# Webhook Trigger

> The Webhook trigger gives your workflow its own web address. When another system sends data there, the workflow starts with that data attached.

The Webhook trigger gives your workflow its own web address. When another system sends data to that address, the workflow starts, with the data attached to the run.

That is how you connect form builders, payment processors, source control and CRMs. Each event starts your workflow the moment it happens, instead of waiting for the next check.

A webhook delivery in four stages: a sender posts JSON to the trigger's URL, Glow answers immediately, the run starts, and the posted fields are addressed as {{ 1.field }} — with no wrapper.

## How it works

1. You add a Webhook trigger to your workflow.
2. Glow generates a **unique webhook URL** for that trigger.
3. You configure an external system to send HTTP POST requests to that URL.
4. Each time a request arrives, Glow starts a new run of the workflow with the request body available as step data.

  
    ### Adding a Webhook Trigger

    1. Open your workflow in the editor.
    2. Open **Tools** in the dock (Webhook sits under **Start**), or right-click the canvas.
    3. Select the **Webhook** trigger to add it to your workflow.

  

  
    ### The Webhook URL

    **The URL only exists once the workflow is Live.** In Draft the panel shows _"Switch workflow to Live mode to access your Webhook URL"_ and a **Go live** button. There is no address to copy until you press it. That is deliberate. A Draft workflow does not accept deliveries, so an endpoint would only mislead the system you gave it to.

    Once Live, the panel shows the URL under **Webhook endpoint**. Copy it into the external system (Typeform, Stripe, GitHub) that should send events to Glow.

    > **Tip:** The URL is unique to each trigger, and it survives unpublishing and republishing the workflow. You do not have to re-paste it every time you edit.
>
> Sometimes it needs to change, because it leaked or a partner should no longer be able to post to it. Use the **Generate a new URL** button beside it. The old address stops working immediately, so update the sender first. Deleting and re-adding the trigger also produces a new URL, but rotating in place is cleaner.

  

  
    ### Testing Your Webhook

    You usually want sample data on the trigger before you build the steps that follow it. Otherwise you are mapping fields you cannot see.

    **Without leaving Glow.** Open the trigger's **Test & Debug** tab, edit the **Testing data** to match the shape you expect, and click **Run step**. The **Executions** tab then shows the output, and downstream steps can reference it immediately. Nothing is sent over the network, so this works while the workflow is still in Draft.

    **With a real request.** To confirm the endpoint itself accepts traffic, send one:

    ```bash
    curl -X POST https://your-glow-webhook-url \
      -H "Content-Type: application/json" \
      -d '{"name": "Test User", "email": "test@example.com"}'
    ```

    Either way, the **Executions** tab is where you confirm what arrived.

  

## Reading what arrived

Whatever the other system sends (its payload) is read and handed to every step that follows. You reference its fields the same way you reference any other step's output.

For example, if your webhook receives:

```json
{
  "customer_name": "Acme Corp",
  "amount": 4500,
  "currency": "USD"
}
```

The posted JSON is the trigger's stored output, with nothing wrapped around it. Reference each field directly by the trigger's step number:

```
{{ 1.customer_name }}
{{ 1.amount }}
{{ 1.currency }}
```

There is no `body` level to go through: `{{ 1.body.customer_name }}` resolves only if the sender actually posted a `body` key.

**Use the data selector rather than typing the path.** Click the data icon beside any field and pick the value from the trigger's output. Glow inserts the correct reference. The exact shape depends on what the sender posted, and one look at the **Executions** tab after a real delivery settles it for good.

## Locking the URL to one sender

Webhook URLs are unguessable, but they are not authenticated by default. If your use case requires verifying that requests genuinely come from a trusted source, Glow supports **Shared Secret / Signature verification** on the trigger itself.

The trigger has two fields for this, both optional:

| Field                | What it does                                                                                                                                                                                                                                                                                                                                                |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Shared secret**    | Leave empty and any request to the URL is accepted. Set it and every delivery must be signed with it.                                                                                                                                                                                                                                                       |
| **Signature header** | The header that carries the signature: a coded fingerprint (an HMAC-SHA256 hash) of the request body, in hex or base64. The provider usually names it for you, for example `X-Hub-Signature-256`. Leave it empty and Glow looks for `x-doflo-signature`, which is almost never what a third-party provider sends: if you set a secret, name the header too. |

An unsigned or wrongly signed request is rejected before anything runs, so your workflow never sees it and no run is created. Use this with any provider that signs its payloads.

## Examples to copy

### A form submission

Point Typeform, Webflow or your own form at the trigger's URL. A form with a
name and an email field arrives as `{{ 1.name }}` and `{{ 1.email }}` — the
field names are whatever the form sends, at the top level, with no wrapper.

**What to do:** add the form's URL as its webhook destination, submit the form
once, then open the trigger's **Executions** tab and read the real field names
before you build against them. Insert them from the Workflow data panel rather
than typing them.

### A payment

Set the trigger's URL as your payment provider's webhook endpoint. A provider
usually nests its data, so the amount is more likely `{{ 1.data.object.amount }}`
than `{{ 1.amount }}`.

**What to do:** follow the trigger with a [Conditions](/build/action-steps/conditions)
step on the event type — providers send many kinds down one URL, and you rarely
want all of them. Send one real payment in test mode first, so the Executions
tab shows you the shape rather than the provider's documentation.

### A repository event

Point a repository's webhook at the URL and choose which events it sends. A
pull request arrives with its own fields, so the title is `{{ 1.pull_request.title }}`.

**What to do:** set the **Shared secret** and **Signature header** together —
GitHub signs with `X-Hub-Signature-256`, and without the header named, Glow
looks for one GitHub never sends.

## What to expect when it runs

### What format to send

**Send JSON.** Glow reads other formats where it can, but the field names only
map reliably from JSON. If the sender lets you choose, choose JSON and set its
content type to `application/json`.

### How big a delivery can be

A single delivery can carry up to **1 MB**. Anything larger is turned away
before a run is created, and the sender sees an error saying so.

That is generous for an event notification and tight for a document. If the sender can be configured to post a link to the data instead of the data itself, do that and fetch it in a later step.

### What the sender gets back

**Glow accepts the delivery immediately, before your workflow runs.** The sender
sees a success in its log — code `202` — and never waits on your automation, so
a slow workflow cannot time out at their end.

That success only says the request arrived. **It says nothing about whether the
run worked**, which is on the **Executions** tab.

A request to an unknown or rotated URL gets the same `202 {"received": true}`, and no run is created. That is deliberate: it stops anyone probing the endpoint to discover which URLs are real. A current URL whose workflow is back in Draft is different. The sender gets an explicit error saying the workflow is not published. If deliveries stop appearing in **Executions**, check the sender's log: a `202` means a stale URL, and the not-published error means the workflow needs to go Live again.

### Duplicate deliveries

Some systems send the same delivery again if they do not hear back quickly
enough, and **Glow starts a run for every request it receives** — so the same
event can be processed twice.

Where that matters, put a [Conditions](/build/action-steps/conditions) step
early on, testing an id the sender includes with each event, and stop the run
if you have seen it before.

## What's Next?

- Turn the incoming payload into addressable fields with [Parse JSON](/build/action-steps/parse-json).
- Run on a recurring clock instead of an external event with the [Scheduler Trigger](/build/triggers/scheduler).
