This guide explains how to ‘complete’ each of the actions that may be required as part of a Billing Request.

Only integrators who build their own payment pages should follow this guide.

In order to access the following end points and complete the required actions integrators will need the custom payment pages upgrade enabled on their account.

Billing Request Flows provide a GoCardless hosted checkout flow that can fulfil Billing Requests, without integrators having to build their own flows.

What are actions?

Whenever you create a Billing Request, it will have a list of actions that require completing before it’s possible to fulfil the request.

The possible actions are:

  • collect_customer_details, collect customer details required for the schemes
  • collect_bank_account, create the bank account for the mandate/payment
  • bank_authorisation, have the payer authorise the billing request via their bank if required
  • confirm_payer_details, confirm customer and bank account details provided by the payer

Once all required actions have been completed, the Billing Request will become ready_to_fulfil, and an integrator can use the fulfil action to create all associated resources.

Which actions should I implement?

Integrators should think carefully before choosing to build their own flows. GoCardless offer Billing Request Flows that provide a hosted checkout flow that can walk a payer through all the actions required to complete their Billing Request, and have been optimised to maximise conversion.

Even if integrators complete a selection of actions themselves, Billing Request Flows can be used to complete the remaining actions.

Our recommendations for whether integrators should implement each action are:

  • collect_customer_details, implement this if you want a whitelabel flow to collect customer details or have already collected the details (pre-filling, etc)
  • collect_bank_account, as with customer details, but be aware that Billing Request Flows can avoid this step for certain schemes which can improve conversion by reducing the amount of details a payer has to manually input
  • confirm_payer_details, As part of scheme compliance it is a requirement to allow the payer to crosscheck the details entered by them and confirm it.
  • bank_authorisation, should be handled via the Billing Request Flow

Ordering and control flow

The actions presented on a Billing Request are unordered, but each action may have dependencies, or have other actions depending on it. These are specified in the fields completes_actions and requires_actions.

Taking a bank_authorisation as an example:

{
  "type": "bank_authorisation",
  "status": "completed",
  "required": true,
  "completes_actions": [
    "collect_customer_details"
  ],
  "requires_actions": [
    "collect_bank_account"
  ]
}

Action status is either pending or completed. Actions can only be executed if the actions listed in requires_action have been completed- in this example, we can’t complete the bank authorisation until we’ve collected the bank.

Actions can complete other actions, which can help streamline checkout flows. The example shows how a bank authorisation might collect customer details, completing that action as a side effect.

Only actions that are required must be completed before fulfilling a request, any other actions are optional.

For most integrators, we suggest building flows that process actions in the order of:

  1. collect_customer_details, so customer contact details are prioritised
  2. collect_bank_account, if it is required and another action won’t complete it
  3. bank_authorisation, as the penultimate step before completing the checkout flow
  4. confirm_payer_details, only applicable if it is a mandate_request

The hosted checkout flow provided by Billing Request Flows is built to optimise conversion, and will follow the minimum number of steps to fulfil the Billing Request. Most integrators should lean on the flow to complete anything beyond collection of customer details.

Action: collect_customer_details

Billing Requests aim to create billing resources against a customer, either a Direct Debit mandate, an Instant Bank Payment, or both.

Payment schemes vary in what customer details you are required to collect. The collect_customer_details action is about collecting all the details required by either the mandate or the payment scheme, to ensure we meet regulatory needs.

As an example, we can create a Billing Request for a GBP mandate:

POST /billing_requests
{
  "billing_requests": {
    "mandate_request": {
       "currency": "GBP"
    }
  }
}

This returns a Billing Request that looks like this:

{
  "billing_requests": {
    "id": "BRQ000010NMDMH2",
    "status": "pending",
    "mandate_request": {
      "currency": "GBP"
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010P52VRF"
    },
    "actions": [
      {
        "type": "collect_customer_details",
        "required": true,
        "completes_actions": [],
        "requires_actions": [
          "choose_currency"
        ],
        "status": "pending",
        "collect_customer_details": {
          "incomplete_fields": {
            "customer": [
              "email",
              "given_name",
              "family_name"
            ],
            "customer_billing_detail": [
              "address_line1",
              "city",
              "postal_code",
              "country_code"
            ]
          }
        }
      },
      ...,
    ],
    "resources": {
      "customer": {
        "id": "CU00016WDAM7BS",
        "created_at": "2021-04-08T14:06:30.977Z",
        "email": null,
        "given_name": null,
        "family_name": null,
        "company_name": null,
        "language": "en",
        "phone_number": null,
        "metadata": {}
      },
      "customer_billing_detail": {
        "id": "CBD000010P52VRF",
        "created_at": "2021-04-08T14:06:30.997Z",
        "address_line1": null,
        "address_line2": null,
        "address_line3": null,
        "city": null,
        "region": null,
        "postal_code": null,
        "country_code": null,
        "swedish_identity_number": null,
        "danish_identity_number": null
      }
    }
  }
}

Note that:

  • There is a collect_customer_details action, which is pending
  • A new customer has been created for us, as the Billing Request wasn’t attached to an existing customer
  • The customer and customer_billing_detail resources are presented back to us, and they have no filled fields

The collect_customer_details action is designed to help us collect the required information from our customer.

Taking a closer look at the action:

{
  "type": "collect_customer_details",
  "required": true,
  "completes_actions": [],
  "requires_actions": [
    "choose_currency"
  ],
  "status": "pending",
  "collect_customer_details": {
    "incomplete_fields": {
      "customer": [
        "email",
        "given_name",
        "family_name"
      ],
      "customer_billing_detail": [
        "address_line1",
        "city",
        "postal_code",
        "country_code"
      ]
    }
  }
}

The collect_customer_details.incomplete_fields object tells us what fields we need to collect, for both resources. Which fields are required changes depending on the schemes of the mandate (or payment).

We can complete this action by POST’ing to the Collect customer details for the billing request endpoint:

POST /billing_requests/BRQ000010NMDMH2/actions/collect_customer_details HTTP/1.1
{
  "data": {
    "customer": {
      "email": "paddington@bearthings.com",
      "given_name": "Paddington",
      "family_name": "Bear"
    },
    "customer_billing_detail": {
      "address_line1": "32 Windsor Gardens",
      "city": "London",
      "postal_code": "W9 3RG",
      "country_code": "GB"
    }
  }
}

As with all action endpoints, the response is the Billing Request. What we get back is:

{
  "billing_requests": {
    "id": "BRQ000010NMDMH2",
    "status": "pending",
    "mandate_request": {
      "currency": "GBP",
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010P52VRF"
    },
    "actions": [
      {
        "type": "collect_customer_details",
        "required": true,
        "completes_actions": [],
        "requires_actions": [
          "choose_currency"
        ],
        "status": "completed",
        "collect_customer_details": {
          "incomplete_fields": {
            "customer": [],
            "customer_billing_detail": []
          }
        }
      },
      ...,
    ],
    "resources": {
      "customer": {
        "id": "CU00016WDAM7BS",
        "created_at": "2021-04-08T14:06:30.977Z",
        "email": "paddington@bearthings.com",
        "given_name": "Paddington",
        "family_name": "Bear",
        "company_name": null,
        "language": "en",
        "phone_number": null,
        "metadata": {}
      },
      "customer_billing_detail": {
        "id": "CBD000010P52VRF",
        "created_at": "2021-04-08T14:06:30.997Z",
        "address_line1": "32 Windsor Gardens",
        "address_line2": null,
        "address_line3": null,
        "city": "London",
        "region": null,
        "postal_code": "W9 3RG",
        "country_code": "GB",
        "swedish_identity_number": null,
        "danish_identity_number": null
      }
    }
  }
}

Note that:

  • The collect_customer_details action is now completed, meaning we can move on to other actions
  • As a result of us collecting the details, our customer and customer_billing_detail has been populated with the details we collected

Most integrators will collect these details via web forms, filled by their payers. Integrators are expected to build forms that can collect all possible customer and customer_billing_detail fields (see the Collect customer details schema) but only display the inputs required, as per incomplete_fields.

Action: collect_bank_account

Depending on the scheme, we might need to collect bank account before fulfilling the Billing Request. An example is a Direct Debit mandate, where we need to capture the payer’s bank in order to create Direct Debit payments against them.

As an example, we can create a Billing Request for a GBP mandate:

POST /billing_requests
{
  "billing_requests": {
    "mandate_request": {
       "currency": "GBP"
    }
  }
}

This returns a Billing Request that looks like:

{
  "billing_requests": {
    "id": "BRQ000010NMDMH2",
    "status": "pending",
    "mandate_request": {
      "currency": "GBP",
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010PAJ810"
    },
    "actions": [
      {
        "type": "collect_bank_account",
        "required": true,
        "completes_actions": [
          "choose_currency"
        ],
        "requires_actions": [],
        "status": "pending"
      },
      ...,
    ],
  }
}

Note that:

  • There is a collect_bank_account action that is pending
  • We have no links.customer_bank_account, confirming no bank account is attached

We can complete this action by POST’ing to the Collect bank account for the billing request endpoint:

POST /billing_requests/BRQ000010NMDMH2/actions/collect_bank_account HTTP/1.1
{                     
  "data": {          
    "account_number": "11223344",
    "branch_code": "040004",       
    "account_holder_name": "Paddington Bear",                  
    "country_code": "GB"                                       
  }                      
}   

As with all action endpoints, the response is the Billing Request. What we get back is:

{
  "billing_requests": {
    "id": "BRQ000010NMDMH2",
    "status": "ready_to_fulfil",
    "mandate_request": {
      "currency": "GBP"
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010P52VRF",
      "customer_bank_account": "BA0000QDWEEAFB"
    },
    "actions": [
      {
        "type": "collect_bank_account",
        "required": true,
        "completes_actions": [
          "choose_currency"
        ],
        "requires_actions": [],
        "status": "completed"
      },
      ...,
    ],
    "resources": {
      "customer_bank_account": {
        "id": "BA0000QDWEEAFB",
        "created_at": "2021-04-08T15:30:36.019Z",
        "account_number_ending": "51",
        "account_holder_name": "PADDINGTON BEAR",
        "account_type": null,
        "bank_name": "MONZO BANK LIMITED",
        "currency": "GBP",
        "country_code": "GB",
        "metadata": {},
        "enabled": true,
        "links": {
          "customer": "CU00016WDAM7BS"
        }
      }
    }
  }
}

Note that:

  • The collect_bank_account action is now completed, meaning we can move on to other actions
  • As a result of us collecting the bank account, we have created a customer_bank_account resource, and you can see the links.customer_bank_account ID has been set

We advise most integrators use Billing Request Flows to complete this action, as the hosted flows will try skipping this action if it can be fulfilled by another (such as bank authorisation).

Action: bank_authorisation

One of the most complex actions, bank_authorisation means the payer needs to log in to their bank to authorise the Billing Request. All Instant Bank Pay schemes will require this action, while mandate only requests may offer an optional bank_authorisation (coming soon!).

If an integrator has whitelabelled the other actions, they should create a Billing Request Flow to handle the bank_authorisation, as we have invested significant time to optimise the flow.

As an example, we can create a Billing Request for a £0.10 payment:

POST /billing_requests
{
  "billing_requests": {
    "payment_request": {
       "currency": "GBP",
       "amount": 10,
       "description": "Large pot of Marmalade"
    }
  }
}

This returns a Billing Request that looks like:

{
  "billing_requests": {
    "id": "BRQ000010NVSP5H",
    "status": "pending",
    "payment_request": {
      "description": "Large pot of Marmalade",
      "currency": "GBP",
      "amount": 10,
      "scheme": "faster_payments",
    },
    "actions": [
      {
        "type": "bank_authorisation",
        "required": true,
        "completes_actions": [],
        "requires_actions": [
          "collect_bank_account"
        ],
        "status": "pending"
      },
      ...,
    ]
  }
}

Note that:

  • There is a bank_authorisation action which is pending
  • The action is required- all requests with Instant Bank Payments will require bank authorisation
  • The action requires collect_bank_account, as we can only authorise the payment after we have collected bank.

To ask a payer to authorise the payment, we need to know which institution provides the bank we set via collect_bank_account.

Integrators should present a list of institutions to the payer, which they can populate from the List Institutions endpoint:

GET /institutions HTTP/1.1

Which responds with the institutions that GoCardless supports for bank authorisation:

{
  "institutions": [
    {
      "id": "monzo",
      "name": "Monzo",
      "logo_url": "https://assets.gocardless.com/icon",
      "icon_url": "https://assets.gocardless.com/icon"
    }
  ]
}

Once the payer has selected their institution, we generate an authorisation using the Create a Bank Authorisation endpoint:

POST /bank_authorisations HTTP/1.1
{
  "bank_authorisations": {
    "authorisation_type": "payment",
    "links": {
      "institution": "monzo",
      "billing_request": "BRQ000010NVSP5H"
    }
  }
}

This request will contact the payers bank directly. In this example, we’ll be talking with Monzo bank to create an authorisation flow. It is worth noting that banks have varying reliability for open-banking requests, and this request may fail due to the retail bank being unavailable.

If successful, we’ll respond with:

{
  "bank_authorisations": {
    "id": "BAU123",
    "url": "https://verify.monzo.com/open-banking/authorize?client_id=oauth2client_00000000ab123arIZM7Pr1",
    "authorisation_type": "payment",
    "last_visited_at": null,
    "expires_at": "2021-03-25T17:41:28.000Z",
    "redirect_uri": "https://pay.gocardless.com/open_banking/static/thankyou",
    "links": {
      "institution": "monzo",
      "billing_request": "BRQ000010NVSP5H"
    }
  }
}

Payers will be redirected to the url in this response, which will open the payer’s bank login screen. If opened on a mobile with the retail bank app installed, it’s possible the payer will jump straight into the app to authorise the payment.

The bank authorisation is queryable, and will be updated once the payer authorises/denies the request. Integrators should have their checkout flows poll the Get a Bank Authorisation endpoint until the authorised_at timestamp is set.

Once the authorisation is complete, the Billing Request will update to mark the action as completed:

{
  "billing_requests": {
    "id": "BRQ000010NVSP5H",
    "status": "ready_to_fulfil",
    "payment_request": {
      "description": "Large pot of Marmalade",
      "currency": "GBP",
      "amount": 10,
      "scheme": "faster_payments",
    },
    "actions": [
      {
        "type": "bank_authorisation",
        "required": true,
        "completes_actions": [],
        "requires_actions": [
          "collect_bank_account"
        ],
        "status": "completed"
      },
      ...,
    ]
  }
}

Action: confirm_payer_details

As part of scheme compliance we need to ensure payer was presented with a confirmation screen before fulfilling the Billing Request. All mandate requests will require this action.

As an example, we can create a Billing Request for a GBP mandate:

POST /billing_requests
{
  "billing_requests": {
    "mandate_request": {
       "currency": "GBP"
    }
  }
}

This returns a Billing Request that looks like:

{
  "billing_requests": {
    "id": "BRQ000010NMDMH2",
    "status": "pending",
    "mandate_request": {
      "currency": "GBP",
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010PAJ810"
    },
    "actions": [
      {
          "type": "confirm_payer_details",
          "required": true,
          "completes_actions": [],
          "requires_actions": [
              "collect_customer_details",
              "collect_bank_account"
          ],
          "status": "pending"
      }
      ...,
    ],
  }
}

Note that:

  • There is a confirm_payer_details action that is pending
  • The action is required - all mandate requests will require this
  • The action requires collect_customer_details and collect_bank_account, as we can only show the confirmation page once these actions are completed.

We can complete this action by POST’ing to the confirm payer details endpoint:

POST /billing_requests/BRQ000010NMDMH2/actions/confirm_payer_details HTTP/1.1
{                     
  "data": {}                      
}   

As with all action endpoints, the response is the Billing Request. What we get back is:

{
  "billing_requests": {
    "id": "BRQ000010NMDMH2",
    "status": "ready_to_fulfil",
    "mandate_request": {
      "currency": "GBP"
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010P52VRF",
      "customer_bank_account": "BA0000QDWEEAFB"
    },
    "actions": [
      {
        "type": "confirm_payer_details",
        "required": true,
        "completes_actions": [],
        "requires_actions": [
            "collect_customer_details",
            "collect_bank_account"
        ],
        "status": "completed"
      },
      ...,
    ],
    "resources": {
      ..., 
     }
    }
  }
}

Note that:

  • The confirm_payer_details action is now completed, and billing request is ready_to_fulfil meaning we can call the fulfil endpoint to complete the transaction.

We advise most integrators to use Billing Request Flows to complete this action, as information presented in confirmation screen changes depending on the scheme.

How to implement actions?

In order to automatically recieve new features and always remain scheme compliant without having to change your integration, GoCardless will need to adjust actions by adding new actions or making optional actions required. This means it will break your integration if you don’t fallback to Billing Request Flow.

Therefore anyone building custom payment pages needs to:

  • Implement the actions you are aware of and want to process.
  • If you reach the last action and the Billing Request is still pending (as opposed to ready_to_fulfil or fulfilled), then you need to create a Billing Request Flow and send the payers through that flow.