GoCardlessDeveloper Docs
Create a sandbox account

JavaScript Drop-in Flow#

View as Markdown

Embed a pre-built payment flow directly in your website. The customer completes mandate setup and payment authorisation without leaving your domain.

Supports: Direct Debit only. Does not support Pay By Bank or Commercial VRP. For these payments, use Hosted Pages or Custom Payment Pages.

Best for#

  • Keeping customers on your site throughout the payment flow
  • Moderate customisation with less development than a full custom build
  • Modern web applications (React, Vue, etc.)
  • Balance between speed of implementation and control

How it works#

  • Create a Billing Request and Billing Request Flow via the API (same as Hosted Pages)
  • Include the GoCardless Drop-in JavaScript library on your page
  • Initialise the component with the flow ID
  • The component renders the payment flow inline on your page
  • Listen for completion events and webhooks

Customisation#

  • Style the component to match your brand colours and fonts
  • Control the container element and placement
  • Handle events (success, exit, error) in your application code

Step-by-step guide#

Create a billing request#

The Billing Request defines what you're collecting.

POST https://api.gocardless.com/billing_requests HTTP/1.1
{
  "billing_requests": {
    "mandate_request": {
        "scheme": "bacs"
    }
  }
}
$client = new \GoCardlessPro\Client(array(
  'access_token' => 'your_access_token_here',
  'environment'  => \GoCardlessPro\Environment::SANDBOX
));
 
$client->billingRequests()->create([
"params" => [
"mandate_request" => [
"scheme" => "bacs"
]
]
]);
 
import gocardless_pro
client = gocardless_pro.Client(access_token="your_access_token_here", environment='sandbox')
 
client.billing_requests.create(params={
  "mandate_request": {
    "scheme": "bacs"
  }
})
@client = GoCardlessPro::Client.new(
  access_token: "your_access_token",
  environment: :sandbox
)
 
@client.billing_requests.create(
  params: {
    mandate_request: {
      scheme: "bacs"
    }
  }
)
import static com.gocardless.GoCardlessClient.Environment.SANDBOX;
String accessToken = "your_access_token_here";
GoCardlessClient client = GoCardlessClient
    .newBuilder(accessToken)
    .withEnvironment(SANDBOX)
    .build();
 
BillingRequest billingRequest = client.billingRequests().create()
  .withMandateRequestScheme("bacs")
  .execute();
const constants = require("gocardless-nodejs/constants");
const gocardless = require("gocardless-nodejs");
const client = gocardless("your_access_token_here", constants.Environments.Sandbox);
 
const billingRequest = await client.billingRequests.create({
  mandate_request: {
    scheme: "bacs",
  },
});
String accessToken = "your_access_token";
GoCardlessClient gocardless = GoCardlessClient.Create(accessToken, Environment.SANDBOX);
 
var mandateRequest = new GoCardless.Services.BillingRequestCreateRequest.BillingRequestMandateRequest
{
  Scheme = "bacs",
};
 
var resp = await gocardless.BillingRequests.CreateAsync(
  new GoCardless.Services.BillingRequestCreateRequest()
  {
    MandateRequest = mandateRequest,
  }
);
 
GoCardless.Resources.BillingRequest billingRequest = resp.BillingRequest;
package main
 
import (
	gocardless "github.com/gocardless/gocardless-pro-go/v6"
)
 
accessToken := "your_access_token_here"
opts := gocardless.WithEndpoint(gocardless.SandboxEndpoint)
config, err := gocardless.NewConfig(accessToken, opts)
if err != nil {
	fmt.Printf("got err in initialising config: %s", err.Error())
	return
}
client, err := gocardless.New(config)
if err != nil {
	fmt.Println("error in initialisating client: %s", err.Error())
	return
}
 
billingRequestCreateParams := gocardless.BillingRequestCreateParams{
	MandateRequest: &gocardless.BillingRequestCreateParamsMandateRequest{
		Scheme: "bacs",
  	},
}
 
billingRequest, err := client.BillingRequests.Create(context, billingRequestCreateParams)
gc create billing_request \
  -d 'mandate_request[scheme]=bacs'

Response:

{
  "billing_requests": {
    "id": "BRQ123",
    "status": "pending",
    "payment_request": null,
    "mandate_request": {
      "currency": "GBP",
      "scheme": "bacs"
    },
    "links": {
      "customer": "CU00016WDAM7BS",
      "customer_billing_detail": "CBD000010PDF4WD",
      "mandate_request": "MRQ123",
      "organisation": "OR123"
    },
    "actions": [
      {
        "type": "collect_customer_details",
        "status": "pending"
      },
      {
        "type": "collect_bank_account",
        "status": "pending"
      }
    ]
  }
}

Create a billing request flow#

This generates the hosted URL where the customer completes authorisation.

POST https://api.gocardless.com/billing_request_flows HTTP/1.1
{
  "billing_request_flows": {
    "redirect_uri": "https://my-company.com/landing",
    "exit_uri": "https://my-company.com/exit",
    "links": {
      "billing_request": "BRQ000010NMDMH2"
    }
  }
}
$client = new \GoCardlessPro\Client(array(
  'access_token' => 'your_access_token_here',
  'environment'  => \GoCardlessPro\Environment::SANDBOX
));
 
$client->billingRequestFlows()->create([
"params" => [
"redirect_uri" => "https://my-company.com/landing",
"exit_uri" => "https://my-company.com/exit",
"links" => [
"billing_request" => "BRQ000010NMDMH2"
]
]
]);
 
import gocardless_pro
client = gocardless_pro.Client(access_token="your_access_token_here", environment='sandbox')
 
client.billing_request_flows.create(params={
  "redirect_uri": "https://my-company.com/landing",
  "exit_uri": "https://my-company.com/exit",
  "links": {
    "billing_request": "BRQ000010NMDMH2"
  }
})
@client = GoCardlessPro::Client.new(
  access_token: "your_access_token",
  environment: :sandbox
)
 
@client.billing_request_flows.create(
  params: {
    redirect_uri: "https://my-company.com/landing",
    exit_uri: "https://my-company.com/exit",
    links: {
      billing_request: "BRQ000010NMDMH2",
    }
  }
)
import static com.gocardless.GoCardlessClient.Environment.SANDBOX;
String accessToken = "your_access_token_here";
GoCardlessClient client = GoCardlessClient
    .newBuilder(accessToken)
    .withEnvironment(SANDBOX)
    .build();
 
BillingRequestFlow billingRequestFlow = client.billingRequestFlows().create()
  .withRedirectUri("https://my-company.com/landing")
  .withExitUri("https://my-company.com/exit")
  .withLinksBillingRequest("BRQ000010NMDMH2")
  .execute();
const constants = require("gocardless-nodejs/constants");
const gocardless = require("gocardless-nodejs");
const client = gocardless("your_access_token_here", constants.Environments.Sandbox);
 
const billingRequestFlow = await client.billingRequestFlows.create({
  redirect_uri: "https://my-company.com/landing",
  exit_uri: "https://my-company.com/exit",
  links: {
    billing_request: "BRQ000010NMDMH2",
  },
});
String accessToken = "your_access_token";
GoCardlessClient gocardless = GoCardlessClient.Create(accessToken, Environment.SANDBOX);
 
var resp = await gocardless.BillingRequestFlows.CreateAsync(
  new GoCardless.Services.BillingRequestFlowCreateRequest()
  {
    RedirectUri = "https://my-company.com/landing",
    ExitUri = "https://my-company.com/exit",
    Links = new GoCardless.Services.BillingRequestFlowCreateRequest.BillingRequestFlowLinks {
      BillingRequest = "BRQ000010NMDMH2",
    },
  }
);
 
GoCardless.Resources.BillingRequestFlow billingRequestFlow = resp.BillingRequestFlow;
package main
 
import (
	gocardless "github.com/gocardless/gocardless-pro-go/v6"
)
 
accessToken := "your_access_token_here";
opts := gocardless.WithEndpoint(gocardless.SandboxEndpoint)
client, err := gocardless.New(accessToken, opts)
 
billingRequestFlowCreateParams := gocardless.BillingRequestFlowCreateParams{}
billingRequestFlowCreateParams.RedirectUri = "https://my-company.com/landing"
billingRequestFlowCreateParams.ExitUri = "https://my-company.com/exit"
billingRequestFlowCreateParams.Links.BillingRequest = "BRQ000010NMDMH2"
billingRequestFlow, err := client.BillingRequestFlows.Create(context, billingRequestFlowCreateParams)
gc create billing_request_flow \
  -d "links[billing_request]= BRQ000010NMDMH2" \
  -d 'redirect_uri=https://my-company.com/landing' \
  -d 'exit_uri=https://my-company.com/exit'

Response:

{
  "billing_request_flows": {
    "authorisation_url": "https://pay.gocardless.com/billing/static/flow?id=<brf_id>",
    "lock_customer_details": false,
    "lock_bank_account": false,
    "auto_fulfil": true,
    "created_at": "2021-03-30T16:23:10.679Z",
    "expires_at": "2021-04-06T16:23:10.679Z",
    "redirect_uri": "https://my-company.com/completed",
    "links": {
      "billing_request": "BRQ123"
    }
  }
}

Initialise the Drop-in Component#

Include the GoCardless Drop-in script on your page and initialise it with the billing_request_flow_id from the previous step.

<!-- Container for the Drop-in component -->
<div id="gc-dropin-container"></div>
 
<script src="https://pay.gocardless.com/billing/static/dropin/v2/initialise.js"></script>
<script>
  GoCardlessDropin.create({
    billingRequestFlowID: "BRF0000201",
    environment: "live",
    onSuccess: function(billingRequest, billingRequestFlow) {
      // Flow completed — verify outcome via webhook, not this callback
      console.log("Flow completed", billingRequest.id);
    },
    onExit: function(error, metadata) {
      // Customer closed the component before completing
      if (error) { console.error("Drop-in error", error); }
    }
  }).mount("#gc-dropin-container");
</script>

Handle Webhooks#

EventMeaningWhat to do
billing_requests.fulfilledCustomer completed the flowRecord the mandate_id from links.mandate_request_mandate
mandates.activeMandate is ready to collect againstEnable payment collection in your system
payments.confirmedA payment against the mandate was collectedMark the associated period/invoice as paid
payments.failedA payment failedNotify the customer, retry if appropriate
mandates.cancelledMandate was cancelledStop future payment creation

Pre-collecting customer details#

If you already have the customer's name, email, and address, submit them before creating the flow. The hosted page skips those fields or locks them if you prefer.

Collect customer details (optional)#

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"
    }
  }
}
$client = new \GoCardlessPro\Client(array(
  'access_token' => 'your_access_token_here',
  'environment'  => \GoCardlessPro\Environment::SANDBOX
));
 
$client->billingRequests()->collectCustomerDetails("BR123", [
"params" => [
"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"
]
]
]);
 
import gocardless_pro
client = gocardless_pro.Client(access_token="your_access_token_here", environment='sandbox')
 
client.billing_requests.collect_customer_details("BR123", params={
  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",
  }
})
@client = GoCardlessPro::Client.new(
  access_token: "your_access_token",
  environment: :sandbox
)
 
@client.billing_requests.collect_customer_details("BR123", {
  params: {
    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".
    }
  }
})
@client = GoCardlessPro::Client.new(
  access_token: "your_access_token",
  environment: :sandbox
)
 
@client.billing_requests.collect_customer_details("BR123", {
  params: {
    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"
    }
  }
})
const constants = require('gocardless-nodejs/constants');
const gocardless = require('gocardless-nodejs');
const client = gocardless('your_access_token_here', constants.Environments.Sandbox);
 
const resp = await client.billingRequests.collectCustomerDetails("BR123", {
  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"
  }
});
String accessToken = "your_access_token";
GoCardlessClient gocardless = GoCardlessClient.Create(accessToken, Environment.SANDBOX);
 
var customer = new GoCardless.Services.BillingRequestCollectCustomerDetailsRequest.BillingRequestCustomer
{
  Email = "paddington@bearthings.com",
  GivenName = "Paddington",
  FamilyName = "Bear",
};
 
var customerBillingDetail =new GoCardless.Services.BillingRequestCollectCustomerDetailsRequest.BillingRequestCustomerBillingDetail
{
  AddressLine1 = "32 Windsor Gardens",
  City = "London",
  PostalCode = "W9 3RG",
  CountryCode = "GB",
};
 
var resp = await gocardless.BillingRequests.CollectCustomerDetails("BR123",
  new GoCardless.Services.BillingRequestCollectCustomerDetailsRequest
  {
    Customer = customer,
    CustomerBillingDetail = customerBillingDetail,
  });
package main
 
import (
	gocardless "github.com/gocardless/gocardless-pro-go/v6"
)
 
accessToken := "your_access_token_here"
config, err := gocardless.NewConfig(accessToken, gocardless.WithEndpoint(gocardless.SandboxEndpoint))
if err != nil {
	fmt.Printf("got err in initialising config: %s", err.Error())
	return
}
client, err := gocardless.New(config)
if err != nil {
	fmt.Println("error in initialisating client: %s", err.Error())
	return
}
 
billingRequestCollectCustomerDetailsParams := gocardless.BillingRequestCollectCustomerDetailsParams{
  Customer: &gocardless.BillingRequestCollectCustomerDetailsParamsCustomer{
    GivenName:  "Paddington",
    FamilyName: "Bear",
    Email:      "paddington@bearthings.com",
  },
  CustomerBillingDetail: &gocardless.BillingRequestCollectCustomerDetailsParamsCustomerBillingDetail{
    AddressLine1: "32 Windsor Gardens",
    City: "London",
    PostalCode: "W9 3RG",
    CountryCode: "GB",
  },
}
 
billingRequest, err := client.BillingRequests.CollectCustomerDetails(context, "BR123", billingRequestCollectCustomerDetailsParams)

Response: Updated Billing Request with collect_customer_details marked completed.

Collect bank account (optional)#

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"
  }
}
$client = new \GoCardlessPro\Client(array(
  'access_token' => 'your_access_token_here',
  'environment'  => \GoCardlessPro\Environment::SANDBOX
));
 
$client->billingRequests()->collectBankAccount("BRQ000010NMDMH2", [
"params" => [
"account_number" => "55779911",
"branch_code" => "200000",
"account_holder_name" => "Frank Osborne",
"country_code" => "GB"
]
]);
 
import gocardless_pro
client = gocardless_pro.Client(access_token="your_access_token_here", environment='sandbox')
 
client.billing_requests.collect_bank_account("BRQ000010NMDMH2", params={
  account_number: "55779911",
  branch_code: "200000",
  account_holder_name: "Frank Osborne",
  country_code: "GB",
})
@client = GoCardlessPro::Client.new(
  access_token: "your_access_token",
  environment: :sandbox
)
 
@client.billing_requests.collect_bank_account("BRQ000010NMDMH2", {
  params: {
    account_number: "55779911",
    branch_code: "200000",
    account_holder_name: "Frank Osborne",
    country_code: "GB",
  }
})
import static com.gocardless.GoCardlessClient.Environment.SANDBOX;
String accessToken = "your_access_token_here";
GoCardlessClient client = GoCardlessClient
    .newBuilder(accessToken)
    .withEnvironment(SANDBOX)
    .build();
 
client.billingRequests().collectBankAccount("BRQ000010NMDMH2")
  .withAccountNumber("55779911")
  .withBranchCode("200000")
  .withAccountHolderName("Frank Osborne")
  .withCountryCode("GB")
  .execute();
const constants = require("gocardless-nodejs/constants");
const gocardless = require("gocardless-nodejs");
const client = gocardless("your_access_token_here", constants.Environments.Sandbox);
 
const resp = await client.billingRequests.collectBankAccount("BRQ000010NMDMH2", {
  account_number: "55779911",
  branch_code: "200000",
  account_holder_name: "Frank Osborne",
  country_code: "GB",
});
String accessToken = "your_access_token";
GoCardlessClient gocardless = GoCardlessClient.Create(accessToken, Environment.SANDBOX);
 
var resp = await gocardless.BillingRequests.CollectBankAccountAsync("BRQ000010NMDMH2",
  new BillingRequestCollectBankAccountRequest
  {
    AccountNumber = "55779911",
    BranchCode = "200000",
    AccountHolderName = "Frank Osborne",
    CountryCode = "GB",
  });
package main
 
import (
	gocardless "github.com/gocardless/gocardless-pro-go/v6"
)
 
accessToken := "your_access_token_here"
config, err := gocardless.NewConfig(accessToken, gocardless.WithEndpoint(gocardless.SandboxEndpoint))
if err != nil {
	fmt.Printf("got err in initialising config: %s", err.Error())
	return
}
client, err := gocardless.New(config)
if err != nil {
	fmt.Println("error in initialisating client: %s", err.Error())
	return
}
 
billingRequestCollectBankAccountParams := gocardless.BillingRequestCollectBankAccountParams{
  BranchCode:        "200000",
  CountryCode:       "GB",
  AccountNumber:     "55779911",
  AccountHolderName: "Frank Osborne",
}
 
billingRequest, err := client.BillingRequests.CollectBankAccount(context, "BRQ000010NMDMH2", billingRequestCollectBankAccountParams)

Response: Updated Billing Request with collect_bank_account marked completed.

What's next?#