--- title: Billing description: |- Contains function used to bill merchants for your app. This object is returned on authenticated Admin requests. api_version: v2 api_name: shopify-app-remix source_url: html: 'https://shopify.dev/docs/api/shopify-app-remix/v2/apis/billing' md: 'https://shopify.dev/docs/api/shopify-app-remix/v2/apis/billing.md' --- # Billing Contains function used to bill merchants for your app. This object is returned on authenticated Admin requests. ## billing Provides utilities that apps can use to request billing for the app using the Admin API. * **require** **(options: RequireBillingOptions\) => Promise\** **required** Checks if the shop has an active payment for any plan defined in the `billing` config option. * **check** **(options: CheckBillingOptions\) => Promise\** **required** Checks if the shop has an active payment for any plan defined in the `billing` config option. * **request** **(options: RequestBillingOptions\) => Promise\** **required** Requests payment for the plan. * **cancel** **(options: CancelBillingOptions) => Promise\** **required** Cancels an ongoing subscription, given its ID. ### RequireBillingOptions * plans The plans to check for. Must be one of the values defined in the \`billing\` config option. ```ts (keyof Config["billing"])[] ``` * onFailure How to handle the request if the shop doesn't have an active payment for any plan. ```ts (error: any) => Promise ``` * isTest Whether to consider test purchases. ```ts boolean ``` ### BillingCheckResponseObject * hasActivePayment Whether the user has an active payment method. ```ts boolean ``` * oneTimePurchases The one-time purchases the shop has. ```ts OneTimePurchase[] ``` * appSubscriptions The active subscriptions the shop has. ```ts AppSubscription[] ``` ### OneTimePurchase * id The ID of the one-time purchase. ```ts string ``` * name The name of the purchased plan. ```ts string ``` * test Whether this is a test purchase. ```ts boolean ``` * status The status of the one-time purchase. ```ts string ``` ### AppSubscription * id The ID of the app subscription. ```ts string ``` * name The name of the purchased plan. ```ts string ``` * test Whether this is a test subscription. ```ts boolean ``` * lineItems ```ts ActiveSubscriptionLineItem[] ``` ### ActiveSubscriptionLineItem * id ```ts string ``` * plan ```ts AppPlan ``` ### AppPlan * pricingDetails ```ts RecurringAppPlan | UsageAppPlan ``` ### RecurringAppPlan * interval ```ts BillingInterval.Every30Days | BillingInterval.Annual ``` * price ```ts Money ``` * discount ```ts AppPlanDiscount ``` ### BillingInterval * OneTime ```ts ONE_TIME ``` * Every30Days ```ts EVERY_30_DAYS ``` * Annual ```ts ANNUAL ``` * Usage ```ts USAGE ``` ### Money * amount ```ts number ``` * currencyCode ```ts string ``` ### AppPlanDiscount * durationLimitInIntervals ```ts number ``` * remainingDurationInIntervals ```ts number ``` * priceAfterDiscount ```ts Money ``` * value ```ts AppPlanDiscountAmount ``` ### AppPlanDiscountAmount ```ts BillingConfigSubscriptionPlanDiscountAmount | BillingConfigSubscriptionPlanDiscountPercentage ``` ### BillingConfigSubscriptionPlanDiscountAmount * amount The amount to discount. Cannot be set if \`percentage\` is set. ```ts number ``` * percentage The percentage to discount. Cannot be set if \`amount\` is set. ```ts never ``` ### BillingConfigSubscriptionPlanDiscountPercentage * amount The amount to discount. Cannot be set if \`percentage\` is set. ```ts never ``` * percentage The percentage to discount. Cannot be set if \`amount\` is set. ```ts number ``` ### UsageAppPlan * balanceUsed ```ts Money ``` * cappedAmount ```ts Money ``` * terms ```ts string ``` ### CheckBillingOptions * plans The plans to check for. Must be one of the values defined in the \`billing\` config option. ```ts (keyof Config["billing"])[] ``` * isTest Whether to consider test purchases. ```ts boolean ``` ### RequestBillingOptions * plan The plan to request. Must be one of the values defined in the \`billing\` config option. ```ts keyof Config["billing"] ``` * 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 ``` * returnUrl The URL to return to after the merchant approves the payment. ```ts string ``` ### CancelBillingOptions * subscriptionId The ID of the subscription to cancel. ```ts string ``` * prorate Whether to prorate the cancellation. ```ts boolean ``` * isTest ```ts boolean ``` Examples ### 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'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); 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]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Requesting billing with line items ##### Description Call \`billing.request\` with the \`v3\_lineItemBilling\` future flag enabled ##### /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'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { lineItems: [ { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, { amount: 1, currencyCode: 'USD', interval: BillingInterval.Usage. terms: '1 dollar per 1000 emails', }, ], }, } future: {v3_lineItemBilling: true} }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### 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]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### 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]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### 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]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ## Related [Authenticate requests from Shopify Admin. - Admin context](https://shopify.dev/docs/api/shopify-app-remix/authenticate/admin)