Shopify App billing Api,Status and oauth token

Hi everyone,

I am using Shopify Billing API with appSubscriptionCreate and have a few questions about subscription lifecycle:

1. Trial end and first charge

I created an AppSubscription with trialDays: 2. When the 2-day trial ended and Shopify charged the merchant, I did not receive an app_subscriptions/update webhook indicating that the trial ended or that the actual paid billing started.

Is this expected? What is the recommended way to detect when the trial ends and the first actual charge begins?

2. Renewal webhook

For a subscription with recurring billing, do we receive app_subscriptions/update for every successful renewal, or only when the subscription status changes?

3. Failed payment and custom 7-day grace period

From my understanding, when a renewal payment fails or when trial period end after that payment fails, the subscription can remain ACTIVE during Shopify’s billing/grace period and later become FROZEN.

I want to implement my own 7-day grace period:

  • Payment fails → start 7-day grace period

  • Payment succeeds → continue normally

  • Payment remains unresolved after 7 days → restrict paid features

Since the initial payment failure may not trigger app_subscriptions/update, what is the recommended way to detect the payment failure and start my own 7-day timer?

4. New OAuth token

Suppose I create a subscription and register webhooks using OAuth token A. Later, the same shop goes through OAuth again and I receive OAuth token B.

What happens to the existing subscription and webhook registrations?

Are they associated with the shop/app installation rather than the individual OAuth access token? Do the existing subscription and webhooks continue working with the new token, or do I need to recreate anything?

Thanks!

@amber_dube, on the token question, the subscription and any webhooks you registered through the API belong to the shop’s app installation, not to a specific token, so a new token from re-auth doesn’t need them recreated. For status I’d rely on querying currentAppInstallation.activeSubscriptions rather than waiting on a webhook to tell you the trial ended.

Hi @amber_dube, to answer each of your questions:

  1. Trial end and first charge

    The subscription becomes active when the merchant approves the charge. trialDays delays the start of billing; it does not delay subscription activation. When the trial ends and billing begins, the status remains ACTIVE, so app_subscriptions/update is not emitted.

    For a non-test subscription, currentPeriodEnd identifies the trial end while the trial is active. When the first post-trial billing period begins, it advances to the end of that period. Use this value rather than calculating createdAt + trialDays: record it, re-query after it passes, and retry later if it has not moved.

    If the subscription was created with test: true, currentPeriodEnd is set once at approval to the trial end plus one billing interval and does not advance. Test subscriptions therefore cannot be used to observe this transition.

  2. Renewals

    A renewal leaves the subscription ACTIVE, so it does not emit the app_subscriptions/update webhook, which is triggered only when the subscription status or capped amount changes.

    You can use currentPeriodEnd to detect that a new billing period has begun, but not as confirmation that payment succeeded.

  3. Failed payment and a custom seven-day grace period

    App charges are collected through the merchant’s Shopify bill. The initial failed attempt to collect that bill is not exposed through an Admin API field, webhook, or Partner API event. The subscription remains ACTIVE while Shopify retries collection. The first signal available to the app is when the subscription becomes FROZEN, which emits app_subscriptions/update.

    This means a seven-day timer beginning with the initial failed attempt cannot be implemented reliably. We recommend restricting access only after the subscription becomes FROZEN, as described in the failed-payment guidance.

  4. New OAuth token

    The answer above is correct. Store token B for subsequent requests.

    If the new OAuth grant has fewer scopes, affected webhook registrations are not deleted, but deliveries stop and they no longer appear in the webhookSubscriptions query. New registrations for those topics also fail until the required scope is restored. An uninstall cancels the subscription and removes the installation’s webhooks, so both need to be set up again after reinstalling.

Let me know if you need any further clarification!

Thank you @Mubashir_Hassan for your response.

Hi @Paige-Shopify ,Thank you for the detailed explanation I have question regarding renewals

In 2 point You mentioned that currentPeriodEnd can be used to detect that a new billing period has begun, but it cannot be used as confirmation that the renewal payment succeeded.

if I provide different features based on the merchant’s subscription plan. Therefore, I need to know whether the merchant has actually paid for the next billing period before continuing to provide paid-plan features.

Similarly, after a trial ends, the first paid charge could potentially fail while the subscription remains ACTIVE. In that situation, how would my application know whether the merchant successfully started the paid billing period or whether Shopify is still attempting to collect the payment?
One more thing I am using manual pricing so partner api will work with that?
So what approach should I follow for an app that needs to control paid-plan features based on whether the billing was successfully collected?

There is no real-time API signal that the latest app subscription charge has been paid. The subscription remains ACTIVE even while payment is pending or being retried.

For feature access, keep paid features enabled for ACTIVE, pause them for FROZEN and restore them when it returns to ACTIVE. CANCELLED, DECLINED, and EXPIRED are terminal states, but a plan change cancels the previous subscription and activates another, so check for another ACTIVE subscription before removing access.

For manual pricing through the Billing API, read the status from app_subscriptions/update. If you query currentAppInstallation.activeSubscriptions, make sure to inspect each subscription’s status because it can return both ACTIVE and FROZEN subscriptions.

Payment can only be confirmed after the fact. You can review the latest charge in the Partner Dashboard, where a recurring charge can take up to 37 days to appear as an earning after the merchant agrees to it. Partner API Historical Events also work with manual-pricing subscriptions. EARNING_CHARGE_RECURRING confirms payment, while CHARGE_RECURRING only means the merchant was billed. A missing earning event does not indicate payment failure.

@Paige-Shopify Thanks for explanation

Two follow-up questions:

  1. Renewals: If a renewal payment fails, does currentPeriodEnd still advance to the next billing period right away, or does it stay at the old value until payment is resolved? Is a successful renewal identical in this respect, so the only difference is a later FROZEN status or an EARNING_CHARGE_RECURRING event?
  2. Testing FROZEN: Is there any way to simulate a FROZEN subscription, either with a test: true subscription or a non-test one on a development store (for example, a test payment method that makes the Shopify bill fail)? If not, what is the recommended way to test FROZEN and reactivation handling before going live?