Direct Debit: Taking Instalment Payments

Using instalment schedules

Finally, let’s try collecting payments using an instalment schedule. Instalment schedules collect a finite set of recurring payments from a customer.

Let’s say we have an invoice for £100. We want to collect this in 3 instalments, with a cadence of 1 instalment every 2 weeks:

1<?php 2require "vendor/autoload.php"; 3 4$client = new \GoCardlessPro\Client([ 5 "access_token" => $currentUser->gocardlessAccessToken, 6 "environment" => \GoCardlessPro\Environment::SANDBOX 7]); 8 9$instalment_schedule = $client->instalmentSchedules()->createWithSchedule([ 10 "params" => [ 11 "name" => "ACME Invoice 103", 12 "total_amount" => 10000, // 100 GBP in pence, collected from the customer 13 "app_fee" => 10, // Your 10 pence fee, applied to each instalment, 14 // to be paid out to you 15 "currency" => "GBP", 16 "schedule" => [ 17 "start_date" => "2019-08-20", 18 "interval_unit" => "weekly", 19 "interval" => "2", 20 "amounts" => [ 21 3400, 22 3400, 23 3200 24 ] 25 ], 26 "links" => [ 27 "mandate" => "MD0000XH9A3T4C" 28 // Mandate ID from the last section 29 ], 30 "metadata" => [] 31 ], 32 "headers" => [ 33 "Idempotency-Key" => "random_instalment_schedule_specific_string" 34 ] 35]); 36 37// Keep hold of this instalment schedule ID - we"ll use it in a minute 38// It should look a bit like "IS00006FWHUIA" 39print("ID: " . $instalment_schedule->id);

GoCardless will take responsibility for calculating the estimated charge dates of these payments. The charge date scheduling semantics are as follows:

  • We will create the first payment as close to the specified start date as possible.

  • The subsequent payment will be as close to two weeks after the specified start date as possible.

The important clarification is that we will always schedule from the originally specified start date, not the realised charge date of the first payment.

We will then debit £34, £34, and £32 from the end customer’s bank account in the 6 weeks following the specified charge date.

Charged on

2019-08-20

2019-09-03

2019-09-17

Amounts charged

£34.00

£34.00

£32.00

Scheduling Instalments

For your convenience, we also provide you with the ability to schedule the payments yourself if you have a specific or irregular cadence with which you’d like to collect instalments:

1<?php 2require "vendor/autoload.php"; 3 4$client = new \GoCardlessPro\Client([ 5 "access_token" => $currentUser->gocardlessAccessToken, 6 "environment" => \GoCardlessPro\Environment::SANDBOX 7]); 8 9$instalment_schedule = $client->instalmentSchedules()->createWithDates([ 10 "params" => [ 11 "name" => "ACME Invoice 103", 12 "total_amount" => 10000, // 100 GBP in pence, collected from the customer 13 "app_fee" => 10, // Your 10 pence fee, applied to each instalment, 14 // to be paid out to you 15 "currency" => 'GBP', 16 "instalments" => [ 17 [ 18 "charge_date" => '2019-08-20', 19 "amount" => 3400 20 ], 21 [ 22 "charge_date" => '2019-09-03', 23 "amount" => 3400 24 ], 25 [ 26 "charge_date" => '2019-09-17', 27 "amount" => 3200 28 ], 29 ], 30 "links" => [ 31 "mandate" => 'MD0000XH9A3T4C' 32 // Mandate ID from the last section 33 ], 34 "metadata" => [] 35 ], 36 "headers" => [ 37 'Idempotency-Key' => 'random_instalment_schedule_specific_string' 38 ] 39]); 40 41// Keep hold of this instalment schedule ID - we'll use it in a minute 42// It should look a bit like "IS00006FWHUIA" 43print("ID: " . $instalment_schedule->id);

We will try to create the payments as close to the charge dates you specify as possible.

The process of setting up all the payments for an instalment schedule is quite expensive. For this reason, the instalment schedule starts off in the “pending” state and remains in this state while we create all the instalments for it. If you want to inspect the created instalment schedule yourself, we can do this using the instalment schedule ID which is returned when making the request to create the schedule:

1GET https://api.gocardless.com/instalment_schedules/IS00006FWHUIA 2 3HTTP/1.1 200 (OK) 4{ 5 "instalment_schedules": { 6 "id": "IS123", 7 "name": "Bike Invoice 271", 8 "currency": "GBP", 9 "status": "pending", 10 "amount": "10000", 11 "metadata": {}, 12 "links": { 13 "mandate": "MD0000XH9A3T4C", 14 "payments": [] 15 } 16 } 17}

This should return the instalment schedule object we just created.

Once all the related payments for an instalment schedule have been created, it will transition into the “active” state. We will send you a webhook to notify you of this change. If you do not wish to rely on webhooks, we’d recommend polling the GET endpoint to check when an instalment schedule becomes active. Once all the instalments for a schedule have been created, their IDs will be included under the payments key in the “links” attribute of the response object.

Listing and cancelling a schedule

Let’s imagine that we no longer want to collect the payment in instalments, and we need to cancel the instalment schedule. This is accomplished as follows:

1<?php 2require 'vendor/autoload.php'; 3 4$client = new \GoCardlessPro\Client([ 5 'access_token' => $currentUser->gocardlessAccessToken, 6 'environment' => \GoCardlessPro\Environment::SANDBOX 7]); 8 9$instalment_schedule = $client->instalment_schedules()->get("IS00006FWHUIA"); 10 // Instalment Schedule ID from above. 11 12print("Status: " . $instalment_schedule->status . "<br />"); 13print("Cancelling...<br />"); 14 15$instalment_schedule = $client->instalment_schedules()->cancel("IS00006FWHUIA"); 16 17print("Status: " . $instalment_schedule->status . "<br />");

Cancelling an instalment schedule will cancel all remaining payments (i.e. payments that are not submitted, collected or failed) in the schedule. If you wish to collect the leftover amount for a given invoice, you can do so by creating a single payment to collect the remainder, or by splitting the remaining amount into a new instalment schedule. Instalment schedules cannot be cancelled if they are already cancelled, or completed. You will receive a webhook notifying you of when the instalment schedule and its remaining payments have been cancelled.

Advice on calculating your instalment amounts

You may have noticed that whilst GoCardless takes responsibility for figuring out the precise dates upon which payments will be collected, we are not prescriptive on how the original invoice amount is split between instalments. How much you charge your customers is, after all, your decision entirely!

We will use the top-level amount parameter as a checksum, to make sure all the individual instalment amounts add up to the right total. With that in mind, it’s crucial for you as the integrator to ensure you’ve worked out the right split between your instalment amounts. Below, we provide a sample algorithm (in pseudocode) to help you accomplish this:

1// @param total - the total in GBP/USD etc. 2// @param number_of_instalments - the number of instalments you'd like to split the 3// invoice into 4 5function calculateInstalmentValue(total, number_of_instalments) 6{ 7 // work out the value of each instalment, rounded up to the nearest whole unit 8 rounded_units = ceiling(total/number_of_instalments) 9 10 if (rounded_units * (number_of_instalments - 1) >= total) { 11 return floor(total / number_of_instalments); 12 } else { 13 return rounded_units; 14 } 15} 16 17// @param total - the invoice total in GBP/USD etc. 18// @param number_of_instalments - the number of instalments you'd like to split the 19// invoice into 20// @param normal_instalment_amount - the amount in pence/cents etc. for all payments 21// except the final 'balancing' payment 22 23function getInstalmentAmounts(total, number_of_instalments, normal_instalment_amount) 24{ 25 number_of_normal_instalments = floor(total / normal_instalment_amount); 26 minimum = 200 // some "reasonable minimum" instalment amount 27 28 amounts = []; 29 30 for (i = 1; i < number_of_normal_instalments; i++) { 31 amounts.push(normal_instalment_amount); 32 } 33 34 remainder = total % normalInstalmentAmount; 35 36 if (remainder < minimum) { 37 amounts[amounts.length - 1] += remainder; 38 } else { 39 amounts.push(remainder); 40 } 41 42 return amounts; 43} 44 45normal_instalment_amount = calculateInstalmentValue(total, number_of_instalments) 46instalment_amounts = getInstalmentAmounts( 47 total, 48 number_of_instalments, 49 normal_instalment_amount 50 )

Instalment schedule modes of failure

There are two distinct “failure” states an instalment schedule can fall into. The first is creation_failed, which indicates we could not create the instalment schedule and its payments. You would be notified of this in the response to the POST create request.

The second is slightly more nuanced and is called errored. This indicates that one or more of the instalments is in a failed state. We will serve you a webhook should this occur, but you will need to reconcile the failed payment(s) yourself.

Taking instalment payments against a mandate

Taking a one-off payment against a mandate

Taking subscription payments against a mandate