Skip to main content

Welcome to our Dev Docs!

Synchronization & Reliability

It is essential to keep your system in sync to billwerk, i.e. you must ensure that if your system delivers the bronze plan to a given customer, Billwerk doesn't charge her for platinum. This gives rise to the typical challenges of distributed computing that require a number of approaches to prevent race conditions.

An important concept used both in signups and up/downgrades is that of orders, or more generally speaking, state management on our server. The following example uses our REST API, but the concepts are also true for SubscriptionJS. Let's look at how an overly naive implementation of an upgrade could look like:

POST /contracts/:contractId/upgrade

{
    "newPlan" : "platinum"
}

Such a call comes with a number of problems:

  • It's not reliable. If you don't receive an answer from our server, you don't know the state without inspecting another resource, the contract. Even then, it's possible you wanted to schedule an upgrade in the future so the plan can't have changed yet, hence the state is unknown to you.

  • It's not idempotent.

  • It's not restful.

Instead, the idea is to create, modify and commit orders:

POST /orders/

{
    "contractId" : ...,
    "newPlan" : ""
}

// idempotent commit operation
POST /orders/:orderId/commit

This way, you can query the order- or commit- status, because the order has an ID, and the actual operation is idempotent. The details are explained in the section upgrades & downgrades [TBD - we might want to show a long 'recipe' for this that comes with a number of examples]. The same argument applies to signups.

If a customer is shown an amount of USD 120,- in step 2 of 3, it is desirable and sometimes required by law to ensure that this is the price that is actually charged when completing the payment. However, because the price could be changed in the mean time and because the price can depend on the checkout time (e.g. a plan that is billed a month in advance but costs per day causes a larger bill in 31-day months than in 30-day months or February), ensuring this on the client is impossible.

Therefore, signups internally work by creating a signup order which is committed by the initial payment, or using a separate commit call if no payment is required.

Also, webhooks help to ensure reliablity by repeating requests a large number of times unless they received a response that indicated some kind of success, i.e. a 2xx HTTP status code. Again, this implies that webhook handlers must be idempotent, because it's possible for them to get called multiple times and in incorrect order.