Integrations
Shopify
Installing the app, choosing events, and wiring the back-in-stock form into your theme.
The Shopify app subscribes to your store's order and fulfilment webhooks and maps them onto the same 18 events the rest of the platform uses. It runs embedded in your Shopify admin and calls the public API with your own key. It has no privileged access to the platform, and it never writes to your store except for the one case noted under scopes.
Install the app
The app is installed as a custom app you create in your own Shopify Partner account, so the credentials and the hosting are yours. Shopify requires a public HTTPS origin, plain http is refused for both OAuth redirects and webhook addresses.
Create the app
partners.shopify.com → Apps → Create app → Create app manually. Name it, then open Configuration.Set the URLs
App URL ishttps://<your-host>/, andhttps://<your-host>/auth/callbackgoes under Allowed redirection URL(s). AnOauth error invalid_requeston install means these two do not match exactly, including the scheme and any trailing slash.Leave the app embedded
The admin UI is built for the embedded frame and gets its session tokens from App Bridge. Opened standalone it cannot authenticate, and every call returns 401.Copy the credentials
Client ID and Client secret from the API credentials panel becomeSHOPIFY_API_KEYandSHOPIFY_API_SECRETin the app's environment. The secret signs both webhook HMACs and session tokens, so rotating it invalidates every open admin session and every in-flight webhook signature at once, do it during a quiet window.Install it on the store
Partner dashboard → your app → Test your app → select the store, then approve the scope list. You land on the app's Setup tab inside the Shopify admin.
Scopes
Declare the same list in the Partner dashboard, in shopify.app.toml under [access_scopes], and in SHOPIFY_SCOPES. Shopify grants what the configuration says, so a mismatch is not an install error, it surfaces later as a 403 on the first Admin API call that needs the missing scope.
read_orders,write_orders,read_fulfillments,read_customers,read_checkouts,read_products,read_inventory- read_orders
- Order created, updated, cancelled, paid and refunded, most of the events.
- read_fulfillments
- Tracking numbers and shipment status transitions.
- read_customers
- The customer's phone number, and the welcome message on account creation.
- read_checkouts
- Abandoned-cart recovery.
- read_products
- Product name and link for back-in-stock alerts.
- read_inventory
- Variant stock levels, so a back-in-stock alert fires on the transition rather than on every product edit.
- write_orders
- Cash on delivery only. When a customer taps Cancel order the app calls Shopify's cancel endpoint, and either decision tags the order so you can see it in the admin. Without this scope the COD flow answers 403 the moment a customer replies, and because that failure is logged rather than surfaced the symptom is orders that never move.
Connect your WhatsApp account
Paste your platform API key
Open the Setup tab. Generate a key in the platform dashboard under API Keys. It starts withsk_live_, and paste it into Platform API key, then Save connection.Choose the number you send from
Saving the key fills the Send from dropdown fromGET /v1/phones. Pick a number and save again. A quality rating next to a number is Meta's, not the app's; a Red number may have its daily reach cut.
Turn on the notifications
The Notifications tab has a card per event, grouped by Orders, Shipping, Payments & Returns and so on. Use Submit all for approval. There is no cost to having a template approved that you never switch on, then Refresh approval status until the badges change.
- Not created
- Not submitted yet.
- Pending
- Meta is reviewing it. Nothing to do but wait.
- Approved
- Ready to send.
- Rejected
- Meta declined it. The reason is shown on the card.
Rejections cluster on the three marketing events, Cart Recovery, Review Request and Back in Stock. Meta holds marketing to a higher standard and looks for evidence that customers agreed to receive it. The order-related templates are rarely refused, and you can go live on Order Confirmation alone while the rest are still in review.
Each card carries three things worth reading before you switch it on:
- Message fields
- Most fill themselves from the order. Two cannot: the review link on Order Delivered and Review Request, because Shopify has no review page of its own, and the discount code on Cart Recovery. Leave the review link blank and the message points at your front page; leave the discount code blank and the customer sees a
-. - Customer sees
- A live preview of the message as it will land on the phone. Read it once. The wording is fixed after approval.
- Delay (minutes)
- How long to wait after the event.
0for an order confirmation;2880, two days, for a review request. Asking for a review the moment a parcel arrives gets you nothing.
Nothing is saved until you press Save notifications.

Automations and delivery settings
The Features tab decides when the app sends; the Notifications tab decides what. Both are needed, a feature switched on with its event disabled or unapproved sends nothing.
- Abandoned cart recovery
- Messages customers who reached the phone-number step at checkout and did not finish. This is marketing: send it only to customers who accepted marketing, and one reminder is the limit before it becomes a nuisance.
- Cash-on-delivery confirmation
- Asks the customer to confirm a COD order before you dispatch. Inside the 24-hour window they get two buttons and their tap moves the order, a confirmation tags it
cod-confirmed, a cancellation cancels it and tags itcod-cancelled. Outside it, which is the usual case straight after checkout, they get a code to reply with. A tapped button is only acted on when it comes from a number your store already holds for that order. - Back-in-stock alerts
- Messages customers who asked to be told when a sold-out product returns. Needs the theme snippet and the App Proxy below.
- Review requests
- Asks for a review after delivery. Give it a delay of a day or two.
Test mode sends everything to your test recipient instead of the customer, with a banner on the Features tab while it is on. Use it during setup and turn it off before you go live.

Which Shopify webhook drives which event
Subscriptions are registered over the Admin API on every install and re-auth, because a scope change or a reinstall drops the previous ones. Each arrives at https://<your-host>/webhooks/<topic>, and the X-Shopify-Hmac-Sha256 signature is verified against the raw body before the JSON is parsed.
- orders/create
order_confirmation, andorder_verificationwhen COD is on- orders/updated
order_status- orders/cancelled
order_cancelled- orders/paid
payment_received- orders/fulfilled, fulfillments/create
order_shipped- fulfillments/update
out_for_delivery,order_delivered,review_request- refunds/create
refund_processed- checkouts/create, checkouts/update
- Records the cart for recovery
- customers/create
welcome- products/update
back_in_stock- app/uninstalled
- Marks the shop uninstalled and stops all sending
Back in stock: the App Proxy and the theme snippet
A sold-out product page needs a form that posts a phone number to the app. It reaches the app through a Shopify App Proxy: Shopify serves a path on the merchant's own domain and forwards it to your app, signing each request. Because the request comes from the store's own origin it is same-origin for the theme, no CORS, no third-party cookie problem.
storefront https://the-shop.myshopify.com/apps/whatsapp/back-in-stock
└──┬─┘ └───┬──┘
prefix subpath
arrives at https://<your-host>/proxy/back-in-stockConfigure the proxy
In the Partner Dashboard: Apps → your app → Configuration → App proxy.
- Subpath prefix
apps- Subpath
whatsapp- Proxy URL
https://<your-host>/proxy
The same three values live in the app's shopify.app.toml under [app_proxy] if you deploy with the Shopify CLI; shopify app config push applies them.
Add the snippet to your theme
Create the snippet
Online Store → Themes → … → Edit code, then Snippets → Add a new snippet, namedwhatsapp-back-in-stock. Paste indocs/back-in-stock-snippet.liquidfrom the app repository.Render it on the product page
Open your product template,sections/main-product.liquidin Dawn and most Online Store 2.0 themes,sections/product-template.liquidortemplates/product.liquidin older ones, and add the render tag where the form should appear, usually after the Add to cart button.Check the proxy path at the top of the snippet
assign proxy_path = '/apps/whatsapp/back-in-stock'. It is/<prefix>/<subpath>/back-in-stock. If you changed either in the Partner Dashboard, change it here too.Switch the feature on
Back-in-stock alerts on the Features tab, and theback_in_stockevent enabled with an approved template on the Notifications tab. Without both, sign-ups are refused and nothing is stored.
{% render 'whatsapp-back-in-stock' %}The form is safe to render on every product: it stays hidden until the selected variant is sold out. It also calls GET on the same proxy path, which answers {"ok":true,"enabled":…}, and hides itself when back-in-stock alerts are switched off in the app. That endpoint deliberately says nothing about a particular number or variant, a per-phone answer would let anyone with a list of numbers ask which of them shop here, and a subscriber count would publish which products are in demand.
Sign-ups are refused, with a status a theme can act on, in six cases:
- 404 shop_inactive
- The app has been uninstalled from this store.
- 403 not_enabled
- Back-in-stock alerts are switched off in the app.
- 400 invalid_product
- The product or variant id did not resolve.
- 400 no_recipient
- The number could not be read, usually a missing country code.
- 403 opted_out
- This number has replied STOP, and stays refused.
- 429 rate_limited
- Too many sign-ups from one number in an hour. The response carries
Retry-After: 3600, and a successful sign-up returnsperHourLimitso a theme can show its own limit first.

Test, then go live
Send yourself a test
With test mode on, place a real order on the store and watch it arrive on your own number. A test that goes through the whole webhook path proves more than a send button does.Turn test mode off
Then place one more order and confirm the customer copy arrives.Watch the first day
Read the delivery log rather than waiting to be told. See Analytics and delivery logs.
When it does not work
- Every webhook fails HMAC
- Something parsed the body before the signature check ran, a global
express.json(), or a proxy that rewrites the body. The signature is over the raw bytes. - Every admin call returns 401
- The app was opened outside the Shopify admin frame, or the client secret was rotated. Session tokens are signed with it.
- TEMPLATE_NOT_APPROVED
- The event is enabled but its template is not approved. Refresh the status.
- The reply box is greyed out
- The customer's 24-hour window has closed. Send an approved template instead, see The 24-hour window.
- Back-in-stock sign-ups fail
- Nearly always the proxy path not matching in all three places. See above.
- Nothing arrives at all
- Meta error
133010. The number is not registered on the Cloud API.
Troubleshooting covers the platform-side causes in the order worth checking them.
