Let’s add our first customer, and set them up with a Direct Debit mandate.

  • A customer is a person or company we want to take payments from.
  • A mandate is an authorisation from a customer to take payments from their bank account - once you have a mandate set up, you can charge the customer with future API calls. (A customer can have multiple mandates, but you’ll almost always only want one.)

When setting up a mandate, your setup process (e.g. a set of payment screens on a screen or a paper form) must comply with Direct Debit scheme rules. To make this easy for you, GoCardless hosts secure and fully-compliant payment pages that have been translated into many European languages.

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

The Redirect Flow API lets you use these hosted payment pages. Once your customer enters their bank details, you will be set up with everything you need at once: a customer, a customer bank account, and a mandate.

If you’d like to build your own white-label payment pages, just get in touch.

We’ll use the API to create a redirect flow, generating a URL which we can send our customer to in order to have them set up a mandate.

<?php
require 'vendor/autoload.php';

$client = new \GoCardlessPro\Client([
    // We recommend storing your access token in an
    // environment variable for security
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    // Change me to LIVE when you're ready to go live
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$redirectFlow = $client->redirectFlows()->create([
    "params" => [
        // This will be shown on the payment pages
        "description" => "Wine boxes",
        // Not the access token
        "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
print("ID: " . $redirectFlow->id . "<br />");

print("URL: " . $redirectFlow->redirect_url);
import os
import gocardless_pro

client = gocardless_pro.Client(
    # We recommend storing your access token in an
    # environment variable for security
    access_token=os.environ['GC_ACCESS_TOKEN'],
    # Change this to 'live' when you are ready to go live.
    environment='sandbox'
)

redirect_flow = client.redirect_flows.create(
    params={
        "description" : "Ale Casks", # This will be shown on the payment pages
        "session_token" : "dummy_session_token", # Not the access token
        "success_redirect_url" : "https://developer.gocardless.com/example-redirect-uri/",
        "prefilled_customer": { # Optionally, prefill customer details on the payment page
            "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 - we'll need it when we
# "confirm" the redirect flow later
print("ID: {} ".format(redirect_flow.id))
print("URL: {} ".format(redirect_flow.redirect_url))
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
  # We recommend storing your access token in an
  # environment variable for security
  access_token: ENV['GC_ACCESS_TOKEN'],
  # Remove the following line when you're ready to go live
  environment: :sandbox
)

redirect_flow = client.redirect_flows.create(
  params: {
    description: 'Lager Kegs', # This will be shown on the payment pages
    session_token: 'dummy_session_token', # Not the access token
    success_redirect_url: 'https://developer.gocardless.com/example-redirect-uri/',
    prefilled_customer: { # Optionally, prefill customer details on the payment page
      given_name: 'Tim',
      family_name: 'Rogers',
      email: 'tim@gocardless.com',
      address_line1: '338-346 Goswell Road',
      city: 'London',
      postal_code: 'EC1V 7LQ'
    }
  }
)

# Hold on this ID - we'll need it when we
# "confirm" the redirect flow later
puts "ID: #{redirect_flow.id}"
puts "URL: #{redirect_flow.redirect_url}"
package com.gcintegration;

import com.gocardless.GoCardlessClient;
import com.gocardless.resources.RedirectFlow;

public class CreateRedirectFlow {
    public static void main(String[] args) {
        GoCardlessClient client = GoCardlessClient
            // We recommend storing your access token in an
            // environment variable for security
            .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
            // Change me to LIVE when you're ready to go live
            .withEnvironment(GoCardlessClient.Environment.SANDBOX)
            .build();

        RedirectFlow redirectFlow = client.redirectFlows().create()
            .withDescription("Cider Barrels") // This will be shown on the payment pages.
            .withSessionToken("dummy_session_token") // Not the access token
            .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();
        // Hold on to this ID - you'll need it when you
        // "confirm" the redirect flow later
        System.out.println(redirectFlow.getId());
        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);

In a real integration:

  • You’d set the success_redirect_url to a cheery success page on your website where you’d “complete” the flow using the API (we’ll show you how to do this next), as well as storing the created customer and mandate details.
  • You’d provide a session_token which identifies the user’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.
  • 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.

The redirect_url we’ve just printed (which will look something like https://pay-sandbox.gocardless.com/flow/RE00006GBDVVP3BBCP9Q5318ZVJWE0DN) is where you send your customer to set up their mandate on our secure payment pages.

Try going to the URL printed by your code and completing the setup process - this is exactly what your customers will see. You can use our example bank details rather than your own while working in the sandbox:

  • In the UK, use the sort code 200000 and the account number 55779911
  • 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 number 012345678
  • In New Zealand, use the bank code 12, branch code 3113 and the account number 0003869-00
  • In Canada, use the bank code (Financial Institution number) 0003, branch code (Branch Transit number) 00006 and the account number 0000000
  • In United States of America, use the bank code 026073150, account number 2715500356 and the account type checking
  • Everywhere else, use the French IBAN FR1420041010050500013M02606
When you sign up in the sandbox, we’ll give you access to the Direct Debit scheme most appropriate for your location: Bacs in the UK, ACH in the United States of America, Autogiro in Sweden, Betalingsservice in Denmark, BECS in Australia, BECS NZ in New Zealand and SEPA elsewhere. If you want to use other schemes, just get in touch. You’ll need to have a bank account where you can receive payouts in the relevant currency.

Completing the redirect flow

Once you’ve completed the form, you’ll be redirected back to our example success page. Note that the redirect_flow_id query parameter in the URL matches the ID of the redirect flow object.

Now we’ll use a second API call to “complete” the redirect flow. In a real integration, we’d build our own success page, setting it as the redirect_url, and this page would perform this step.

We’ll need the ID from above, and the session_token we set earlier:

<?php
require 'vendor/autoload.php';

$client = new \GoCardlessPro\Client([
    // We recommend storing your access token in an environment variable for security
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    // Change me to LIVE when you're ready to go live
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$redirectFlow = $client->redirectFlows()->complete(
    "RE00006GBASX53T7KYWT4051FMC0TZA6", //The redirect flow ID from above.
    ["params" => ["session_token" => "dummy_session_token"]]
);

print("Mandate: " . $redirectFlow->links->mandate . "<br />");
// Save this mandate ID for the next section.
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(
    #We recommend storing your access token in an environment variable for
    #security.
    access_token=os.environ['GC_ACCESS_TOKEN'],
    #Change this to 'live' when you are ready to go live.
    environment='sandbox'
)

redirect_flow = client.redirect_flows.complete(
    "RE00006GBASX53T7KYWT4051FMC0TZA6", # The redirect flow ID from above.
    params={
        "session_token": "dummy_session_token"
})

print("Mandate: {}".format(redirect_flow.links.mandate))
# Save this mandate ID for the next section.
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(
	access_token: ENV['GC_ACCESS_TOKEN'],
	environment: :sandbox
)

redirect_flow = client.redirect_flows.complete(
    'RE00006GBASX53T7KYWT4051FMC0TZA6', # The redirect flow ID from above.
    params: { session_token: 'dummy_session_token' })

puts "Mandate: #{redirect_flow.links.mandate}"
# Save this mandate ID for the next section.
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;

public class CompleteRedirectFlow {
    public static void main(String[] args) {
        GoCardlessClient client = GoCardlessClient
            // We recommend storing your access token in an
            // environment variable for security
            .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
            // Change me to LIVE when you're ready to go live
            .withEnvironment(GoCardlessClient.Environment.SANDBOX)
            .build();

        RedirectFlow redirectFlow = client.redirectFlows()
            // The redirect flow ID from above
            .complete("RE00007201VQ3H3HSTM2V02BYG4DPF1S")
            .withSessionToken("dummy_session_token")
            .execute();

        System.out.println(redirectFlow.getLinks().getMandate());
        // Save this mandate ID for the next section.
        System.out.println(redirectFlow.getLinks().getCustomer());

        // Display a confirmation page to your 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.

Keep a note of the mandate ID - you'll need it later. In a real application, you’d write them to a database record associated with your customer.

With the redirect flow completed via the API and the mandate ID stored, show your 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, 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.

GoCardless's ready-made confirmation page

Our provided confirmation page is only available for 15 minutes from the moment when you complete the redirect flow via the API, so you should redirect the customer straight to it.

Let’s try listing our customers again, like we did for our first request. Now, we’ll see the customer we’ve just created:

$customers = $client->customers()->list()->records;
print_r($customers);
customers = client.customers.list().records
print(customers)
print([customer.email for customer in customers])
# `pp` is Ruby's built-in pretty printing functionality
require 'pp'

pp client.customers.list.records
List<Customer> customers = client.customers().list().execute().getItems();
System.out.println(Arrays.toString(customers.toArray()));
const listResponse = await client.customers.list();
const customers = listResponse.customers;
console.log(customers);
var listResponse = await client.Customers.ListAsync();
var customers = listResponse.Customers;
Console.WriteLine("Customers: " + string.Join(", ", customers.Select(c => c.Id)));

Setting up Direct Debit mandates using the Drop-in

Drop-in is in early-access stage. You can read about it here.