You’ll need to provide a way for your users to set up Direct Debit mandates with their customers (whom we’ll refer to from now on as “end customers”) so they can start collecting payments from them.
A mandate allows you to pull money from an end customer’s bank account with a simple API call.
Mechanisms to add customers
You have three options for setting up Direct Debit mandates:
- Use our secure, hosted payment pages: GoCardless provides secure, hosted, mobile-friendly, conversion-optimised payment pages that have been translated into many European languages and comply with the “scheme rules” of the Direct Debit schemes. You redirect the customer to us, they provide their bank details on our site, and then we send them back to your application. You never have to handle end customers’ bank details.
- Use our Drop-in payment page solution: You can use this to host the mandate setup experience within your software, but let us handle the compliance and security aspects. You just need to embed a piece of JavaScript code that will load the experience in your web property, without the need for a redirect.
- Build your own Direct Debit setup process: Rather than use our ready-made flow, you can build your own. If you’d like to do this, please contact our partnerships team who’ll be able to explain the process.
Below is a comparison of the 3 solutions:
GoCardless hosted payment pages (redirect flow) | Drop-in | Custom payment pages | |
---|---|---|---|
What is the payer experience like? | Payer is redirected to pay.gocardless.com/… where the payer puts in bank account details | Payment page opens up in a modal on the integrator’s website. Payer does not leave integrator’s website | Integrator has complete control of UX and the payer does not leave the integrator’s website |
How much engineering work is required to use this? | Minimal engineering work required | Minimal engineering work required | Complex piece of work that requires integrators build payment pages for each scheme |
Who takes care of scheme compliance and when things change? | GoCardless hosts these pages and merchants / partners don’t need to worry about compliance. | GoCardless hosts this modal and integrators don’t need to worry about compliance. | Integrator is responsible for ensuring their payment pages are up-to-date with scheme compliance requirements |
Who is responsible for security? | GoCardless collects all sensitive data (personal and bank account details) in a secure way and integrator does not have to worry about storing them | GoCardless collects all sensitive data (personal and bank account details) in a secure way and integrator does not have to worry about storing them | Integrator needs to collect sensitive data and send them to GoCardless using our API |
What happens when GoCardless adds new features or schemes? | Merchants and partners automatically get any new features or schemes we add | Integrators automatically get any new features or schemes we add | Integrators will have to update their custom payment pages to use newer GoCardless features or add new schemes |
Who is this best suited for? | Merchants and partners who don’t mind the redirect | All merchants and partners want to host payment experience on their website and provide a great experience for their customers | Typically larger merchants and partners who want complete control over UX and don’t mind the technical complexity |
Does the merchant need to be on a certain package to use this? | This is open for all merchants and partners | This is open for all merchants and partners | Only merchants on Pro package and above can build custom payment pages. Partners can build custom payment pages on behalf of merchants who are on any package. Only restriction is partners can only give the same experience for all their merchants. |
Setting up Direct Debit mandates using Hosted Payment Pages
In this section, we’ll take you through using our hosted payment pages, which we call the “Redirect Flow”. To set up a mandate, you’ll generate a link to the Redirect Flow using the API, and send the customer there where they’ll enter their details.
At this point, it’s worth thinking through how your users will want to send their end customers to the Direct Debit setup flow - making this work in a way which suits their workflow and how they use your product will hugely improve their experience. Here are some ideas you might like to consider:
- In KashFlow, end customers can set up a Direct Debit by clicking a button on their invoice
- In GoCardless for Xero, users collecting payments can copy a personalised link to allow a customer to set up a Direct Debit, ready to paste into their own emails or add as a link on their website
- In the GoCardless Dashboard, users collecting payments can send an email to a customer in one click with their own customised copy, asking them to set up a Direct Debit, either for a single customer or for tens or hundreds at a time
You can read some of our suggestions on the best ways for your users to send their end customers to the Direct Debit setup flow in our user experience guide.
Whatever the experience looks like for setting up mandates from your user’s point of view, the code for generating the link looks identical:
<?php
require 'vendor/autoload.php';
$client = new \GoCardlessPro\Client([
// You'll need to identify the user that the customer is paying and fetch their
// access token
'access_token' => $user->gocardlessAccessToken,
// Change me to LIVE when you're ready to go live
'environment' => \GoCardlessPro\Environment::SANDBOX
]);
$redirectFlow = $client->redirectFlows()->create([
"params" => [
// A description of what the Direct Debit is for to be shown to the customer
"description" => "Automatic invoice payments to Acme plc",
// A unique token for the customer's session
"session_token" => "dummy_session_token",
// The URL for a success page you host, to send the customer to when they finish
"success_redirect_url" => "https://developer.gocardless.com/example-redirect-uri/",
// Optionally, prefill customer details on the payment page
"prefilled_customer" => [
"given_name" => "Tim",
"family_name" => "Rogers",
"email" => "tim@gocardless.com",
"address_line1" => "338-346 Goswell Road",
"city" => "London",
"postal_code" => "EC1V 7LQ"
]
]
]);
// You'll need to redirect the end customer to this URL.
print("URL: " . $redirectFlow->redirect_url);
import os
import gocardless_pro
client = gocardless_pro.Client(
# You'll need to identify the user that the customer is paying and fetch their
# access token
access_token=user.gocardless_access_token,
# Change this to 'live' when you are ready to go live.
environment='sandbox'
)
redirect_flow = client.redirect_flows.create(
params={
# A description of what the Direct Debit is for to be shown to the customer
"description" : "Automatic invoice payments to Acme plc",
# A unique token for the customer's session
"session_token" : "dummy_session_token",
# The URL for a success page you host, to send the customer to when they finish
"success_redirect_url" : "https://developer.gocardless.com/example-redirect-uri/",
# Optionally, prefill customer details on the payment page
"prefilled_customer": {
"given_name": "Tim",
"family_name": "Rogers",
"email": "tim@gocardless.com",
"address_line1": "338-346 Goswell Road",
"city": "London",
"postal_code": "EC1V 7LQ"
}
}
)
# You'll need to redirect the end customer to this URL.
print("URL: {} ".format(redirect_flow.redirect_url))
require 'gocardless_pro'
client = GoCardlessPro::Client.new(
# You'll need to identify the user that the customer is paying and fetch their
# access token
access_token: user.gocardless_access_token,
# Remove the following line when you're ready to go live
environment: :sandbox
)
redirect_flow = client.redirect_flows.create(
params: {
# A description of what the Direct Debit is for to be shown to the customer
description: 'Automatic invoice payments to Acme plc',
# A unique token for the customer's session
session_token: 'dummy_session_token',
# The URL for a success page you host, to send the customer to when they finish
success_redirect_url: 'https://developer.gocardless.com/example-redirect-uri/',
# Optionally, prefill customer details on the payment page
prefilled_customer: {
given_name: 'Tim',
family_name: 'Rogers',
email: 'tim@gocardless.com',
address_line1: '338-346 Goswell Road',
city: 'London',
postal_code: 'EC1V 7LQ'
}
}
)
# You'll need to redirect the end customer to this URL.
puts "URL: #{redirect_flow.redirect_url}"
package com.gcintegration;
import com.gocardless.GoCardlessClient;
import com.gocardless.resources.RedirectFlow;
GoCardlessClient client = GoCardlessClient
// You'll need to identify the user that the customer is paying and fetch their
// access token
.newBuilder(CurrentUser.gocardlessAccessToken)
// Change me to LIVE when you're ready to go live
.withEnvironment(GoCardlessClient.Environment.SANDBOX)
.build();
RedirectFlow redirectFlow = client.redirectFlows().create()
// A description of what the Direct Debit is for to be shown to the customer
.withDescription("Automatic invoice payments to Acme plc")
// A unique token for the customer's session
.withSessionToken("dummy_session_token")
// The URL for a success page you host, to send the customer to when they
// finish
.withSuccessRedirectUrl("https://developer.gocardless.com/example-redirect-uri/")
// Optionally, prefill customer details on the payment page
.withPrefilledCustomerGivenName("Tim")
.withPrefilledCustomerFamilyName("Rogers")
.withPrefilledCustomerEmail("tim@gocardless.com")
.withPrefilledCustomerAddressLine1("338-346 Goswell Road")
.withPrefilledCustomerCity("London")
.withPrefilledCustomerPostalCode("EC1V 7LQ")
.execute();
// You'll need to redirect the end customer to this URL.
System.out.println(redirectFlow.getRedirectUrl());
const redirectFlow = await client.redirectFlows.create({
description: "Cider Barrels",
session_token: "dummy_session_token",
success_redirect_url:
"https://developer.gocardless.com/example-redirect-uri/",
// Optionally, prefill customer details on the payment page
prefilled_customer: {
given_name: "Tim",
family_name: "Rogers",
email: "tim@gocardless.com",
address_line1: "338-346 Goswell Road",
city: "London",
postal_code: "EC1V 7LQ"
}
});
// Hold on to this ID - you'll need it when you
// "confirm" the redirect flow later
console.log(redirectFlow.id);
console.log(redirectFlow.redirect_url);
var redirectFlowResponse = await client.RedirectFlows.CreateAsync(new RedirectFlowCreateRequest
{
Description = "Cider Barrels",
SessionToken = "dummy_session_token",
SuccessRedirectUrl = "https://developer.gocardless.com/example-redirect-uri/",
// Optionally, prefill customer details on the payment page
PrefilledCustomer = new RedirectFlowCreateRequest.RedirectFlowPrefilledCustomer
{
GivenName = "Tim",
FamilyName = "Rogers",
Email = "tim@gocardless.com",
AddressLine1 = "338-346 Goswell Road",
City = "London",
PostalCode = "EC1V 7LQ"
}
});
var redirectFlow = redirectFlowResponse.RedirectFlow;
// Hold on to this ID - you'll need it when you
// "confirm" the redirect flow later
Console.WriteLine(redirectFlow.Id);
Console.WriteLine(redirectFlow.RedirectUrl);
You’ll need to customise this code snippet with a few details of your own:
- Substitute in your user’s GoCardless access token, which you stored when they completed the OAuth Flow
- Provide a helpful
description
which will be shown to the end customer, explaning what their payments are for (e.g. “Automatic invoice payments to Acme plc” or “Monthly membership payments to Peckham Pikes Swimming Club”) - Set the
success_redirect_url
to where you want us to send the customer once they’ve finished the Direct Debit setup flow (you’ll need to make an API call from this page to “complete” the redirect flow - this will be explained below) - Pass in a
session_token
which identifies the end customer’s session on your website (for example their session ID in your application). You provide this when creating the redirect flow, and must provide it again when “completing” it at the end. Supplying this token twice makes sure that the person who completed the redirect flow is the person you sent to it. Note: if this token is stored in a cookie, make sure theSameSite
directive is not set; otherwise, on Safari 12, the cookie won’t be sent to your server when we redirect the user tosuccess_redirect_url
(see this issue for more details). - Optionally, you can include a
prefilled_customer
object with your end customer’s details. These will be pre-filled on the payment page so your customer doesn’t have to enter them. For a full list of the details you can provide, head to the API reference.
You’ll get back a URL which will look something like
https://pay-sandbox.gocardless.com/flow/RE00006GBDVVP3BBCP9Q5318ZVJWE0DN
- redirect the
end customer to this link where they’ll be able to enter their details and set up their
mandate.
While you’re testing the mandate setup process in the sandbox, you can use the following sample bank details:
-
In the UK, use the sort code
200000
and the account number55779911
-
In Sweden, use the clearingnummer (branch code)
5491
, the kontonummer (account number)0000003
and the personnummer (Swedish identity number)198112289874
-
In Denmark, use the registreringsnummer (bank code)
345
, the kontonummer (account number)3179681
and the CPR-nummer (Danish identity number)0101701234
-
In Australia, use the BSB
082-082
and the account number012345678
-
In New Zealand, use the bank code
12
, branch code3113
and the account number0003869-00
-
In Canada, use the bank code (Financial Institution number)
0003
, branch code (Branch Transit number)00006
and the account number0000000
-
In United States of America, use the bank code
026073150
, account number2715500356
and the account typechecking
-
Everywhere else, use the French IBAN
FR1420041010050500013M02606
When you’re building an integration with the API, there are some common paths you should make sure your integration handles successfully, for example a customer cancelling their mandate or a payment failing due to lack of funds. We’ll look at handling these cases later.
In the sandbox environment, we provide scenario simulators which allow you to manually trigger certain cases (like a customer cancelling their mandate or a payment failing due to insufficient funds) from the Dashboard so you can test how your integration responds.
Completing the redirect-flow
Once the end customer finishes filling out our payment pages, they’ll be redirected to
your success_redirect_url
. On this page, you’ll need to use a second API call to
“complete” the redirect flow. You’ll need the ID of the redirect flow, passed to you in
the redirect_flow_id
query parameter, plus the session_token
we set earlier:
<?php
require 'vendor/autoload.php';
$client = new \GoCardlessPro\Client([
// You'll need to identify the user that the customer is paying and fetch their
// access token - you might store this in the end customer's session, for example
'access_token' => $user->gocardlessAccessToken,
// Change me to LIVE when you're ready to go live
'environment' => \GoCardlessPro\Environment::SANDBOX
]);
$redirectFlow = $client->redirectFlows()->complete(
$_GET['redirect_flow_id'], // The value of the `redirect_flow_id` query parameter
["params" =>
["session_token" => "dummy_session_token"] // The session token specified earlier
]
);
// Store the mandate ID against the customer's database record so you can charge
// them in future
print("Mandate: " . $redirectFlow->links->mandate . "<br />");
print("Customer: " . $redirectFlow->links->customer . "<br />");
// Display a confirmation page to the customer, telling them their Direct Debit has been
// set up. You could build your own, or use ours, which shows all the relevant
// information and is translated into all the languages we support.
print("Confirmation URL: " . $redirectFlow->confirmation_url . "<br />");
import os
import gocardless_pro
client = gocardless_pro.Client(
# You'll need to identify the user that the customer is paying and fetch their access
# token - you might store this in the end customer's session, for example
access_token=user.gocardless_access_token,
#Change this to 'live' when you are ready to go live.
environment='sandbox'
)
redirect_flow = client.redirect_flows.complete(
"RE00006GBASX53T7KYWT4051FMC0TZA6", # The value of the `redirect_flow_id` query parameter
params={
"session_token": "dummy_session_token" // The session token you specified earlier
})
# Store the mandate ID against the customer's database record so you can charge them in
# future
print("Mandate: {}".format(redirect_flow.links.mandate))
print("Customer: {}".format(redirect_flow.links.customer))
# Display a confirmation page to the customer, telling them their Direct Debit has been
# set up. You could build your own, or use ours, which shows all the relevant
# information and is translated into all the languages we support.
print("Confirmation URL: {}".format(redirect_flow.confirmation_url))
require 'gocardless_pro'
client = GoCardlessPro::Client.new(
# You'll need to identify the user that the customer is paying and fetch their access
# token - you might store this in the end customer's session, for example
access_token: user.gocardless_access_token,
environment: :sandbox
)
redirect_flow = client.redirect_flows.complete(
params['redirect_flow_id'], # The value of the `redirect_flow_id` query parameter
params: { session_token: 'dummy_session_token' }) # The session token you specified earlier
# Store the mandate ID against the customer's database record so you can charge them in
# future
puts "Mandate: #{redirect_flow.links.mandate}"
puts "Customer: #{redirect_flow.links.customer}"
# Display a confirmation page to the customer, telling them their Direct Debit has been
# set up. You could build your own, or use ours, which shows all the relevant
# information and is translated into all the languages we support.
puts "Confirmation URL: #{redirect_flow.confirmation_url}"
package com.gcintegration;
import com.gocardless.GoCardlessClient;
import com.gocardless.resources.RedirectFlow;
GoCardlessClient client = GoCardlessClient
// You'll need to identify the user that the customer is paying and fetch their
// access token - you might store this in the end customer's session, for example
.newBuilder(user.gocardlessAccessToken)
// Change me to LIVE when you're ready to go live
.withEnvironment(GoCardlessClient.Environment.SANDBOX)
.build();
RedirectFlow redirectFlow = client.redirectFlows()
.complete("RE00007201VQ3H3HSTM2V02BYG4DPF1S")
// The value of the `redirect_flow_id` query parameter
.withSessionToken("dummy_session_token")
// The session token you specified earlier
.execute();
// Store the mandate ID against the customer's database record so you can charge
// them in future
System.out.println(redirectFlow.getLinks().getMandate());
System.out.println(redirectFlow.getLinks().getCustomer());
// Display a confirmation page to the customer, telling them their Direct Debit has been
// set up. You could build your own, or use ours, which shows all the relevant
// information and is translated into all the languages we support.
System.out.println(redirectFlow.getConfirmationUrl());
const redirectFlow = await client.redirectFlows.complete(
"RE00007201VQ3H3HSTM2V02BYG4DPF1S",
{
session_token: "dummy_session_token"
}
);
// Store the mandate ID against the customer's database record so you can charge
// them in future
console.log(`Mandate: ${redirectFlow.links.mandate}`);
console.log(`Customer: ${redirectFlow.links.customer}`);
// Display a confirmation page to the customer, telling them their Direct Debit has been
// set up. You could build your own, or use ours, which shows all the relevant
// information and is translated into all the languages we support.
console.log(`Confirmation URL: ${redirectFlow.confirmation_url}`);
var redirectFlowResponse = await client.RedirectFlows
.CompleteAsync("RE00007201VQ3H3HSTM2V02BYG4DPF1S",
new RedirectFlowCompleteRequest
{
SessionToken = "dummy_session_token"
}
);
var redirectFlow = redirectFlowResponse.RedirectFlow;
// Store the mandate ID against the customer's database record so you can charge
// them in future
Console.WriteLine($"Mandate: {redirectFlow.Links.Mandate}");
Console.WriteLine($"Customer: {redirectFlow.Links.Customer}");
// Display a confirmation page to the customer, telling them their Direct Debit has been
// set up. You could build your own, or use ours, which shows all the relevant
// information and is translated into all the languages we support.
Console.WriteLine($"Confirmation URL: {redirectFlow.ConfirmationUrl}");
The complete
method returns the redirect flow object, now including details of the
mandate, customer and customer bank account that have been created.
You’ll want to store the mandate ID in your database, associated with the end customer (for example, if you’re building an product for managing memberships to a sports club, you’d store it in the database attached to the database record representing the member). We’d suggest storing the mandates in a separate database table so you can more easily keep track of mandates over their whole lifecycle and handle multiple mandates per customer - we’ll learn more about that later.
With the redirect flow completed and the mandate ID stored, show the end customer a clear confirmation page telling them that their Direct Debit has been set up, and what will happen next.
You could build your own (we’ve included some more thoughts on this in our
user experience guide), or you could use our pre-made one which comes ready
translated into all the languages we support - just redirect the customer to the URL
found in the confirmation_url
attribute of the redirect flow.
Setting up Direct Debit mandates using the Drop-in
Drop-in is in early-access stage. You can read about it here.