--- title: Billing description: |- Contains function used to bill merchants for your app with the Billing API. This object is returned on authenticated Admin requests. > Note: [Managed App Pricing](/docs/apps/launch/billing/managed-pricing) is now available. Define your app’s pricing plans directly in the Shopify Partner Dashboard, without needing to use the Billing API. api_version: v4 latest api_name: shopify-app-remix source_url: html: https://shopify.dev/docs/api/shopify-app-remix/latest/apis/billing md: https://shopify.dev/docs/api/shopify-app-remix/latest/apis/billing.md --- # Billingobject Contains function used to bill merchants for your app with the Billing API. This object is returned on authenticated Admin requests. Note [Managed App Pricing](https://shopify.dev/docs/apps/launch/billing/managed-pricing) is now available. Define your app’s pricing plans directly in the Shopify Partner Dashboard, without needing to use the Billing API. ## billing Provides utilities that apps can use to request billing for the app using the Admin API. * cancel (options: CancelBillingOptions) => Promise\ required Cancels an ongoing subscription, given its ID. * check \>(options?: Options) => Promise\ required Checks if the shop has an active payment for any plan defined in the `billing` config option. * createUsageRecord (options: CreateUsageRecordOptions) => Promise\ required Creates a usage record for an app subscription. * request (options: RequestBillingOptions\) => Promise\ required Requests payment for the plan. * require (options: RequireBillingOptions\) => Promise\ required Checks if the shop has an active payment for any plan defined in the `billing` config option. * updateUsageCappedAmount (options: UpdateUsageCappedAmountOptions) => Promise\ required Updates the capped amount for a usage billing plan. ### CancelBillingOptions * isTest Whether to use the test mode. This prevents the credit card from being charged. ```ts boolean ``` * prorate Whether to issue prorated credits for the unused portion of the app subscription. There will be a corresponding deduction (based on revenue share) to your Partner account. For example, if a $10.00 app subscription (with 0% revenue share) is cancelled and prorated half way through the billing cycle, then the merchant will be credited $5.00 and that amount will be deducted from your Partner account. ```ts boolean ``` * subscriptionId The ID of the subscription to cancel. ```ts string ``` ```ts export interface CancelBillingOptions { /** * The ID of the subscription to cancel. */ subscriptionId: string; /** * Whether to issue prorated credits for the unused portion of the app subscription. There will be a corresponding * deduction (based on revenue share) to your Partner account. For example, if a $10.00 app subscription * (with 0% revenue share) is cancelled and prorated half way through the billing cycle, then the merchant will be * credited $5.00 and that amount will be deducted from your Partner account. */ prorate?: boolean; /** * Whether to use the test mode. This prevents the credit card from being charged. */ isTest?: boolean; } ``` ### CheckBillingOptions * isTest Whether to include charges that were created on test mode. Test shops and demo shops cannot be charged. ```ts boolean ``` * plans The plans to check for. Must be one of the values defined in the \`billing\` config option. ```ts (keyof Config["billing"])[] ``` ```ts export interface CheckBillingOptions extends Omit { /** * The plans to check for. Must be one of the values defined in the `billing` config option. */ plans?: (keyof Config['billing'])[]; } ``` ### CreateUsageRecordOptions * description The description of the app usage record. ```ts string ``` * idempotencyKey ```ts string ``` * isTest Whether to use the test mode. This prevents the credit card from being charged. ```ts boolean ``` * price The price of the app usage record. ```ts { amount: number; currencyCode: string; } ``` * subscriptionLineItemId ```ts string ``` ```ts export interface CreateUsageRecordOptions { /** * The description of the app usage record. */ description: string; /** * The price of the app usage record. */ price: { /** * The amount to charge for this usage record. */ amount: number; /** * The currency code for this usage record. */ currencyCode: string; }; /** * Whether to use the test mode. This prevents the credit card from being charged. */ isTest: boolean; /* * Defines the usage pricing plan the merchant is subscribed to. */ subscriptionLineItemId?: string; /* * A unique key generated to avoid duplicate charges. */ idempotencyKey?: string; } ``` ### RequestBillingOptions * isTest Whether to use the test mode. This prevents the credit card from being charged. Test shops and demo shops cannot be charged. ```ts boolean ``` * plan The plan to request. Must be one of the values defined in the \`billing\` config option. ```ts keyof Config["billing"] ``` * returnUrl The URL to return to after the merchant approves the payment. ```ts string ``` ```ts export interface RequestBillingOptions extends Omit { /** * The plan to request. Must be one of the values defined in the `billing` config option. */ plan: keyof Config['billing']; /** * Whether to use the test mode. This prevents the credit card from being charged. Test shops and demo shops cannot be charged. */ isTest?: boolean; /** * The URL to return to after the merchant approves the payment. */ returnUrl?: string; } ``` ### RequireBillingOptions * isTest Whether to include charges that were created on test mode. Test shops and demo shops cannot be charged. ```ts boolean ``` * onFailure How to handle the request if the shop doesn't have an active payment for any plan. ```ts (error: any) => Promise ``` * plans The plans to check for. Must be one of the values defined in the \`billing\` config option. ```ts (keyof Config["billing"])[] ``` ```ts export interface RequireBillingOptions extends Omit { /** * The plans to check for. Must be one of the values defined in the `billing` config option. */ plans: (keyof Config['billing'])[]; /** * How to handle the request if the shop doesn't have an active payment for any plan. */ onFailure: (error: any) => Promise; } ``` ### UpdateUsageCappedAmountOptions * cappedAmount The maximum charge for the usage billing plan. ```ts { amount: number; currencyCode: string; } ``` * subscriptionLineItemId The subscription line item ID to update. ```ts string ``` ```ts export interface UpdateUsageCappedAmountOptions { /** * The subscription line item ID to update. */ subscriptionLineItemId: string; /** * The maximum charge for the usage billing plan. */ cappedAmount: { /** * The amount to update. */ amount: number; /** * The currency code to update. */ currencyCode: string; }; } ``` ## Examples ### cancel Cancelling a subscription Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`. ### Examples * #### Cancelling a subscription ##### Description Use the \`billing.cancel\` function to cancel an active subscription with the id returned from \`billing.require\`. ##### /app/routes/cancel-subscription.ts ```typescript import { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); const billingCheck = await billing.require({ plans: [MONTHLY_PLAN], onFailure: async () => billing.request({ plan: MONTHLY_PLAN }), }); const subscription = billingCheck.appSubscriptions[0]; const cancelledSubscription = await billing.cancel({ subscriptionId: subscription.id, isTest: true, prorate: true, }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, } ], }, [ANNUAL_PLAN]: { lineItems: [ { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ### check Check what billing plans a merchant is subscribed to Use billing.check if you want to determine which plans are in use. Unlike `require`, `check` does notthrow an error if no active billing plans are present. Check for payments without filtering Use billing.check to see if any payments exist for the store, regardless of whether it's a test ormatches one or more plans. ### Examples * #### Check what billing plans a merchant is subscribed to ##### Description Use billing.check if you want to determine which plans are in use. Unlike \`require\`, \`check\` does notthrow an error if no active billing plans are present. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); const { hasActivePayment, appSubscriptions } = await billing.check({ plans: [MONTHLY_PLAN], isTest: false, }); console.log(hasActivePayment); console.log(appSubscriptions); }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, } ], }, [ANNUAL_PLAN]: { lineItems: [ { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Check for payments without filtering ##### Description Use billing.check to see if any payments exist for the store, regardless of whether it's a test ormatches one or more plans. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); const { hasActivePayment, appSubscriptions } = await billing.check(); // This will be true if any payment is found console.log(hasActivePayment); console.log(appSubscriptions); }; ``` ### createUsageRecord Creating a usage record Create a usage record for the active usage billing plan ### Examples * #### Creating a usage record ##### Description Create a usage record for the active usage billing plan ##### /app/routes/create-usage-record.ts ```typescript import { ActionFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const action = async ({ request }: ActionFunctionArgs) => { const { billing } = await authenticate.admin(request); const chargeBilling = await billing.createUsageRecord({ description: "Usage record for product creation", price: { amount: 1, currencyCode: "USD", }, isTest: true, }); console.log(chargeBilling); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const USAGE_PLAN = 'Usage subscription'; const shopify = shopifyApp({ // ...etc billing: { [USAGE_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Usage, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ### request Using a custom return URL Change where the merchant is returned to after approving the purchase using the `returnUrl` option. Overriding plan settings Customize the plan for a merchant when requesting billing. Any fields from the plan can be overridden, as long as the billing interval for line items matches the config. ### Examples * #### Using a custom return URL ##### Description Change where the merchant is returned to after approving the purchase using the \`returnUrl\` option. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); await billing.require({ plans: [MONTHLY_PLAN], onFailure: async () => billing.request({ plan: MONTHLY_PLAN, isTest: true, returnUrl: 'https://admin.shopify.com/store/my-store/apps/my-app/billing-page', }), }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, } ], }, [ANNUAL_PLAN]: { lineItems: [ { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Overriding plan settings ##### Description Customize the plan for a merchant when requesting billing. Any fields from the plan can be overridden, as long as the billing interval for line items matches the config. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); await billing.require({ plans: [MONTHLY_PLAN], onFailure: async () => billing.request({ plan: MONTHLY_PLAN, isTest: true, trialDays: 14, lineItems: [ { interval: BillingInterval.Every30Days, discount: { value: { percentage: 0.1 } }, }, ], }), }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, } ], }, [ANNUAL_PLAN]: { lineItems: [ { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ### require Requesting billing right away Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment. Redirect to a plan selection page When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one. ### Examples * #### Requesting billing right away ##### Description Call \`billing.request\` in the \`onFailure\` callback to immediately redirect to the Shopify page to request payment. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); await billing.require({ plans: [MONTHLY_PLAN], isTest: true, onFailure: async () => billing.request({ plan: MONTHLY_PLAN }), }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Redirect to a plan selection page ##### Description When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderFunctionArgs, redirect } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { billing } = await authenticate.admin(request); const billingCheck = await billing.require({ plans: [MONTHLY_PLAN, ANNUAL_PLAN], isTest: true, onFailure: () => redirect('/select-plan'), }); const subscription = billingCheck.appSubscriptions[0]; console.log(`Shop is on ${subscription.name} (id ${subscription.id})`); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, } ], }, [ANNUAL_PLAN]: { lineItems: [ { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ### updateUsageCappedAmount Updating the capped amount for a usage billing plan Update the capped amount for the usage billing plan specified by `subscriptionLineItemId`. ### Examples * #### Updating the capped amount for a usage billing plan ##### Description Update the capped amount for the usage billing plan specified by \`subscriptionLineItemId\`. ##### /app/routes/\*\*\\/\*.ts ```typescript import { ActionFunctionArgs } from "@remix-run/node"; import { authenticate } from "../shopify.server"; export const action = async ({ request }: ActionFunctionArgs) => { const { billing } = await authenticate.admin(request); await billing.updateUsageCappedAmount({ subscriptionLineItemId: "gid://shopify/AppSubscriptionLineItem/12345?v=1&index=1", cappedAmount: { amount: 10, currencyCode: "USD" }, }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const USAGE_PLAN = 'Usage subscription'; const shopify = shopifyApp({ // ...etc billing: { [USAGE_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Usage, terms: "Usage based" } ], }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ## Related [![](https://shopify.dev/images/icons/32/pickaxe-1.png)![](https://shopify.dev/images/icons/32/pickaxe-1-dark.png)](https://shopify.dev/docs/api/shopify-app-remix/authenticate/admin) [Authenticate requests from Shopify Admin.Admin context](https://shopify.dev/docs/api/shopify-app-remix/authenticate/admin)