Recover failed Shopify Subscriptions payments

Shopify subscription contracts are billed by attempt. When an attempt fails, the contract stays alive but the order is not created — that window is where recovery happens, and it usually ends with the customer updating their payment method in their account.

The Shopify Subscriptions events recovery depends on

subscription_billing_attempts/failure
A scheduled subscription charge failed — open a recovery case.
subscription_billing_attempts/success
The charge cleared. Close the case.
subscription_contracts/update
The customer changed the contract or its payment method.

Verifying Shopify Subscriptions webhooks

Scheme
HMAC-SHA256 over the raw body, base64-encoded
Signature location
X-Shopify-Hmac-Sha256

Verify before parsing. Shopify also sends X-Shopify-Shop-Domain, which you should map to the right workspace in a multi-store setup.

import { createHmac, timingSafeEqual } from "crypto";

const digest = createHmac("sha256", process.env.SHOPIFY_WEBHOOK_SECRET!)
  .update(rawBody, "utf8")
  .digest("base64");

const hmac = req.headers["x-shopify-hmac-sha256"] as string;
if (!timingSafeEqual(Buffer.from(digest), Buffer.from(hmac))) {
  return new Response("Invalid signature", { status: 401 });
}

// topic: subscription_billing_attempts/failure
const attempt = JSON.parse(rawBody);
await rrlabs.enqueueRecovery({
  provider: "shopify",
  externalId: attempt.admin_graphql_api_id,
  declineCode: attempt.error_code,      // e.g. "expired_payment_method"
});

Decline playbook for Shopify Subscriptions

Recovery actions per Shopify Subscriptions failure signal
Failure signalRecovery action
expired_payment_methodSend the customer-account payment update link. Retrying the same method will not succeed.
insufficient_fundsReschedule the billing attempt a few days out and send a light reminder.
payment_method_not_foundThe stored method was removed — ask the customer to add one before the next contract cycle.

What happens after a payment fails

  1. T+0s

    Payment failed

    Provider webhook received and verified

  2. T+2s

    AI analysis

    Decline reason classified, amount at risk scored

  3. T+5s

    Dynamic email

    Copy generated for that decline code and customer

  4. Day 2

    Smart retry

    Retry scheduled only when the decline code is retryable

  5. Day 2

    WhatsApp push

    Second channel used when the email went unanswered

  6. On success

    Recovered

    Counted only when the provider confirms the charge

Timings describe the configured workflow, not a guaranteed outcome. Every step is skipped when the decline reason makes it counter-productive.

Frequently asked questions

Does a failed billing attempt cancel the Shopify contract?
Not immediately. The contract stays active while attempts are retried, which is the window recovery messaging targets.
Can RRLabs retry the Shopify billing attempt?
Retries are scheduled through Shopify's subscription APIs by the app that owns the contract. RRLabs decides when a retry makes sense and handles the customer communication.

Connect Shopify Subscriptions with read-only credentials

RRLabs reads failure events and orchestrates recovery. It never holds card data and never becomes the merchant of record.

Get early access