Billing API request not authenticating

Topic summary

A developer is experiencing a 302 redirect error when implementing Shopify’s Billing API, preventing the expected subscription page from appearing. Instead, the app enters a loop and fails with an authentication-related redirect (/auth/exit-iframe?shop=).

Current Implementation:

  • Using billing.require() with a monthly plan ($300 USD, 30-day interval, 45-day trial)
  • Checking for active subscriptions via GraphQL query
  • Attempting to redirect users to subscription page when no active subscription exists

Key Issue:
The app doesn’t automatically open the subscription page as expected from tutorials; instead it loops and errors out.

Suggested Solution:
A commenter notes the developer isn’t using try-catch blocks and suggests the issue may be failing to re-throw the 302 redirect that billing.require() generates. The redirect response needs to be properly handled to send users to the authentication/billing flow.

Status: Unresolved - awaiting confirmation if implementing proper redirect handling resolves the authentication loop.

Summarized with AI on October 24. AI used: claude-sonnet-4-5-20250929.

Hi there,

I’ve been following the existing solutions for setting up the billing API that seems to generally work (https://github.com/marktiddy/Shopify-Remix-Billing-Demo/blob/main/app/routes/app._index.jsx)

However, I’m getting a weird 302 error when I run the app, the header is making me think that there’s some sort of authentication error (location: '/auth/exit-iframe?shop=).

app._index.js

export const loader = async ({ request }: LoaderFunctionArgs) => {
  // Authenticate with Shopify
  const { admin, billing, session } = await authenticate.admin(request);
  const {shop} = session;
  const subscriptions = await getSubscriptionStatus(admin.graphql);
  const { activeSubscriptions } = subscriptions.data.app.installation;

  const returnUrl = `https://admin.shopify.com/store/${shop}/apps/[APP]/app`
  console.log("Return URL: ", returnUrl);

  if (activeSubscriptions.length < 1) {
    console.log("billing: ", billing)
    console.log("billing.request: ", billing.request)
    await billing.require({
      plans: [MONTHLY_PLAN],
      isTest: true,
      onFailure: async () => { 
        billing.request({ 
          plan: MONTHLY_PLAN, 
          isTest: true,
          returnUrl: returnUrl
        }).catch(error => {
          console.error('An error occurred:', error);
        });
      },
      returnUrl: returnUrl
    });
  }

from shopify.server

billing: {
    [MONTHLY_PLAN]: {
      amount: 300,
      currencyCode: "USD",
      interval: BillingInterval.Every30Days,
      trialDays: 45,
      isTest: true,
    }
  }

In the tutorials, I expects that when I refreshed my app a subscription page would open up automatically; however, instead, my app seems to get caught in some sort of loop and then errors out.

Does anyone have an idea of what may be going awry?

Thanks!

1 Like

Clearly you’re not using a try-catch statement, but I had problems where I wasn’t re-throwing the redirect (302 response) that billing.require() throws sometimes to send the user to auth.

I don’t know if this is relevant: Billing Redirect Not Working On Remix - 401 Error using "billing.request()" - #2 by stefanb1234