Subscriptions#
What are Subscriptions?#
Automatically collect fixed amounts at regular intervals. Set up a subscription once, and GoCardless handles collection on schedule.
When to use Subscriptions
SaaS subscriptions
Membership fees
Content subscriptions
Gym memberships, insurance premiums, and ongoing services
Comparison between other recurring payment options#
Key difference from instalments: Instalment schedules have a defined end. Subscriptions continue indefinitely until cancelled.
Subscriptions Instalments Variable Recurring Payments Instant Bank Pay + Direct Debit Mandate required Yes Yes Yes (consent) Yes Customer authorisation Once Once Once (with agreed limits and frequency) Once Payment amounts Fixed (per subscription) Fixed per instalment, can vary across schedule Variable within agreed constraints First payment fixed; subsequent payments flexible Payment schedule Merchant-defined recurring (weekly, monthly, yearly) Merchant-defined schedule with a defined end Flexible - merchant triggers payments as needed Flexible after first payment Confirmation speed 2-x business days 2-x business days Seconds First payment: minutes; subsequent: 2-x business days Chargeback risk Yes Yes None First payment: none; subsequent: yes Missed payment retries Yes (with Success+) Yes (with Success+) Yes Subsequent payments: yes Best for SaaS, memberships, gym fees, insurance Payment plans, tuition, professional services Usage-based regulated billing and utilities, financial services, government services Subscription services needing immediate, initial payment Availability All schemes All schemes GBP only GBP and EUR
Need to change the amount? If the amount varies between cycles, use one-off payments instead and control each charge individually. Alternatively, you can cancel and recreate a subscription with a new amount.
**Only taking payments for a defined period? **If the amount doesn't vary and you wish to only take a certain number of payments, use instalments instead.
How it works#
The customer sets up a mandate via your chosen integration
You create a payment against the mandate via the API
GoCardless collects the payment (typically 2-5 business days)
You receive a webhook confirming the payment status
Funds are included in your next payout
Frequency options: Weekly, monthly, yearly, or custom intervals.
Step-by-step guide#
Create a billing request#
HTTP PHP Python Ruby Java JavaScript .NET Go
curl -X POST https://api.gocardless.com/billing_requests \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"billing_requests": {
"mandate_request": {
"scheme": "bacs"
}
}
}' <? 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' ,
],
],
]); import os
import gocardless_pro
client = gocardless_pro.Client(
access_token = os.environ[ 'GC_ACCESS_TOKEN' ],
environment = 'sandbox'
)
response = client.billing_requests.create(
params = {
'mandate_request' : {
'scheme' : 'bacs' ,
}
}
) require 'gocardless_pro'
client = GoCardlessPro :: Client . new (
access_token: ENV [ 'GC_ACCESS_TOKEN' ],
environment: :sandbox
)
response = client. billing_requests . create (
params: {
mandate_request: {
scheme: 'bacs'
}
}
) import com.gocardless.GoCardlessClient;
GoCardlessClient client = GoCardlessClient
. newBuilder (System. getenv ( "GC_ACCESS_TOKEN" ))
. withEnvironment (GoCardlessClient.Environment.SANDBOX)
. build ();
BillingRequestCreateResponse response = client. billingRequests ()
. create ()
. withMandateRequestScheme ( "bacs" )
. execute (); 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: {
scheme: "bacs" ,
},
}); 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
{
Scheme = "bacs"
}
}
); package main
import (
" context "
" fmt "
" os "
gocardless " github.com/gocardless/gocardless-pro-go/v6 "
)
func main () {
opts := gocardless. WithEndpoint (gocardless.SandboxEndpoint)
client, err := gocardless. New (os. Getenv ( "GC_ACCESS_TOKEN" ), opts)
if err != nil {
panic (err)
}
params := gocardless . BillingRequestCreateParams {
MandateRequest: & gocardless . BillingRequestCreateParamsMandateRequest {
Scheme: "bacs" ,
},
}
result, err := client.BillingRequests. Create (context. TODO (), params)
if err != nil {
panic (err)
}
fmt. Println (result)
}
Response:
{
"billing_requests" : {
"id" : "BRQ000123" ,
"status" : "pending" ,
"mandate_request" : {
"currency" : "GBP" ,
"scheme" : "bacs"
}
}
}
Confirm the mandate#
After creating the Billing Request, direct the customer to authorise the mandate. How you do this depends on your integration type:
Hosted Pages - Create a Billing Request Flow and redirect the customer to the authorisation_url. See Hosted Payment Pages .
Custom API - Collect customer details and bank account via Billing Request actions, then confirm. See Custom Payment Pages .
Handle the outcome#
Once fulfilled, retrieve both mandate ID and payment ID from the billing request:
Response:
{
"billing_requests" : {
"id" : "BRQ000123" ,
"status" : "fulfilled" ,
"mandate_request" : {
"scheme" : "bacs" ,
"links" : {
"mandate" : "MD123"
}
}
}
}
Listen for webhooks to confirm the payment status:
Event Meaning billing_request_fulfilled Customer authorised the mandate mandates_created Mandate created and ready to use mandates_active Mandate active
Handle the subscription#
Once the mandate is active, set up recurring payments against it:
HTTP PHP Python Ruby Java JavaScript .NET Go
curl -X POST https://api.gocardless.com/subscriptions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subscriptions": {
"amount": 5000,
"currency": "GBP",
"name": "Monthly subscription",
"interval_unit": "monthly",
"interval": 1,
"start_date": "2024-11-01",
"links": {
"mandate": "MD123"
}
}
}' <? php
require 'vendor/autoload.php' ;
$client = new \GoCardlessPro\Client ([
'access_token' => getenv ( 'GC_ACCESS_TOKEN' ),
'environment' => \GoCardlessPro\Environment :: SANDBOX
]);
$response = $client -> subscriptions () -> create ([
'params' => [
'amount' => 2500 ,
'currency' => 'GBP' ,
'name' => 'Monthly Magazine' ,
'interval_unit' => 'monthly' ,
'interval' => 1 ,
'day_of_month' => 1 ,
'start_date' => '2024-11-01' ,
'links' => [
'mandate' => 'MD123' ,
],
],
]); import os
import gocardless_pro
client = gocardless_pro.Client(
access_token = os.environ[ 'GC_ACCESS_TOKEN' ],
environment = 'sandbox'
)
response = client.subscriptions.create(
params = {
'amount' : 2500 ,
'currency' : 'GBP' ,
'name' : 'Monthly Magazine' ,
'interval_unit' : 'monthly' ,
'interval' : 1 ,
'day_of_month' : 1 ,
'start_date' : '2024-11-01' ,
'links' : {
'mandate' : 'MD123' ,
},
}
) require 'gocardless_pro'
client = GoCardlessPro :: Client . new (
access_token: ENV [ 'GC_ACCESS_TOKEN' ],
environment: :sandbox
)
response = client. subscriptions . create (
params: {
amount: 2500 ,
currency: 'GBP' ,
name: 'Monthly Magazine' ,
interval_unit: 'monthly' ,
interval: 1 ,
day_of_month: 1 ,
start_date: '2024-11-01' ,
links: {
mandate: 'MD123'
}
}
) import com.gocardless.GoCardlessClient;
GoCardlessClient client = GoCardlessClient
. newBuilder (System. getenv ( "GC_ACCESS_TOKEN" ))
. withEnvironment (GoCardlessClient.Environment.SANDBOX)
. build ();
Subscription subscription = client. subscriptions ()
. create ()
. withAmount ( 2500 )
. withCurrency ( "GBP" )
. withName ( "Monthly Magazine" )
. withIntervalUnit (Subscription.IntervalUnit.MONTHLY)
. withInterval ( 1 )
. withDayOfMonth ( 1 )
. withStartDate ( "2024-11-01" )
. withLinksMandate ( "MD123" )
. execute (); const gocardless = require ( "gocardless-nodejs" );
const constants = require ( "gocardless-nodejs/constants" );
const client = gocardless (process.env. GC_ACCESS_TOKEN , constants.Environments.Sandbox);
const subscription = await client.subscriptions. create ({
amount: 2500 ,
currency: "GBP" ,
name: "Monthly Magazine" ,
interval_unit: "monthly" ,
interval: 1 ,
day_of_month: 1 ,
start_date: "2024-11-01" ,
links: {
mandate: "MD123" ,
},
}); using GoCardless ;
var client = GoCardlessClient. Create (
Environment. GetEnvironmentVariable ( "GC_ACCESS_TOKEN" ),
GoCardlessClient.Environment.SANDBOX
);
var subscription = await client.Subscriptions. CreateAsync (
new SubscriptionCreateRequest
{
Amount = 2500 ,
Currency = "GBP" ,
Name = "Monthly Magazine" ,
IntervalUnit = SubscriptionCreateRequest.SubscriptionIntervalUnit.Monthly,
Interval = 1 ,
DayOfMonth = 1 ,
StartDate = "2024-11-01" ,
Links = new SubscriptionCreateRequest . SubscriptionLinks
{
Mandate = "MD123"
}
}
); package main
import (
" context "
" fmt "
" os "
gocardless " github.com/gocardless/gocardless-pro-go/v6 "
)
func main () {
opts := gocardless. WithEndpoint (gocardless.SandboxEndpoint)
client, err := gocardless. New (os. Getenv ( "GC_ACCESS_TOKEN" ), opts)
if err != nil {
panic (err)
}
params := gocardless . SubscriptionCreateParams {
Amount: 2500 ,
Currency: "GBP" ,
Name: "Monthly Magazine" ,
IntervalUnit: "monthly" ,
Interval: 1 ,
DayOfMonth: 1 ,
StartDate: "2024-11-01" ,
Links: gocardless . SubscriptionCreateParamsLinks {
Mandate: "MD123" ,
},
}
subscription, err := client.Subscriptions. Create (context. TODO (), params)
if err != nil {
panic (err)
}
fmt. Println (subscription)
}
Response:
{
"subscriptions" : {
"id" : "SB123" ,
"status" : "active" ,
"amount" : 2500 ,
"currency" : "GBP" ,
"interval" : 1 ,
"interval_unit" : "monthly" ,
"start_date" : "2024-11-01" ,
"upcoming_payments" : [
{ "charge_date" : "2024-11-01" , "amount" : 2500 },
{ "charge_date" : "2024-12-01" , "amount" : 2500 }
],
"links" : {
"mandate" : "MD123"
}
}
}
Manage the subscription#
Listen for webhooks to confirm the mandate status and notifications about future payments:
Event Meaning subscriptions_created Subscription set up successfully subscriptions_payment_created A scheduled payment was created payments_confirmed Recurring payment collected successfully payments_failed Recurring payment failed subscriptions_finished All payments collected (if count was set) subscriptions_cancelled Subscription cancelled
You can also cancel the subscription:
Or pause the subscription:
HTTP PHP Python Ruby Java JavaScript .NET Go
curl -X POST https://api.gocardless.com/subscriptions/SB123/actions/pause \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "data": { "pause_cycles": 3 } }' $response = $client -> subscriptions () -> pause ( 'SB123' , [
'params' => [
'pause_cycles' => 3 ,
],
]); response = client.subscriptions.pause(
'SB123' ,
params = {
'pause_cycles' : 3 ,
}
) response = client. subscriptions . pause (
'SB123' ,
params: {
pause_cycles: 3
}
) Subscription subscription = client. subscriptions ()
. pause ( "SB123" )
. withPauseCycles ( 3 )
. execute (); const subscription = await client.subscriptions. pause ( "SB123" , {
pause_cycles: 3 ,
}); var subscription = await client.Subscriptions. PauseAsync (
"SB123" ,
new SubscriptionPauseRequest
{
PauseCycles = 3
}
); params := gocardless . SubscriptionPauseParams {
PauseCycles: 3 ,
}
subscription, err := client.Subscriptions. Pause (context. TODO (), "SB123" , params)
And resume the subscription:
What's next?#