TriggersIncoming webhooks

Incoming webhooks

Copy page

Let an ERP, a form or any other system start a workflow with a POST request to a secret URL, and read its body, query and headers in your steps.

The trigger Incoming webhook gives a workflow its own secret URL. Another system, such as an ERP, a warehouse, a form tool or a script, sends a POST request to that URL, and the workflow starts with the request as its event.

Set it up

  1. Select the trigger, Change trigger, and pick Incoming webhook.
  2. Save the workflow. Until then the panel says Save the workflow to get its webhook URL.
  3. Copy the Webhook URL from the trigger panel. It is a secret URL on shopify.workflow-suite.app.
  4. The panel also shows an Example request you can copy and run from a terminal.
  5. Turn the workflow on. A workflow that is off answers with an error and starts nothing.

A workflow created from a template, duplicated or created over the API gets its own URL. A duplicate never shares the URL of the original.

The trigger panel of the Incoming webhook: a note that the event contains personal data, the Webhook URL with a copy button, and an Example request with a curl command; the secret part of the URL is hidden
The trigger panel shows the secret Webhook URL and a curl example you can copy. The secret part of the URL is hidden in this picture.

What the steps read

Variable Holds
event.payload.body The JSON body of the request
event.payload.query The query parameters of the URL
event.payload.headers A small set of request headers: content type, user agent, request id, x-event-type, x-event-id, x-signature and x-hub-signature-256

Example: the other system sends a SKU and a quantity.

{ "sku": "ABC-1", "quantity": 12 }

A later step reads them as:

{{ event.payload.body.sku }} and {{ event.payload.body.quantity }}

To test without the other system, paste a body like the one above into Event (JSON) in the Test panel, under body.

What the caller gets back

Answer Meaning
202 with started: true A run was started
202 with started: false Nothing started. reason is filtered (the trigger filter rejected it) or suppressed (loop protection or the plan limit stopped it)
401 The workflow asks for a signature, and the request has none or a wrong one. See the signature check below
404 The URL is not known
405 The request was not a POST
409 The workflow is turned off
413 The body is larger than 256 KB
429 More than 120 requests in a minute. Wait a minute and try again

The answer comes at once. It does not wait for the run and does not carry its result. The other system can look the run up over the Developer API. See Developer API and MCP.

Signature check (optional)

On top of the secret URL, a workflow can ask every request for a signature. The trigger panel has two optional fields:

  • Signing secret - the name of a secret from the Secrets page, for example WEBHOOK_SIGNING_SECRET. Enter the name, never the value. See Secrets.
  • Signature header - the request header that holds the signature. Empty means x-signature. GitHub sends x-hub-signature-256, Shopify x-shopify-hmac-sha256.

When a signing secret is set, a request starts the workflow only if that header holds the HMAC-SHA256 of the raw request body under that secret, written as hex, as sha256=<hex> or as base64. Any other request is answered with 401 and starts nothing. So is every request when the named secret does not exist: the check never falls open.

The signature covers the body exactly as it was sent, byte for byte. Sign the same bytes you send:

curl -X POST "$URL" -H "content-type: application/json" -H "x-signature: $(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')" -d "$BODY"

Without a signing secret the trigger works as before: the secret URL is the only protection.

Good to know

  • Use a trigger filter to ignore requests you do not want. Rejected requests start nothing and do not count against your plan. See Trigger filters.
  • End the workflow with a Fail the run step on the path where the data is wrong, for example when no variant has the SKU. The run then shows as Failed with your message, and you get the failure alert.
  • The webhook URL is never returned to a read-only API key.