shopify-billing

SKILL.md

Shopify Billing Skill

The Billing API allows you to charge merchants for your app using recurring subscriptions or one-time purchases.

[!IMPORTANT] GraphQL Only: The REST Billing API is deprecated. Always use the GraphQL Admin API for billing operations.

1. Recurring Subscriptions (appSubscriptionCreate)

Use this mutation to create a recurring charge (e.g., monthly plan).

Example (Remix / Shopify App Template)

/* app/routes/app.upgrade.tsx */
import { authenticate } from "../shopify.server";

export const action = async ({ request }) => {
  const { admin } = await authenticate.admin(request);
  const shop = await admin.graphql(`
    mutation AppSubscriptionCreate($name: String!, $lineItems: [AppSubscriptionLineItemInput!]!, $returnUrl: URL!) {
      appSubscriptionCreate(name: $name, returnUrl: $returnUrl, lineItems: $lineItems) {
        userErrors {
          field
          message
        }
        appSubscription {
          id
        }
        confirmationUrl
      }
    }
  `,
  {
    variables: {
      name: "Pro Plan",
      returnUrl: "https://myapp.com/app",
      lineItems: [{
        plan: {
          appRecurringPricingDetails: {
            price: { amount: 10.00, currencyCode: "USD" },
            interval: "EVERY_30_DAYS"
          }
        }
      }]
    }
  });

  const response = await shop.json();
  const confirmationUrl = response.data.appSubscriptionCreate.confirmationUrl;
  
  // Redirect merchant to approve charge
  return redirect(confirmationUrl);
};

2. One-Time Purchases (appPurchaseOneTimeCreate)

Use this mutation for non-recurring charges (e.g., specific service, lifetime access).

const response = await admin.graphql(`
  mutation AppPurchaseOneTimeCreate($name: String!, $price: MoneyInput!, $returnUrl: URL!) {
    appPurchaseOneTimeCreate(name: $name, returnUrl: $returnUrl, price: $price) {
      userErrors { field message }
      confirmationUrl
    }
  }
`, {
  variables: {
    name: "Concierge Setup",
    returnUrl: "https://myapp.com/app",
    price: { amount: 50.00, currencyCode: "USD" }
  }
});

3. Checking Active Subscriptions

To gate features, check the currentAppInstallation for active subscriptions.

/* app/shopify.server.ts (billing config) */
export const billing = {
  "Pro Plan": {
    amount: 10.00,
    currencyCode: "USD",
    interval: "EVERY_30_DAYS",
  },
};

/* Checking in loader */
const { billing } = await authenticate.admin(request);
const billingCheck = await billing.require({
  plans: ["Pro Plan"],
  isTest: true, // Use true for development stores
  onFailure: async () => billing.request({ plan: "Pro Plan", isTest: true }),
});
const subscription = billingCheck.appSubscriptions[0];

Manual Query (if not using billing helper)

query {
  currentAppInstallation {
    activeSubscriptions {
      id
      name
      status
      lineItems {
        plan {
          pricingDetails {
            ... on AppRecurringPricing {
              price { amount currencyCode }
            }
          }
        }
      }
    }
  }
}

4. Best Practices

  • Test Mode: Always set test: true (or isTest) when developing. Test charges do not bill the merchant.
  • Confirmation URL: You MUST redirect the user to the confirmationUrl returned by the mutation. The charge is not active until they approve it.
  • Webhooks: Listen for app_subscriptions/update to handle cancellations or status changes in real-time.
Weekly Installs
4
First Seen
Jan 25, 2026
Installed on
gemini-cli4
claude-code4
codex4
opencode4
antigravity3
github-copilot3