Register webhook subscriptions for the `subscription_billing_attempts/success` and `subscription_billing_attempts/failure` topics via the Admin GraphQL API `webhookSubscriptionCreate` mutation, providing your HTTPS endpoint URL and the topic.
On your server, receive the POST request, immediately return a 200 response to acknowledge receipt before doing any processing — Shopify will retry delivery if it does not receive a 200 within a few seconds.
Verify the webhook authenticity by computing an HMAC-SHA256 digest of the raw request body using your webhook secret and comparing it to the `X-Shopify-Hmac-SHA256` header value — reject requests that do not match.
Parse the payload: on `subscription_billing_attempts/success`, extract the subscription contract ID and update your records with the new `nextBillingDate`; on `subscription_billing_attempts/failure`, extract the `errorCode` and trigger your dunning logic.
Implement deduplication using the `X-Shopify-Event-Id` header — store processed event IDs to prevent double-processing on Shopify's retry deliveries.
For missed webhooks, implement a reconciliation job that queries the Admin GraphQL API for recent billing attempts on active contracts and compares the result to your local records.
Known gotchas
Shopify retries webhook delivery with exponential backoff if your endpoint returns a non-200 status or times out. Ensure your endpoint responds with 200 before performing any async work — use a queue to offload processing.
The `subscription_billing_attempts/failure` payload includes an `error_code` string. This is distinct from payment decline codes from the underlying processor — map it to your dunning decision tree using Shopify's documented error code values, not raw processor codes.
Shopify webhook topics related to subscriptions require that your app has the appropriate subscription-related access scopes. If the webhooks are not being delivered, verify scope configuration first before debugging the endpoint.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp