Build a Shopify App with Node.js and React

Charge a fee using the Billing API

All paid apps need to use the Billing API to process sales in the Shopify App Store, unless you’ve been approved for other payment methods by Shopify.

When you’re ready to list your app on the Shopify App Store, you’ll probably need a way to charge the merchants who install your app. You can do this by using the Billing API, which lets third-party app charges be added to a merchant’s monthly invoice. You can make query the Billing API via the admin GraphQL endpoint, so you will implement it with fetch using isomporphic fetch in your server.js file.

Because merchants store their payment methods in Shopify, and we aim to provide a simple, streamlined billing experience, all apps that create charges must use the Shopify Billing API. It supports three different billing models:

  • one-time charges
  • 30-day recurring charges
  • usage charges, which charge a merchant based on a variable-value over a recurring 30-day period
The examples in this tutorial are based on the recurring application charge. To learn more about which model your own apps can use, see Determine your billing model.

Make calls to the Billing API

You’ll need to make an API call to redirect merchants to the billing screen in the Shopify admin. The call will need to come from your server.js file during the authentication process. The Billing API expects the following properties:

  • name - The name of your charge. For example, Sample embedded app 30-day fee.
  • price - The price of the recurring application charge.
  • The return URL - The URL where the merchant is sent after accepting or declining the charge.

The Billing API also has a test property that simulates successful charges.

Set up a test return URL

You’ll use your ngrok URL as the return URL while testing your app’s billing process. In a production app you would use your production URL for the return URL.

  1. Add the HTTPS version of your ngrok forwarding URL and your API version to your .env file:
    SHOPIFY_API_KEY='YOUR SHOPIFY API KEY FROM THE SHOPIFY PARTNERS DASHBOARD' SHOPIFY_API_SECRET_KEY='YOUR SHOPIFY API SECRET KEY FROM THE SHOPIFY PARTNERS DASHBOARD' HOST='https://YOURNGROKADDRESS.io' API_VERSION='2019-10'

Call the Billing API and redirect to the confirmation page

You will make a call to the GraphQL endpoint using a POST request, it will return the confirmation_url which you can redirect users to. You’ll set up a getSubscriptionUrl file to make the call and then await that in your server file.

  1. Create a server folder in your root project folder.
  2. Create a getSubscriptionUrl file in the server folder.
  3. Add the following scaffolding to get charges and check status:

    /server/getSubscriptionUrl.js

    code contained in /server/getSubscriptionUrl.js
    const getSubscriptionUrl = async (ctx, accessToken, shop) => { const query = JSON.stringify({ query: `mutation { appSubscriptionCreate( name: "Super Duper Plan" returnUrl: "${process.env.HOST}" test: true lineItems: [ { plan: { appUsagePricingDetails: { cappedAmount: { amount: 10, currencyCode: USD } terms: "$1 for 1000 emails" } } } { plan: { appRecurringPricingDetails: { price: { amount: 10, currencyCode: USD } } } } ] ) { userErrors { field message } confirmationUrl appSubscription { id } } }` }); const response = await fetch(`https://${shop}/admin/api/2019-10/graphql.json`, { method: 'POST', headers: { 'Content-Type': 'application/json', "X-Shopify-Access-Token": accessToken, }, body: query }) const responseJson = await response.json(); const confirmationUrl = responseJson.data.appSubscriptionCreate.confirmationUrl return ctx.redirect(confirmationUrl) }; module.exports = getSubscriptionUrl;
  4. In your server.js file, add the call to getSubscriptionUrl:

    /server.js

    code contained in /server.js
    require('isomorphic-fetch'); const dotenv = require('dotenv'); const Koa = require('koa'); const next = require('next'); const { default: createShopifyAuth } = require('@shopify/koa-shopify-auth'); const { verifyRequest } = require('@shopify/koa-shopify-auth'); const session = require('koa-session'); dotenv.config(); const { default: graphQLProxy } = require('@shopify/koa-shopify-graphql-proxy'); const { ApiVersion } = require('@shopify/koa-shopify-graphql-proxy'); Add: const getSubscriptionUrl = require('./server/getSubscriptionUrl'); const port = parseInt(process.env.PORT, 10) || 3000; const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); const { SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY, API_VERSION } = process.env; app.prepare().then(() => { const server = new Koa(); server.use(session(server)); server.keys = [SHOPIFY_API_SECRET_KEY]; server.use( createShopifyAuth({ apiKey: SHOPIFY_API_KEY, secret: SHOPIFY_API_SECRET_KEY, scopes: ['write_products', 'read_products'], Remove: afterAuth(ctx) { Add: async afterAuth(ctx) { const { shop, accessToken } = ctx.session; ctx.cookies.set('shopOrigin', shop, { httpOnly: false }) Remove: ctx.redirect('/'); Add: await getSubscriptionUrl(ctx, accessToken, shop); }, }), ); server.use(graphQLProxy({version: ApiVersion.October19})) server.use(verifyRequest()); server.use(async (ctx) => { await handle(ctx.req, ctx.res); ctx.respond = false; ctx.res.statusCode = 200; return }); server.listen(port, () => { console.log(`> Ready on http://localhost:${port}`); }); });

Create a test charge

Test your app charge from your development store to view the output and check its status.

  1. Stop and restart your server.
  2. In your development store’s Shopify admin, go to the Apps page, and then uninstall your app. Apps section of the development store Admin circling the sample embedded app's garbage icon
  3. Reinstall your app using the callback address:

    https://YOURNGROKADDRESS.io/auth?shop=YOURTESTSTORE.myshopify.com

    You should first be prompted to install the app, and then prompted separately to accept the test charges. The billing screen should look like this

    Billing charges screen
  4. Click Approve charges to accept the test charges.
  5. You should receive an email with a confirmation of the test charges.

    <span class="translation_missing" title="translation missing: en.build_a_shopify_app_with_node_and_react.charge_a_fee_using_the_billing_api.email_alt">Email Alt</span>
Continue to Listen for store events with Webhooks