Skip to main content

Invoices, Taxes and Payments

In this guide, we're going to go through the steps you need to take in order to create Invoices, add Taxes, and finally take Payment for your Subscriptions.

Once you've gone through all the steps, you should have a good understanding of how to:

  1. Import datasets into Elastic Path Subscriptions to set up your store
  2. Model an Offering that requires Tax to be added to the Invoice
  3. Create Invoices with a Billing Run
  4. Add taxes to those invoices with a Tax Run
  5. Take payment for Invoices with a Payment Run with both Elastic Path Payments and Manual Payments

Prerequisites

Store Setup

Make sure your store has USD, EUR, and GBP currency codes set up.

We'll be using each of these codes to model different Taxes across different authorities.

Download the Assets

Download this zip file which contains the following:

FileDescription
collection.jsonA Postman Collection with all the API calls required for this guide
environment.jsonA Postman Environment you can set up to point to your store
manual-payment-store-dataset.jsonlA dataset file you can import into Elastic Path Subscriptions if you're using Manual Payments
ep-payment-store-dataset.jsonlA dataset file you can import into Elastic Path Subscriptions if you're using Elastic Path Payments

Payment Provider Setup

For this guide, we've set up two different approaches on how you can take payment for your invoices and suggest you pick the one that best suits your production needs.

info

If you are planning on using Elastic Path Payments with your store, there are a few prerequisites you need to do before continuing with the tutorial.

First, make sure you have Elastic Path Payments enabled for your store.

Second, you will need to create the following three customers in Stripe Test mode, along with some dummy card information (you can use the card number 4242 4242 4242 4242 with any future expiry date and CVC):

  1. Albert Einstein
  2. Isaac Newton
  3. Robert Oppenheimer

Make note of their Stripe Customer IDs and associated Card ID.

Finally, open up ep-payment-store-dataset.jsonl in your IDE or text editor.

You'll notice that on lines 4-6, we define the subscriptions where payment_authority has a few placeholder values for you to modify.

{
"type": "elastic_path_payments_stripe",
"customer_id": "<STRIPE_CUSTOMER_ID>",
"card_id": "<STRIPE_CARD_ID>"
}

Replace <STRIPE_CUSTOMER_ID> and <STRIPE_CARD_ID> with the Stripe information for each Customer you just created.

note

For a production use case, your checkout process would handle the creation of these customers and cards in Stripe, but for the purposes of this guide we're doing it manually.

Import the Postman Collection and Environment

Finally, let's set up the Postman Collection and Environment file.

Import collection.json and environment.json into Postman, and go to the Elastic Path Subscriptions - Adding Taxes environment.

Change the Current Value of the following variables to match your store, creating a new API key in Commerce Manager if you haven't already got one:

VariableValue
clientSecretThe Client Secret for your API key
clientIDThe Client ID for your API key
authURLThe API Base URL for your store

To check everything is set up correctly, go to the Elastic Path Subscriptions - Adding Taxes collection, ensure that the Elastic Path Subscriptions - Adding Taxes environment is selected and run the first API request called Authenticate.

You should see a 200 OK response and a new access token created in your environment for subsequent requests.

Our Fictional Business Problem

Let's get started by outlining the problem we're trying to solve.

  • You own a company called GlamGlobe which sells access to its makeup tutorials all around the world
  • There is only one monthly plan available called GlamPass, giving you access to all of its content on a monthly cadence
  • Because your Subscriptions are located across many countries, you are going to have different taxes applied to each Subscriber
  • You already have a tax system that can handle this for you, but you need a way to add those taxes to invoices before payment is collected
  • Taxes for the EU are added into the price of the Subscription so we don't have to add anything to the invoice, but this is not the case for the US and UK

Step 1 - Importing Offerings & Subscriptions into a Store

Let's start by setting up a store with all the information we need for our Subscriptions.

Elastic Path Subscriptions supports the ability to model most of your Subscription entities in a JSON Lines file that can then be imported into your store.

JSON Lines is a text format where each line is a JSON object, which is great for importing large datasets with relational information between objects in a single file.

We include support for importing the following Subscription entities:

  • Products
  • Plans
  • Offerings
  • Subscribers
  • Subscriptions

Depending on which approach you're using (Elastic Path Payments or Manual Payments), you'll find a .jsonl file in the zip you would have downloaded in the prerequisites section.

In Postman, go to the Import the Dataset API request and in the Body tab, change the value of import_file to select the dataset you want to use (ep-payment-store-dataset.jsonl for Elastic Path Payments or manual-payment-store-dataset.jsonl).

Run the request and you should see a new subscription_import job created with status:pending.

If you then run Check the Import Status request, you should eventually see that the status of your import job is successful, with meta.records.imported showing the following:

{
"imported": {
"subscription": 3,
"subscription_offering": 1,
"subscription_plan": 1,
"subscription_product": 1,
"subscription_subscriber": 0
}
}

If you then check Commerce Manager, you'll see that you now have a single offering called GlamGlobe, which has a GlamPass Product and a simple Monthly Plan.

You'll notice you also have three famous Subscribers, each an active subscription.

This can also be validated in Postman by running List Subscriptions.

Step 2 - Understanding Taxes in Elastic Path Subscriptions

Let's take a look at the Offering we've just imported. Open up the file you just imported into Elastic Path Subscriptions, and take a look at the first line which should be a subscription_product.

{
"data": {
"type": "subscription_product",
"attributes": {
"external_ref": "glam_pass",
"name": "GlamPass",
"sku": "glam_pass",
"price": {
"GBP": {
"amount": 1200,
"includes_tax": false
},
"USD": {
"amount": 1500,
"includes_tax": false
},
"EUR": {
"amount": 1400,
"includes_tax": true
}
}
}
}
}

You'll notice that for the GBP and USD currency codes, we have set includes_tax as false, but EUR we've set it to true.

This allows us to model for the scenario where our EUR Subscribers either have tax included in the price of the Subscription, or alternatively, no tax is actually required within that jurisdiction

On the other hand, for USD and EUR subscribers, we've indicated that tax is not included in the price, and we're going to have to add it to the invoice before taking payment.

warning

When you set includes_tax to true, you will not be able to take payment for that invoice until you have added taxes to it (even if it's an empty array of Tax Items).

Step 3 - Creating Invoices with a Billing Run

If you run the List Invoices request in Postman, or check Subscriptions -> Billing & Payment -> Invoices in
Commerce Manager, you'll notice that there aren't any there yet, even though there are active Subscriptions.

This is because of two reasons:

  1. These imported Subscriptions did not have first_invoice_paid set to true, indicating that the first Invoice would have been paid at checkout (either in Carts and Orders or your own checkout process)
  2. We haven't triggered a Billing Run yet

Billing Runs are used to generate the next Invoice for each of your Subscriptions and are asychronous jobs that you can set up to run on a schedule (e.g., once a day at 1:00am).

For the purposes of this guide however, we're going to start one manually.

In your Postman collection, run the request called Trigger a Billing Run, followed by Check the Billing Run Status.

The first call will schedule a Billing Run to start immediately, where the second one will check the status of that job.

Once your Billing Run has successfully completed, let's take a look at the report meta:

{
"invoices_ready_for_payment": 1,
"invoices_tax_required": 2,
"total_ready_for_payment": {
"EUR": {
"amount": 1400,
"includes_tax": true
}
},
"total_tax_required": {
"GBP": {
"amount": 1200,
"includes_tax": false
},
"USD": {
"amount": 1500,
"includes_tax": false
}
}
}

You'll notice that the Billing Run has reported that there is one invoice ready for payment for €14, and two invoices that require tax to be added for £12 and $15 respectively.

We can also see the invoices it's created in either Commerce Manager (under Subscriptions -> Billing & Payment -> Invoices), or by running List Invoices in Postman.

Take note of the following fields for each Invoice:

  • data.attributes.outstanding - Indicates if an Invoice has been paid (false) or not (true)
  • data.attributes.tax_required - Indicates if an Invoice requires tax to be added (true) or not (false)

You'll notice that all have outstanding set to true, but only the EUR invoice has tax_required set to false.

Step 4 - Triggering a Payment Run without Tax Set

Now, what happens if we try to run a Payment Run without adding tax to those Invoices that require it?

Run the Trigger a Payment Run request and then Check the Payment Run Status until the job is successful.

Let's take a look at our invoices again by running the List Invoices request.

info

You'll notice that only one of our invoices has been marked as outstanding set to false, which is our EUR invoice that had tax included in the price.

The two invoices that required tax to be added are still outstanding, which we'll go over how to do in the next section.

Step 5 - Adding Taxes to Invoices with Tax Runs

While one of our invoices had payment collected, the other two are still outstanding because we've not added any taxes to the invoices yet.

To do this, we need to trigger a Tax Run that will add Tax Items to each of our invoices.

Tax Items in Subscriptions are the same as you get in (Carts & Orders)[https://elasticpath.dev/guides/How-To/Carts/Taxes/create-tax-rates], allowing you to specify a rate that will be added to the base price of the invoice.

{
"code": "NY_SALES_TAX",
"jurisdiction": "New York, USA",
"name": "New York State Sales Tax",
"rate": 0.04,
"type": "tax_item"
}

In a real world scenario, you would want to build an integration that listens to Invoice Created events, checks if tax is required, calculate it, then batches them up to be sent as part of a Tax Run.

For the purposes of this guide however, we're going to do it manually as we only have two invoices that we need to add Taxes for.

If you run the List Invoices request again, copy the id field for each of the invoices that have tax_required set to true, making a note of which invoice is for which currency (one for USD, one for GBP).

Next, go to the Postman request Start a Tax Run and open up the Body section.

Replace each invoice_id with the associated ids you've just copied and run the request.

If you check the status of that Tax Run by running Check the Tax Run Status, you should see meta.report.invoices_updated has been set to 3.

When you go back to look at those invoices in either Commerce Manager or by running List Invoices, tax_required will be set to false and you'll see the Tax Items you've just added to each invoice under data.attributes.tax_items.

Step 6 - Collecting Payment for Invoices with Taxes Added

Finally, let's trigger another Payment Run to collect payment for those Invoices we've just added taxes to.

Run the Trigger a Payment Run request again and then Check the Payment Run Status until the job is successful.

info

If you've been using Elastic Path Payments for this tutorial then payment should have been successfully collected for all of your invoices!

You can check this in either Commerce Manager, or by running List Invoices again.

outstanding will have been set to false for each of your invoices, and if you check Stripe you should find a record of Payment for each of your Subscribers.

You will also have had a subscription_invoice_payment object created for each of your invoices.

Let's check this out.

First, run the Get invoice in Postman. You'll notice it returns one of the three invoices you've just taken payment for, where outstanding is now false.

Next, run Get Payments. You'll see a single subscription_invoice_payment object where success has been marked as true, with some associated meta about what time the payment was collected and the amount paid.

What Have we Learned?

In this guide, we've covered the basic workflow for managing Invoices, Taxes, and Payments in Elastic Path Subscriptions for both Elastic Path Payments and Manual Payments.

You should know how to specify whether a Subscription requires Tax Items to be added to the Invoice before payment can be taken.

You should understand the difference between Payment, Tax, and Billing Runs, and what Tax Items are.

Finally, you should know the differences between Invoices being marked as outstanding and tax_required, and once payment has been collected, how to access the payment record against an Invoice.