In this first step of the partner integration guide, we’ll take you through securely gaining access to your users’ GoCardless accounts.
You’ll end up with an access token, which we’ll be able to use later on in this guide to set up mandates and payments on your user’s behalf.
OAuth: an introduction
To set up mandates and payments for your users, you’ll need access to their GoCardless account so you can make API requests on their behalf.
Our OAuth flow allows you to securely obtain an access token for a GoCardless account without having to have your user’s password or do any manual setup.
There are four key benefits to getting access to your users’ accounts using OAuth:
- It’s secure: Your users have a secure way to grant you access to their account without needing to send you their login credentials or an access token. They only need to tell us that you may have access through a simple online process.
- It’s fast : You only need to generate and send your user to a link to our OAuth flow. From there, they’ll create a GoCardless account or sign in to their existing one, approve your access to their account, and then we’ll send them right back to you with an access token.
- It’s lucrative: Linking to your users’ accounts using OAuth makes you eligible to earn commission for each payment they process through your product, either by adding your own fees on top of GoCardless’s, or by receiving a share of GoCardless’s fees
- It’s future-proof: As the GoCardless API gets better and better over time and offers new functionality, you’ll be able to stay up-to-date and use all the latest features
The process for your user looks like this:
- Your user clicks a button in your UI to start the process of connecting with GoCardless
- You generate a link to the GoCardless OAuth flow, embedding details of your app
(which we’ll set up next) as well as a
scope
to specify the level of access you want your user to give you - You redirect your user to the generated link. Your user lands on our site, where they create a GoCardless account or log in to their existing one, and agree to grant your app access
- We redirect your user’s browser back to you with a
code
query parameter - You exchange the
code
for a permanent access token, which you store so that you can use it to make API requests on your user’s behalf
You’ll send each of your users through this flow, connecting them to the same app, and getting an access token for each of them.
Using the OAuth flow
Creating an app
Before we can get started, you need to create an “app” in the sandbox environment which
represents your partner integration in the GoCardless system. You’ll be issued with a
client ID and secret, which you’ll use to identify yourself when sending users to the
OAuth flow and swapping code
s for access tokens.
First sign up for a GoCardless account in our sandbox testing environment and then create an app.
You’ll need to provide a name, a description and the URL of your homepage (where users can go to read more about your product or your integration with GoCardless). We won’t specify the post-onboarding URL or webhook URL for now.
Once your user has completed the OAuth flow, they will be redirected to your application
using the redirect_url
parameter you provide. For security reasons, this can’t be just
any internet URL, so you will need to configure at least one redirect URL here (which must
exactly match the parameter). You may wish to add additional redirect URLs, for example
when also testing against your local application, but we’ll only allow up to 20 redirect
URLs in total.
Once you’ve created an app, you’ll see it in the list of your apps in your Dashboard. Click on your newly-created app, and take a note of the Client ID and Client Secret.
Generating a link to the OAuth flow
Let’s get started by installing an OAuth client library:
composer require adoy/oauth2
pip install oauth2client
echo "gem 'oauth2'" >> Gemfile
bundle install
<-- Add the following to your Maven file -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.4.1</version>
</dependency>
Now we’ve installed the library, we can build a link to the OAuth flow. We’ll have to
pass in a number of parameters, including the client_id
and client_secret
, as well as
a few parameters that will vary by library. These can include:
- The URL of the GoCardless OAuth flow
- In the sandbox, this is
https://connect-sandbox.gocardless.com/oauth/authorize
. It'll form the base of the URL your client library generates. - A redirect URL
- The URL to send your users to once they've agreed to connect their account to GoCardless (as well if they deny authorisation or something goes wrong, in which case we'll pass you details of the error). This must exactly match one of the redirect URLs you specified above.
- The URL of the GoCardless access token API
- The URL of the API endpoint which will be used to exchange the
code
for an access token after your user has been redirected back to your redirect URL. In the sandbox environment, this ishttps://connect-sandbox.gocardless.com/oauth/access_token
. scope
- The level of access you want to your users' GoCardless accounts - this may either
be
read_write
orread_only
. -
initial_view
(optional) - An optional parameter, set to either
signup
orlogin
to specify which view we should show when your user enters the OAuth flow. By default, they will see the login view if you're requestingread_only
access and the signup view if requestingread_write
. -
state
(optional) - Any value you pass in here will be included as a querystring parameter when we redirect back to your redirect URL. Please note that this value can be tampered with by your user, and so shouldn't be trusted implicitly. We recommend using this parameter for a CSRF token.
-
prefill[email]
(optional) - Your user's email address. We will pre-fill this on the login or signup forms to make it quicker and easier for them to complete the flow.
-
prefill[given_name]
(optional) - Your user's given (first) name. We will pre-fill this on the signup form.
-
prefill[family_name]
(optional) - Your user's family (last) name. We will pre-fill this on the signup form.
-
prefill[organisation_name]
(optional) - The name of the user's organisation (e.g. Acme Widget plc, 2nd Upminster Scout Group or Tim Rogers). We will pre-fill this on the signup form.
-
prefill[country_code]
(optional) - The country code of the users' organisation in ISO 3166-1 alpha-2 code format. We will pre-fill this on the signup form.
-
language
(optional) - The language that the login/signup form should be in, in ISO 639-1 format. If the language specified is supported, we will use it. Otherwise, we will fall back to the most appropriate available language for the user, based on factors like their browser settings and location.
<?php
require 'vendor/autoload.php';
// You should store your client ID and secret in environment variables rather than
// committing them with your code
$client = new OAuth2\Client(getenv('GOCARDLESS_CLIENT_ID'), getenv('GOCARDLESS_CLIENT_SECRET'));
$authorizeUrl = $client->getAuthenticationUrl(
// Once you go live, this should be set to https://connect.gocardless.com. You'll also
// need to create a live app and update your client ID and secret.
'https://connect-sandbox.gocardless.com/oauth/authorize',
'https://acme.enterprises/redirect', // Your redirect URL
['scope' => 'read_write',
'initial_view' => 'login',
'prefill' => ['email' => 'tim@gocardless.com',
'given_name' => 'Tim',
'family_name' => 'Rogers',
'organisation_name' => 'Tim\'s Fishing Store']]
);
// You'll now want to direct your user to the URL - you could redirect them or display it
// as a link on the page
header("Location: " . $authorizeUrl);
import os
from oauth2client.client import OAuth2WebServerFlow
# You should store your client ID and secret in environment variables rather than
# committing them with your code
flow = OAuth2WebServerFlow(
client_id=os.environ['GOCARDLESS_CLIENT_ID'],
client_secret=os.environ['GOCARDLESS_CLIENT_SECRET'],
scope="read_write",
redirect_uri="https://acme.enterprises/redirect",
# Once you go live, this should be set to https://connect.gocardless.com. You'll
# also need to create a live app and update your client ID and secret.
auth_uri="https://connect-sandbox.gocardless.com/oauth/authorize",
token_uri="https://connect-sandbox.gocardless.com/oauth/access_token",
initial_view="signup",
prefill={
"email": "tim@gocardless.com",
"given_name": "Tim",
"family_name": "Rogers",
"organisation_name": "Tim's Fishing Store"
}
)
authorize_url = flow.step1_get_authorize_url()
# You'll now want to direct your user to the URL - you could redirect them or display it
# as a link on the page
flask.redirect(authorize_url, code=302)
require 'oauth2'
# You should store your client ID and secret in environment variables rather than
# committing them with your code
oauth = OAuth2::Client.new(ENV['GOCARDLESS_CLIENT_ID'],
ENV['GOCARDLESS_CLIENT_SECRET'],
# Once you go live, this should be set to
# https://connect.gocardless.com. You'll also need to create
# a live app and update your client ID and secret.
site: 'https://connect-sandbox.gocardless.com',
authorize_url: '/oauth/authorize',
token_url: '/oauth/access_token')
authorize_url = oauth.auth_code.authorize_url(redirect_uri: 'https://acme.enterprises/redirect',
scope: 'read_only',
initial_view: 'signup',
prefill: {
email: "tim@gocardless.com",
given_name: "Tim",
family_name: "Rogers",
organisation_name: "Tim's Fishing Store"
})
redirect_to authorize_url
// See https://raw.githubusercontent.com/gocardless/gocardless-pro-java-maven-example/master/src/main/java/hello/OAuthController.java
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.util.UriComponentsBuilder;
@RestController
public class OAuthController {
private static final String authoriseRedirectUrl =
"https://connect-sandbox.gocardless.com/oauth/authorize";
private static final String redirectUrl =
"https://bb314345.ngrok.io/redirect";
private static final String clientID =
System.getenv("GOCARDLESS_CLIENT_ID");
private static final String clientSecret =
System.getenv("GOCARDLESS_CLIENT_SECRET");
@GetMapping("/")
public ResponseEntity<String> index() {
String oauthUrl = UriComponentsBuilder
.fromUriString(authoriseRedirectUrl)
.queryParam("client_id", clientID)
.queryParam("redirect_uri", redirectUrl)
.queryParam("scope", "read_write")
.queryParam("response_type", "code")
.queryParam("initial_view", "signup")
.queryParam("prefill[email]", "tim@gocardless.com")
.queryParam("prefill[given_name]", "Tim")
.queryParam("prefill[family_name]", "Rogers")
.queryParam("prefill[organisation_name]", "Tim's Fishing Store")
.queryParam("prefill[country_code]", "GB")
.toUriString();
HttpHeaders headers = new HttpHeaders();
headers.add("Location", oauthUrl);
return new ResponseEntity<String>(oauthUrl, headers, HttpStatus.FOUND);
}
}
// This is example code and must be inserted into you application structure
private readonly string authoriseRedirectUrl = "https://connect-sandbox.gocardless.com/oauth/authorize";
private readonly string redirectUrl = "https://acme.enterprises/redirect";
private readonly string clientID = Environment.GetEnvironmentVariable("GOCARDLESS_CLIENT_ID");
private readonly string clientSecret = Environment.GetEnvironmentVariable("GOCARDLESS_CLIENT_SECRET");
public static void redirect()
{
var uriBuilder = new UriBuilder(authoriseRedirectUrl);
uriBuilder.Query = "?client_id=" + clientID
uriBuilder.Query += "&redirect_uri=" + redirectUrl
uriBuilder.Query += "&scope=read_write"
uriBuilder.Query += "&response_type=code"
uriBuilder.Query += "&prefill[email]=tim@gocardless.com"
uriBuilder.Query += "&prefill[given_name]=Tim"
uriBuilder.Query += "&prefill[family_name]=Rogers"
uriBuilder.Query += "&prefill[organisation_name]=Fishing%20Store"
uriBuilder.Query += "&prefill[country_code]=GB"
Response.Redirect(uriBuilder.ToString());
}
With these parameters set correctly, the resulting URL will have the following format:
https://connect-sandbox.gocardless.com/oauth/authorize?client_id=myid&initial_view=signup&prefill%5Bemail%5D=tim%40gocardless.com&redirect_uri=https%3A%2F%2Facme.enterprises%2Fredirect&response_type=code&scope=read_only
Run this code to generate a link to the OAuth flow. Head over to the link you’ve just generated in an Incognito window, and you’ll see our OAuth flow.
Getting an access token
On the signup form, we recommend creating a second sandbox account using a different email address. This will replicate what your users will experience when connecting to your partner integration, and will give you an example account which you can use from the perspective of one of your users.
Once your user has either signed up or logged in, and then approved your app’s
access to their account, they’ll be sent to your app’s redirect URI with a temporary
code
which you’ll see in the query parameters, as well as any state
you provided.
You should use the OAuth client library we set up earlier to fetch an
access token using the code
. This is a permanent access token which allows you to use
the API on behalf of your merchant at any time.
<?php
require 'vendor/autoload.php';
$client = new OAuth2\Client(getenv('GOCARDLESS_CLIENT_ID'),
getenv('GOCARDLESS_CLIENT_SECRET'));
// You'll need to use exactly the same redirect URI as in the last step
$response = $client->getAccessToken(
'https://connect-sandbox.gocardless.com/oauth/access_token',
'authorization_code',
['code' => $_GET['code'], 'redirect_uri' => 'https://acme.enterprises/redirect']
);
$payload = ['gocardless_access_token' => $response['result']['access_token'],
'gocardless_organisation_id' => $response['result']['organisation_id']];
$currentUser->update($payload);
import os
from oauth2client.client import OAuth2WebServerFlow
# You should store your client ID and secret in environment variables rather than
# committing them with your code
flow = OAuth2WebServerFlow(
client_id=os.environ['GOCARDLESS_CLIENT_ID'],
client_secret=os.environ['GOCARDLESS_CLIENT_SECRET'],
scope="read_write",
# You'll need to use exactly the same redirect URI as in the last step
redirect_uri="https://acme.enterprises/redirect",
# Once you go live, this should be set to https://connect.gocardless.com. You'll
# also need to create a live app and update your client ID and secret.
auth_uri="https://connect-sandbox.gocardless.com/oauth/authorize",
token_uri="https://connect-sandbox.gocardless.com/oauth/access_token",
initial_view="signup"
)
access_token = flow.step2_exchange(request.args.get('code'))
# You should store the user's access token - you'll need it to make API requests on their
# behalf in future. If you want to handle webhooks for your users, you should also store
# their organisation ID which will allow you to identify webhooks belonging to them.
current_user.update(
gocardless_access_token=access_token.access_token,
gocardless_organisation_id=access_token.token_response['organisation_id']
)
require 'oauth2'
# You should store your client ID and secret in environment variables rather than
# committing them with your code
oauth = OAuth2::Client.new(ENV['GOCARDLESS_CLIENT_ID'],
ENV['GOCARDLESS_CLIENT_SECRET'],
# Once you go live, this should be set to
# https://connect.gocardless.com. You'll also need to create
# a live app and update your client ID and secret.
site: 'https://connect-sandbox.gocardless.com',
authorize_url: '/oauth/authorize',
token_url: '/oauth/access_token')
access_token = oauth.auth_code.get_token(
params[:code],
# You'll need to use exactly the same access token as you did in the last step
redirect_uri: 'https://acme.enterprises/redirect'
)
# You should store the user's access token - you'll need it to make API requests on their
# behalf in future. If you want to handle webhooks for your users, you should also store
# their organisation ID which will allow you to identify webhooks belonging to them.
current_user.update!(gocardless_access_token: access_token.token,
gocardless_organisation_id: access_token['organisation_id'])
// See https://raw.githubusercontent.com/gocardless/gocardless-pro-java-maven-example/master/src/main/java/hello/OAuthController.java
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class OAuthController {
private static final String accessTokenUrl =
"https://connect-sandbox.gocardless.com/oauth/access_token";
private static final String redirectUri =
"https://bb314345.ngrok.io/redirect";
private static final String clientID =
System.getenv("GOCARDLESS_CLIENT_ID");
private static final String clientSecret =
System.getenv("GOCARDLESS_CLIENT_SECRET");
private static final OkHttpClient client =
new OkHttpClient();
private String getAccessToken(String oauthCode) throws IOException {
RequestBody body = new FormBody.Builder()
.add("client_id", clientID)
.add("client_secret", clientSecret)
.add("redirect_uri", redirectUri)
.add("grant_type", "authorization_code")
.add("code", oauthCode)
.build();
Request request = new Request.Builder()
.url(accessTokenUrl)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
@GetMapping("/redirect")
public String loggedIn(@RequestParam("code") String oauthCode) throws IOException {
String accessToken = getAccessToken(oauthCode);
System.out.println("Save the access token " +
accessToken + " to your database.");
return "Greetings!";
}
}
// This is example code and must be inserted into you application structure
private readonly string accessTokenUrl = "https://connect-sandbox.gocardless.com/oauth/access_token";
private readonly string redirectUrl = "https://acme.enterprises/redirect";
private readonly string clientID = Environment.GetEnvironmentVariable("GOCARDLESS_CLIENT_ID");
private readonly string clientSecret = Environment.GetEnvironmentVariable("GOCARDLESS_CLIENT_SECRET");
public Task<string> RedirectHandler(request Request) {
var oauthCode = request.Query["code"].ToString();
using (HttpClient client = new HttpClient()) {
using (MultipartFormDataContent data = new MultipartFormDataContent())
{
data.Add(new StringContent(clientID), "client_id");
data.Add(new StringContent(clientSecret), "client_secret");
data.Add(new StringContent(redirectUrl), "redirect_uri");
data.Add(new StringContent("authorization_code"), "grant_type");
data.Add(new StringContent(redirectUrl), "redirect_uri");
data.Add(new StringContent(oauthCode), "code");
var response = await client.PostAsync(accessTokenUrl, data);
var accessToken = response.Content
return accessToken;
}
}
}
Whether you are developing a mobile, web, or desktop application, it is important not to
pass the client secret to your user’s device as it could be used to impersonate your app.
The process of exchanging a code
for an access token should be done on your server so
your client secret can be kept private.
You’ll want to store this access token in your database for use in the future to make requests to the GoCardless API on your user’s behalf. Make sure you keep it safe and secure, as it gives full access to your user’s account.
We’d also strongly advise storing your user’s GoCardless organisation ID. Later on, we’ll set up webhooks to keep your integration up to date as things happen to your users’ mandates and payments. You’ll need to use the organisation ID included in these webhooks to work out which of your users a particular event relates to.
If the redirect URL isn’t the page where you ultimately want your user to arrive, you can redirect them from here to the right place, either before or after exchanging the code for an access token.
Once you’ve stored your merchant’s access token, we’d suggest presenting your customers with any relevant configuration options for the integration (e.g. setting how failed payments should be handled).
We’d also recommend providing in-product tips or links to support materials and letting customers know that they’ll need to verify their account in order to receive payouts (they’ll also receive emails from us reminding them to do this).
Handling Disconnections
As a partner, you may be disconnected from a merchant for two reasons: the merchant can revoke your access or the merchant’s GoCardless account can be closed.
If you need to cleanup any data on your side, we will send you a special, final webhook when this happens. Since the shared access token will have been revoked, you will be unable to make any further API calls to GoCardless, so we suggest you reach out to the user directly if you think this has happened in error.
This webhook is designed to look similar to other webhooks, i.e. it is wrapped in the events
key. However, there is no associated event, so the event id
is null
. It also means you cannot immediately run a GET for the organisation details (as recommended for other webhook types), as the shared access token has been revoked.
You can identify this event as it has resource_type organisations
and action disconnected
.
As an example, we’ll write a handler for this ‘special’ webhook:
<?php
function process_organisation_event($event)
{
switch ($event->action) {
case "disconnected":
print("Organisation " . $event->links->organisation . " has been disconnected!\n");
MarkOrganisationAsDisconnected($event->links->organisation);
break;
default:
print("Don't know how to process an organisation " . $event->action . " event\n");
break;
}
}
$webhook_endpoint_secret = getenv("GOCARDLESS_WEBHOOK_ENDPOINT_SECRET");
$request_body = file_get_contents('php://input');
$headers = getallheaders();
$signature_header = $headers["Webhook-Signature"];
try {
$events = \GoCardlessPro\Webhook::parse($request_body,
$signature_header,
$webhook_endpoint_secret);
foreach ($events as $event) {
print("Processing event " . $event->id . "\n");
switch ($event->resource_type) {
case "organisations":
process_organisation_event($event);
break;
default:
print("Don't know how to process an event with resource_type " . $event->resource_type . "\n");
break;
}
}
header("HTTP/1.1 200 OK");
} catch(\GoCardlessPro\Core\Exception\InvalidSignatureException $e) {
header("HTTP/1.1 498 Invalid Token");
}
# Here, we're using a Django view, but essentially the same code will work in
# other Python web frameworks (e.g. Flask) with minimal changes
import os
import logging
from django.views.generic import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.http import HttpResponse
from gocardless_pro import webhooks, Client
from gocardless_pro.errors import InvalidSignatureError
from myinvoicingapp.models import GoCardlessEvent
# Handle the incoming Webhook and perform an action with the Webhook data.
class Webhook(View):
logger = logging.getLogger(__name__)
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(Webhook, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
try:
for event in self._get_events(request):
self.process(event)
return HttpResponse(204)
except InvalidSignatureError:
return HttpResponse(498)
def process(self, event):
self.logger.info("Processing event {}\n".format(event.id))
if event.resource_type == 'organisations':
return self.process_organisation_event(event)
# ... Handle other resource types
else:
self.logger.info("Don't know how to process an event with \
resource_type {}\n".format(event.resource_type))
def process_organisation_event(self, event):
if event.action == 'disconnected':
self.logger.info(
"Organisation {} has been disconnected\n".
format(event.links.organisation)
)
else:
self.logger.info("Don't know how to process an event with \
resource_type {}\n".format(event.resource_type))
def _get_events(self, request):
secret = os.environ['GC_WEBHOOK_SECRET']
signature = request.META["HTTP_WEBHOOK_SIGNATURE"]
body = request.body.strip()
return webhooks.parse(body, secret, signature)
require 'gocardless_pro'
class OrganisationEventProcessor
def self.process(event, response)
case event.action
when 'disconnected'
response.stream.write("Organisation #{event.links.organisation} has been disconnected\n")
DisconnectOrganisation.enqueue(event['links']['organisation'])
else
response.stream.write(
"Don't know how to process a organisation #{event.action} event\n"
)
end
end
end
def create
# We recommend storing your webhook endpoint secret in an environment variable
# for security
webhook_endpoint_secret = ENV['GOCARDLESS_WEBHOOK_ENDPOINT_SECRET']
# In a Rack app (e.g. Sinatra), access the POST body with
# `request.body.tap(&:rewind).read`
request_body = request.raw_post
# In a Rack app (e.g. Sinatra), the header is available as
# `request.env['HTTP_WEBHOOK_SIGNATURE']`
signature_header = request.headers['Webhook-Signature']
begin
events = GoCardlessPro::Webhook.parse(request_body: request_body,
signature_header: signature_header,
webhook_endpoint_secret: webhook_endpoint_secret)
events.each do |event|
# We're using Rails's streaming functionality here to write directly to the
# response rather than using views, as one would usually.
response.stream.write("Processing event #{event.id}\n")
case event.resource_type
when 'organisations'
OrganisationEventProcessor.process(event, response)
else
response.stream.write(
"Don't know how to process an event with resource_type #{event.resource_type}\n"
)
end
end
response.stream.close
render status: 200
rescue GoCardlessPro::Webhook::InvalidSignatureError
render status: 498
end
end
package hello;
// Use the POM file at
// https://raw.githubusercontent.com/gocardless/gocardless-pro-java-maven-example/master/pom.xml
import com.gocardless.errors.InvalidSignatureException;
import com.gocardless.resources.Event;
import com.gocardless.Webhook;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.http.ResponseEntity;
@RestController
public class HelloController {
private String processDisconnections(Event event) {
switch (event.getAction()) {
case "disconnected":
// here, you probably want to mark the organisation as disconnected
// and stop sending any requests on their behalf
return "Organisation " + event.getLinks().getOrganisation() +
" has been cancelled.\n";
default:
return "Do not know how to process an event with action " +
event.getAction() + ".\n";
}
}
private String processEvent(Event event) {
switch (event.getResourceType()) {
case ORGANISATIONS:
return processDisconnections(event);
default:
return "Don't know how to process an event of resource_type " +
event.getResourceType().toString() + ".\n";
}
}
@PostMapping("/")
public ResponseEntity<String> handlePost(
@RequestHeader("Webhook-Signature") String signatureHeader,
@RequestBody String requestBody) {
String webhookEndpointSecret = System.getenv("GOCARDLESS_WEBHOOK_ENDPOINT_SECRET");
try {
List<Event> events = Webhook.parse(requestBody, signatureHeader, webhookEndpointSecret);
String responseBody = "";
for (Event event : events) {
responseBody += processEvent(event);
}
return new ResponseEntity<String>(responseBody, HttpStatus.OK);
} catch(InvalidSignatureException e) {
return new ResponseEntity<String>("Incorrect Signature", HttpStatus.BAD_REQUEST);
}
}
}
POST https://example.com/webhooks HTTP/1.1
Content-Type: application/json
{
"events": [
{
"id": null,
"created_at": "2018-08-03T12:00:00.000Z",
"action": "disconnected",
"resource_type": "organisations",
"links": {
"organisation": "OR123"
},
"details": {
"cause": "app_disconnected",
"origin": "gocardless",
"description": "Your app has been has disconnected from this organisation"
},
"metadata": {}
}
]
}