---
title: "Return your workflow's response to the webhook caller"
description: "Hold the caller's request until your Shopify Flow workflow replies, using the Sync Webhook Trigger and the Return Webhook Response action."
canonical: "https://docs.workflow-webhooks.app/synchronous-response"
---

# Synchronous response

Normally a webhook answers the caller immediately and your Shopify Flow workflow runs
in the background. With **Synchronous response** on, the app holds the caller's HTTP
request open until your workflow sends data back, and returns that instead.

Useful when the caller needs an answer, not just an acknowledgement - a form that shows
a result, a system that wants a computed value, a lookup.

> [!NOTE]
> Off by default on every webhook. Switching it on changes which Flow trigger fires -
> see below - so existing workflows for that webhook stop running until you rebuild them.

## Turn it on

**Advanced Settings -> Synchronous response** on the webhook.

## Build the workflow

A sync webhook fires the **Sync Webhook Trigger**, not the standard Webhook Trigger. That
trigger carries an extra field, `invocationId`, which identifies the individual request
waiting for an answer.

| Step | What |
| --- | --- |
| Trigger | **Sync Webhook Trigger** |
| Condition | `Webhook ID` equals your webhook's id |
| Last action | **Return Webhook Response** |

The action takes three fields:

| Field | What to put in |
| --- | --- |
| **Invocation ID** | Bind `{{invocationId}}` from the trigger. Without it your reply cannot be matched to the waiting caller and is discarded. |
| **Response body** | What the caller receives - see below. |
| **Content type** | Optional. Defaults to `application/json`; use `text/plain` for plain text. |

## Writing the response body

You can write the body directly in the field using the trigger's variables, which is all
most workflows need:

```text
{"ok": true, "orderId": "{{fieldOne}}", "email": "{{fieldTwo}}"}
```

Every trigger field is available: `{{fieldOne}}` to `{{fieldFour}}`, `{{rawBody}}`, and
`{{webhookId}}`.

For anything that needs logic - looking a customer up, computing a total, shaping a
larger object - use a **Run Code** action earlier in the workflow and bind its result
here instead.

> [!WARNING]
> **Always add the Webhook ID condition.** The Sync Webhook Trigger fires for *every*
> webhook on your store that has synchronous response on. Without a condition, one workflow
> answers all of them - so a caller of webhook B receives a response your workflow built for
> webhook A. With ordinary async webhooks a missing condition only causes extra runs; here it
> returns wrong data to real callers.

## When no answer arrives

If your workflow does not reply within **15 seconds**, the caller gets the ordinary
response instead - the same `200` a non-sync webhook returns. It is never an error and the
caller is never left hanging. The invocation still appears in History and the workflow may
still finish; only the reply is too late to use.

The usual causes:

- The workflow is not turned on.
- It is built on the standard **Webhook Trigger** rather than the Sync one.
- A branch finished without reaching **Return Webhook Response**.
- The **Invocation ID** was not bound.

## Things worth knowing

- **First reply wins.** If two workflows answer the same request, the caller gets the
  first; the second is discarded.
- **Duplicate deliveries never wait.** A request suppressed by
  [Duplicate delivery protection](https://docs.workflow-webhooks.app/duplicate-delivery.md) returns immediately - no workflow runs, so there is
  nothing to reply with.
- **Typical round trip is 2-4 seconds**, but Shopify publishes no timing guarantee for
  Flow. Treat synchronous responses as best-effort: fast in practice, with the 15-second
  fallback as the backstop.
