Product Updates

How Cronofy integrated the ChartMogul Import API

Over the last few months we’ve been working with Cronofy as a Beta partner for our Import API. In this post, CEO Adam Bird sheds some light on the details of their setup, and the integration process itself.

Cronofy: Powerful calendar infrastructure as a service

Cronofy is an API-based Calendar service which powers a number of top web-based products like Zendesk, Skyscanner and more. The value in their business is in allowing customers to easily integrate calendar-based features to their platform, with support for all of the top calendar services.

Skyscanner homepage
Trip-booking scenarios are just one use case for the Cronofy product. Cronofy drives the calendar features of Skyscanner, for exactly this reason.

We asked Adam Bird, Cronofy’s CEO to give us a detailed rundown of their experience with the ChartMogul Import API.

On building their own billing engine

Cronofy has built their own internal billing system, which handles creation of statements, bills and pricing calculations. They then use Xero (via an API integration) to generate invoices and handle the ever-complex tax calculations.

Cronofy’s pricing model has a number of intricacies that require some thought when it comes to handling the billing data:

Adam: Our standard billing approach is to charge a monthly plan fee for up to a set number of users and then a unit fee per user thereafter. However, we also charge on a pure usage basis for some customers, generally larger accounts, with a threshold-based rate that can result in multiple unit prices as a customer transitions through the usage bands.

Getting started with the Import API

Being a Ruby-based product, the folks at Cronofy immediately looked for a gem to install which would handle communication and authentication with the API itself. Unfortunately this didn’t exist at the time… so they created one! You can find it here on Github.

Adam: ChartMogul’s Import API docs are absolutely the place to start and cover the key concepts you need to understand for a successful integration.

We’d definitely echo Adam’s advice here — read the manual! We’ve put a lot of work into making our documentation and Developer Hub easy to consume, and it’ll walk you through the essential parts of the integration. Of course, we’re always here to help if you get stuck…

The ChartMogul Developer Hub is always the best place to start, when integrating any of the ChartMogul APIs.
The ChartMogul Developer Hub is always the best place to start, when integrating any of the ChartMogul APIs.

The technical details

There are three key objects that are important in the ChartMogul platform: Customers, Plans, Invoices. Pushing billing data into ChartMogul involves creating or modifying instances of these objects.

Creating Customers

Customers are somewhat straightforward. A Customer object represents a “real-life” customer in your subscription product.

Adam’s input here:

You need customer_uuid for the Invoice creation. Make sure you include the country as that gives you access to the regional segmentation features.

You can add an external_id which is enforced unique so will return a 422 Unprocessable Entity if you try and create a duplicate record. I’d love to see the ability to lookup, something like:

GET /v1/import/customers?external_id=12345

and get a 404 to indicate that a customer record needs to be added.

At the moment, when generating an invoice, we have to retrieve the entire Customer list to discover if that customer has been added or not.

Defining Plans

Every transaction that happens in ChartMogul (i.e. every invoice) must be related to a plan. Plans represent the subscription plan that the customer is subscribed to, and holds important information like the billing interval.

In Adam’s words:

Plan definition for us was really just about the name. We only needed a monthly interval for any of our plans. An Invoice comprises a series of line_items, each of which is assigned to a plan. This is used to generate a subscription for that customer, which in turn is rendered in the Chart Mogul UI.

Similarly to Customers, you have to ensure a plan has been imported via /v1/import/plans before it can be used in a line_item. In our code we lazy insert plans at the point of importing Invoices, which means we don’t have to worry about coordinating a two-part sync.

Our method for this is similar to the following:

def get_plan_uuid
  @plans ||= Hash[chart_mogul
            .list_plans
            .map { |p| [p.external_id, p.uuid] }]

  unless @plans[plan_id]
    record = {
      external_id: plan_id,
      data_source_uuid: chart_mogul_data_source_uuid,
      name: plan_id,
      interval_count: 1,
      interval_unit: :month,
    }

    plan = chart_mogul.import_plan(record)
    @plans[plan_id] = plan.uuid
  end

  @plans[plan_id]
end

Importing invoices

The Invoice is the all-important object in ChartMogul which holds information related to the customer’s purchase of your service. Invoices are comprised of:

  • One or more Line Items, which represent the kind of service or product being billed and contain some details about them.
  • One or more Transactions, which represent charge or refund attempts to the customer.

From these invoices, ChartMogul automatically creates subscriptions and metrics from invoices, so they’re critical to the system!

Adam: In our case I decided to collapse all of our statement lines into one line_item and not worry too much about differentiating between fixed fees and add-ons. This is one of those philosophical points that can be argued either way. The other attribute of line_items to consider is quantity. One little gotcha is if you pass a quantity of zero then this will result in the line_item being ignored by the Subscription, even if the amount_in_cents has a value.

A quick word on overages

Adam: Given the nature of our service we consider overages not as ad-hoc but as MRR. Each unit represents a user whose calendars have been synchronized with our platform. This is an ongoing relationship which generally grows as our customers grow, ultimately resulting in a transition to a high monthly commitment. We do allow customers to automatically transition between plans as their usage grows or shrinks, which makes plan fee + overage fee just feel like a formula for calculating MRR rather than representing different types of revenue.

Final thoughts

We’re hugely grateful to Adam and the Cronofy team for working with us throughout the Import API beta, identifying issues and giving us detailed feedback along the way. With their help, we’ve now shipped the first public release of the API, opening the doors for virtually anyone to push custom billing data into their ChartMogul account.

I’ll leave the final word to Adam:

As we’ve been building out this integration, we’ve wiped away and resynced the data several times to get us to something that we feel represents our business. So we may well restate this in the future — such is the power of being able to visualize your financial data in this way.

Fundamentally, Vinay and the team have given a lot of thought to how to make this work with other systems, have obviously spent a lot of time on the docs and tutorials and have been super responsive whenever I was scratching my head. We’re fully committed users now and look forward to seeing how the service and, especially the Import API, evolves.

The guys at ChartMogul have a built a fantastic solution for SaaS financial KPI reporting. Being able to take advantage of that with what amounts to a custom billing system is inordinately valuable to anyone with a SaaS business.

Ed Shelley

Former Director of Content

@Mr_Ed

api case study customer