# Custom Payment Pages Overview

Source: https://docs.gocardless.com/docs/collect-payments/integration-types/custom-payment-pages

# Custom Payment Pages

Build your own payment flow from scratch using the GoCardless API directly. You have complete control over the user experience, design, and logic.

**This is the highest-effort integration.** Consider starting with [Hosted Pages](/docs/collect-payments/integration-types/gocardless-hosted-pages) to validate your integration — the underlying API is identical.

Supports: **Direct Debit, Pay By Bank, VRP.**

## Best for

- White-label or embedded product requirements
- Complex, multi-step user journeys
- Deep integration with your application
- Full control over UX and brand experience

## How it works

- Build your own UI for collecting customer and bank account details
- Use the Billing Requests API to create and progress through the payment flow
- Call API actions to collect customer details, collect bank account information, and confirm
- Handle all states, errors, and edge cases in your application

**What you need to handle:**

- Input validation and error messaging
- Scheme-specific bank account fields per country
- Compliance requirements (e.g., Direct Debit Guarantee display)
- Loading states and timeouts
- Mobile responsiveness

## Step-by-step guide

### Create a billing request

The Billing Request defines what you're collecting and applies to all flows. The payload differs by payment type:

#### Direct Debit Mandate

```http
curl -X POST https://api.gocardless.com/billing_requests \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '
    }
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->create([
    'params' => [
        'mandate_request' => [
            'scheme' => 'bacs',
        ],
    ],
]);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.create(
    params=
    }
)
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.create(
  params: 
  }
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestCreateResponse response = client.billingRequests()
    .create()
    .withMandateRequestScheme("bacs")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.create(,
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.CreateAsync(
    new BillingRequestCreateRequest
    
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BillingRequestCreateParams,
    }

    result, err := client.BillingRequests.Create(context.TODO(), params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:**

```json
,
    "actions": [
      ,
      ,
      
    ]
  }
}
```

#### Pay By Bank

```http
curl -X POST https://api.gocardless.com/billing_requests \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '
    }
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->create([
    'params' => [
        'payment_request' => [
            'description' => 'Order #9012',
            'amount'      => 12000,
            'currency'    => 'GBP',
            'scheme'      => 'faster_payments',
        ],
    ],
]);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.create(
    params=
    }
)

```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.create(
  params: 
  }
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestCreateResponse response = client.billingRequests()
    .create()
    .withPaymentRequestDescription("Order #9012")
    .withPaymentRequestAmount(12000)
    .withPaymentRequestCurrency("GBP")
    .withPaymentRequestScheme("faster_payments")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.create(,
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.CreateAsync(
    new BillingRequestCreateRequest
    
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BillingRequestCreateParams,
    }

    result, err := client.BillingRequests.Create(context.TODO(), params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:**

```json
,
    "actions": [
      ,
      ,
      
    ]
  }
}
```

#### Direct Debit + Pay By Bank

```http
curl -X POST https://api.gocardless.com/billing_requests \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d ',
      "mandate_request": 
    }
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->create([
    'params' => [
        'payment_request' => [
            'description' => 'First payment',
            'amount'      => 5000,
            'currency'    => 'GBP',
            'scheme'      => 'faster_payments',
        ],
        'mandate_request' => [
            'scheme' => 'bacs',
        ],
    ],
]);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.create(
    params=,
        'mandate_request': ,
    }
)
```

```ruby
  require 'gocardless_pro'

  client = GoCardlessPro::Client.new(
      access_token: ENV['GC_ACCESS_TOKEN'],
      environment: :sandbox
  )

  response = client.billing_requests.create(
    params: ,
      mandate_request: 
    }
  )
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestCreateResponse response = client.billingRequests()
    .create()
    .withPaymentRequestDescription("First payment")
    .withPaymentRequestAmount(5000)
    .withPaymentRequestCurrency("GBP")
    .withPaymentRequestScheme("faster_payments")
    .withMandateRequestScheme("bacs")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.create(,
  mandate_request: ,
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.CreateAsync(
    new BillingRequestCreateRequest
    ,
        MandateRequest = new BillingRequestCreateRequest.BillingRequestMandateRequest
        
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BillingRequestCreateParams,
        MandateRequest: &gocardless.BillingRequestCreateParamsMandateRequest,
    }

    result, err := client.BillingRequests.Create(context.TODO(), params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:**

```json
,
    "mandate_request": ,
    "actions": [
      ,
      ,
      ,
      ,
      
    ]
  }
}
```

#### Variable Recurring Payments (VRP)

```http
curl -X POST https://api.gocardless.com/billing_requests \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d ']
        }
      }
    }
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->create([
    'params' => [
        'fallback_enabled'     => true,
        'purpose_code'         => 'loan',
        'payment_context_code' => 'billing_goods_and_services_in_arrears',
        'payment_purpose_code' => 'bank_loan_delayed_draw_funding',
        'mandate_request'      => [
            'scheme'      => 'faster_payments',
            'constraints' => [
                'start_date'             => '2024-11-01',
                'max_amount_per_payment' => 50000,
                'periodic_limits'        => [
                    [
                        'period'           => 'month',
                        'max_total_amount' => 100000,
                        'alignment'        => 'creation_date',
                    ],
                ],
            ],
        ],
    ],
]);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.create(
    params=,
                ],
            },
        },
    }
)
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.create(
  params: 
        ]
      }
    }
  }
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestCreateResponse response = client.billingRequests()
    .create()
    .withFallbackEnabled(true)
    .withPurposeCode("loan")
    .withPaymentContextCode("billing_goods_and_services_in_arrears")
    .withPaymentPurposeCode("bank_loan_delayed_draw_funding")
    .withMandateRequestScheme("faster_payments")
    .withMandateRequestConstraintsStartDate("2024-11-01")
    .withMandateRequestConstraintsMaxAmountPerPayment(50000)
    .withMandateRequestConstraintsPeriodicLimitsBuilder()
        .withPeriod("month")
        .withMaxTotalAmount(100000)
        .withAlignment("creation_date")
    .done()
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.create(,
      ],
    },
  },
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.CreateAsync(
    new BillingRequestCreateRequest
    
                }
            }
        }
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    fallbackEnabled := true
    params := gocardless.BillingRequestCreateParams,
                },
            },
        },
    }

    result, err := client.BillingRequests.Create(context.TODO(), params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:**

```json
,
      "links": ,
      "constraints": 
        ]
      }
    },
    "payment_request": null,
    "subscription_request": null,
    "instalment_schedule_request": null,
    "metadata": ,
    "fallback_enabled": true,
    "fallback_occurred": false,
    "purpose_code": "loan",
    "payment_purpose_code": "bank_loan_delayed_draw_funding",
    "sign_flow_url": null,
    "auto_fulfil": false,
    "actions": [
      
        }
      },
      ,
      ,
      
      },
      
    ],
    "links": 
  }
}
```

### Collect Customer Details

Applies to all flows

```http
curl -X POST https://api.gocardless.com/billing_requests/BRQ0000301/actions/collect_customer_details \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d ',
      "customer_billing_detail": 
    }
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->collectCustomerDetails(
    'BRQ0000301',
    [
        'data' => [
            'customer' => [
                'email'       => 'frank.osborne@example.com',
                'given_name'  => 'Frank',
                'family_name' => 'Osborne',
            ],
            'customer_billing_detail' => [
                'address_line1' => '27 Acer Road',
                'city'          => 'London',
                'postal_code'   => 'E8 3GX',
                'country_code'  => 'GB',
            ],
        ],
    ]
);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.collect_customer_details(
    'BRQ0000301',
    params=,
            'customer_billing_detail': ,
        }
    }
)
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.collect_customer_details(
  'BRQ0000301',
  data: ,
    customer_billing_detail: 
  }
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestCollectCustomerDetailsResponse response = client.billingRequests()
    .collectCustomerDetails("BRQ0000301")
    .withCustomerEmail("frank.osborne@example.com")
    .withCustomerGivenName("Frank")
    .withCustomerFamilyName("Osborne")
    .withCustomerBillingDetailAddressLine1("27 Acer Road")
    .withCustomerBillingDetailCity("London")
    .withCustomerBillingDetailPostalCode("E8 3GX")
    .withCustomerBillingDetailCountryCode("GB")
    .execute();

```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.collectCustomerDetails("BRQ0000301", ,
    customer_billing_detail: ,
  },
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.CollectCustomerDetailsAsync(
    "BRQ0000301",
    new BillingRequestCollectCustomerDetailsRequest
    ,
            CustomerBillingDetail = new BillingRequestCollectCustomerDetailsRequest.CustomerBillingDetailData
            
        }
    }
);
```

```go
package main

    "context"
    "fmt"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BillingRequestCollectCustomerDetailsParams,
            CustomerBillingDetail: gocardless.BillingRequestCollectCustomerDetailsParamsCustomerBillingDetail,
        },
    }

    result, err := client.BillingRequests.CollectCustomerDetails(context.TODO(), "BRQ0000301", params)
    if err != nil 
    fmt.Println(result)
```

**Response:** Billing Request with collect_customer_details marked completed.

### Collect a bank account

Applies to all flows.

Required fields vary by country and scheme. Example for UK (Bacs / Faster Payments):

```http
curl -X POST https://api.gocardless.com/billing_requests/BRQ0000301/actions/collect_bank_account \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->collectBankAccount(
    'BRQ0000301',
    [
        'data' => [
            'country_code'        => 'GB',
            'account_holder_name' => 'Frank Osborne',
            'account_number'      => '55779911',
            'branch_code'         => '200000',
        ],
    ]
);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.collect_bank_account(
    'BRQ0000301',
    params=
    }
)
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.collect_bank_account(
  'BRQ0000301',
  data: 
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestCollectBankAccountResponse response = client.billingRequests()
    .collectBankAccount("BRQ0000301")
    .withCountryCode("GB")
    .withAccountHolderName("Frank Osborne")
    .withAccountNumber("55779911")
    .withBranchCode("200000")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.collectBankAccount("BRQ0000301", ,
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.CollectBankAccountAsync(
    "BRQ0000301",
    new BillingRequestCollectBankAccountRequest
    
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BillingRequestCollectBankAccountParams,
    }

    result, err := client.BillingRequests.CollectBankAccount(context.TODO(), "BRQ0000301", params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:** Billing Request with collect_bank_account marked completed.

### Confirm payer details

Applies to: **all flows including mandates** (Mandate-only flow and Payment + Mandate flow

The customer confirms their consent to set up the mandate. No request body required.

```http
curl -X POST https://api.gocardless.com/billing_requests/BRQ0000301/actions/confirm_payer_details \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->confirmPayerDetails('BRQ0000301');
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.confirm_payer_details('BRQ0000301')
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.confirm_payer_details('BRQ0000301')
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestConfirmPayerDetailsResponse response = client.billingRequests()
    .confirmPayerDetails("BRQ0000301")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.confirmPayerDetails("BRQ0000301");
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.ConfirmPayerDetailsAsync("BRQ0000301");
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    result, err := client.BillingRequests.ConfirmPayerDetails(context.TODO(), "BRQ0000301", gocardless.BillingRequestConfirmPayerDetailsParams)
    if err != nil 
    fmt.Println(result)
}
```

**Response:** Billing Request with collect_bank_account marked completed.

```json
,
      ,
      
    ]
  }
}
```

### Select Institution

Applies to: **all flows including payments** (Payment-only flow and Payment + Mandate flow

Identify the customer's bank for the open banking authorisation. Use the list institutions endpoint to present a bank picker to the customer.

```http
curl -X POST https://api.gocardless.com/billing_requests/BRQ0000302/actions/select_institution \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->selectInstitution(
    'BRQ0000302',
    [
        'data' => [
            'institution'  => 'MONZO_MONZGB2L',
            'country_code' => 'GB',
        ],
    ]
);
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.select_institution(
    'BRQ0000302',
    params=
    }
)
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.select_institution(
  'BRQ0000302',
  data: 
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestSelectInstitutionResponse response = client.billingRequests()
    .selectInstitution("BRQ0000302")
    .withInstitution("MONZO_MONZGB2L")
    .withCountryCode("GB")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.selectInstitution("BRQ0000302", ,
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.SelectInstitutionAsync(
    "BRQ0000302",
    new BillingRequestSelectInstitutionRequest
    
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BillingRequestSelectInstitutionParams,
    }

    result, err := client.BillingRequests.SelectInstitution(context.TODO(), "BRQ0000302", params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:** Billing Request with select_institution marked completed.

### Create a bank authorisation

Applies to: **all flows including payments** (Payment-only flow and Payment + Mandate flow.

```http
curl -X POST https://api.gocardless.com/bank_authorisations \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '
    }
  }'
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->bankAuthorisations()->create([
    'params' => [
        'redirect_uri' => 'https://yoursite.com/payment-complete',
        'links'        => [
            'billing_request' => 'BRQ0000302',
        ],
    ],
]);

```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.bank_authorisations.create(
    params=,
    }
)
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.bank_authorisations.create(
  params: 
  }
)
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BankAuthorisationCreateResponse response = client.bankAuthorisations()
    .create()
    .withRedirectUri("https://yoursite.com/payment-complete")
    .withLinksBuilder()
        .withBillingRequest("BRQ0000302")
    .done()
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.bankAuthorisations.create(,
});
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BankAuthorisations.CreateAsync(
    new BankAuthorisationCreateRequest
    
    }
);
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    params := gocardless.BankAuthorisationCreateParams,
    }

    result, err := client.BankAuthorisations.Create(context.TODO(), params)
    if err != nil 
    fmt.Println(result)
}
```

**Response:**

```json

  }
}
```

### Redirect customer to their bank

Applies to: **all flows including payments** (Payment-only flow and Payment + Mandate flow

Redirect your customer to the url from the bank authorisation response. The customer approves the payment in their banking app, then is returned to your redirect_uri.

> **Warning:**
> Don't use the redirect to confirm the outcome. Always use webhooks.

### Fulfill the billing request

Applies to: **Mandate-only flow**

Once the Billing Request status is ready_to_fulfil, call the fulfil action to activate the mandate.

```http
curl -X POST https://api.gocardless.com/billing_requests/BRQ0000301/actions/fulfil \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"
```

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

$client = new \GoCardlessPro\Client([
    'access_token' => getenv('GC_ACCESS_TOKEN'),
    'environment' => \GoCardlessPro\Environment::SANDBOX
]);

$response = $client->billingRequests()->fulfil('BRQ0000301');
```

```python

client = gocardless_pro.Client(
    access_token=os.environ['GC_ACCESS_TOKEN'],
    environment='sandbox'
)

response = client.billing_requests.fulfil('BRQ0000301')
```

```ruby
require 'gocardless_pro'

client = GoCardlessPro::Client.new(
    access_token: ENV['GC_ACCESS_TOKEN'],
    environment: :sandbox
)

response = client.billing_requests.fulfil('BRQ0000301')
```

```java

GoCardlessClient client = GoCardlessClient
    .newBuilder(System.getenv("GC_ACCESS_TOKEN"))
    .withEnvironment(GoCardlessClient.Environment.SANDBOX)
    .build();

BillingRequestFulfilResponse response = client.billingRequests()
    .fulfil("BRQ0000301")
    .execute();
```

```javascript
const gocardless = require("gocardless-nodejs");
const constants = require("gocardless-nodejs/constants");

const client = gocardless(process.env.GC_ACCESS_TOKEN, constants.Environments.Sandbox);

const response = await client.billingRequests.fulfil("BRQ0000301");
```

```cs
using GoCardless;

var client = GoCardlessClient.Create(
    Environment.GetEnvironmentVariable("GC_ACCESS_TOKEN"),
    GoCardlessClient.Environment.SANDBOX
);

var response = await client.BillingRequests.FulfilAsync("BRQ0000301");
```

```go
package main

    "context"
    "fmt"
    "os"

    gocardless "github.com/gocardless/gocardless-pro-go/v6"
)

func main() 

    result, err := client.BillingRequests.Fulfil(context.TODO(), "BRQ0000301", gocardless.BillingRequestFulfilParams)
    if err != nil 
    fmt.Println(result)
}
```

**Response:**

```json

  }
}
```

### Handle Webhooks

| **Event**                  | **Meaning**                 | **Applies to**                  |
| -------------------------- | --------------------------- | ------------------------------- |
| billing_requests.fulfilled | Billing Request completed   | All flows                       |
| mandates.active            | Mandate is active and ready | Mandate-only, payment + mandate |
| payments.confirmed         | Pay By Bank payment settled | Payment-only, payment + mandate |
| payments.failed            | Payment failed              | Payment-only, payment + mandate |
| mandates.cancelled         | Mandate cancelled           | Mandate-only, payment + mandate |

## What's next?

  
#### [Setting Up Mandates](/docs/collect-payments/setting-up-mandates)

Guide to creating mandates and handling all mandate actions.

  
#### [Billing Request Events](/docs/collect-payments/events-and-webhooks/billing-request-events)

Understand the events fired during a billing request lifecycle.

  
#### [Prefill Customer Details](/docs/optimise/prefill-customer-details)

Pre-populate customer data to reduce steps in your custom flow.

  
#### [GoCardless Hosted Pages](/docs/collect-payments/integration-types/gocardless-hosted-pages)

Start with hosted pages to validate your integration — same underlying API.