Stay up to date with webhooks
Staying up-to-date with webhooks
A webhook is a request that GoCardless sends to your server to alert you of an event. Adding support for webhooks allows you to receive real-time notifications from GoCardless when things happen in your account, so you can take automated actions in response, for example:
When a payment fails due to lack of funds, retry it automatically
When a customer cancels their mandate with the bank, suspend their account
When a customer’s subscription generates a new payment, you can record that payment against their account
Create a webhook endpoint
To start receiving webhooks, you’ll need to add a webhook endpoint from your Dashboard here.
Simply enter the HTTPS URL from earlier and add on the path where your webhook handler will be available, give your endpoint a name, and then click “Create webhook endpoint”. Next, click on your new endpoint in the list and copy the secret to your clipboard.
Build a webhook handler
Let’s get started by building our first webhook handler. Webhooks are HTTP POST requests made to the URL you provided, with a JSON body. See an example below.
1POST https://example.com/webhooks HTTP/1.1
2User-Agent: gocardless-webhook-service/1.1
3Content-Type: application/json
4Webhook-Signature: 78e3507f61f141046969c73653402cb50b714f04322da04d766ee0f6d2afe65f
5
6{
7 "events": [
8 {
9 "id": "EV123",
10 "created_at": "2014-08-04T12:00:00.000Z",
11 "action": "cancelled",
12 "resource_type": "mandates",
13 "links": {
14 "mandate": "MD123",
15 "organisation": "OR123"
16 },
17 "details": {
18 "origin": "bank",
19 "cause": "bank_account_disabled",
20 "description": "Your customer closed their bank account.",
21 "scheme": "bacs",
22 "reason_code": "ADDACS-B"
23 }
24 }
25 ]
26}
Secure your webhooks
The first step to take when you receive a webhook is to check its signature - this makes sure that is genuinely from GoCardless and hasn’t been forged. A signature is provided in the Webhook-Signature
header of the request. We just need to compute the signature ourselves using the POST
ed JSON and the webhook endpoint’s secret (which we copied earlier), and compare it to the one in the header.
If they match, the webhook is genuine, because only you and GoCardless know the secret. It’s important that you keep the secret safe, and change it periodically using the Dashboard.
We can verify the signature like this:
1<?php
2// We recommend storing your webhook endpoint secret in an environment variable
3// for security
4$webhook_endpoint_secret = getenv("GOCARDLESS_WEBHOOK_ENDPOINT_SECRET");
5$request_body = file_get_contents('php://input');
6
7$headers = getallheaders();
8$signature_header = $headers["Webhook-Signature"];
9
10try {
11 $events = \GoCardlessPro\Webhook::parse($request_body,
12 $signature_header,
13 $webhook_endpoint_secret);
14
15 // Process the events...
16
17 header("HTTP/1.1 204 No Content");
18} catch(\GoCardlessPro\Core\Exception\InvalidSignatureException $e) {
19 header("HTTP/1.1 498 Invalid Token");
20}
Processing events
A webhook can contain multiple events, and each has a resource_type
(telling us what kind of resource the event is for, for example, “payments” or “mandates”), an action
(telling us what happened to the resource, for example, the cancelled
action for a mandate) and details
(specifying why the event happened).
You can see a full list of the possible combinations in the reference docs.
As an example, we’ll write a handler for when a mandate is cancelled:
1<?php
2function process_mandate_event($event)
3{
4 switch ($event->action) {
5 case "cancelled":
6 print("Mandate " . $event->links->mandate . " has been cancelled!\n");
7
8 // You should keep some kind of record of what events have been processed
9 // to avoid double-processing
10 //
11 // $event = Event::where("gocardless_id", $event->id)->first();
12
13 // You should perform processing steps asynchronously to avoid timing out if
14 // you receive many events at once. To do this, you could use a queueing
15 // system like Beanstalkd
16 //
17 // http://george.webb.uno/posts/sending-php-email-with-mandrill-and-beanstalkd
18 //
19 // Once you've performed the actions you want to perform for an event, you
20 // should make a record to avoid accidentally processing the same one twice.
21 CancelServiceAndNotifyCustomer::performAsynchronously($event->links->mandate);
22 break;
23 default:
24 print("Don't know how to process a mandate " . $event->action . " event\n");
25 break;
26 }
27}
28
29// We recommend storing your webhook endpoint secret in an environment variable
30// for security
31$webhook_endpoint_secret = getenv("GOCARDLESS_WEBHOOK_ENDPOINT_SECRET");
32$request_body = file_get_contents('php://input');
33
34$headers = getallheaders();
35$signature_header = $headers["Webhook-Signature"];
36
37try {
38 $events = \GoCardlessPro\Webhook::parse($request_body,
39 $signature_header,
40 $webhook_endpoint_secret);
41
42 foreach ($events as $event) {
43 print("Processing event " . $event->id . "\n");
44
45 switch ($event->resource_type) {
46 case "mandates":
47 process_mandate_event($event);
48 break;
49 default:
50 print("Don't know how to process an event with resource_type " . $event->resource_type . "\n");
51 break;
52 }
53 }
54
55 header("HTTP/1.1 200 OK");
56} catch(\GoCardlessPro\Core\Exception\InvalidSignatureException $e) {
57 header("HTTP/1.1 498 Invalid Token");
58}
Send a test webhook again, just like the one you sent before, and then click on it in the list. You’ll see a response at the bottom like this:
Processing event EVTEST8XP9DCPK
Mandate index_ID_123 has been cancelled!
We’ll send webhooks exactly like this when real events happen in your account.
You can add support for as many differ resource_type
s and action
s as you like, and make use of all of the other data we give you with events.
Test your webhook handler
Using the Dashboard
In the Dashboard, the “Send test webhook” functionality makes it easy to start experimenting with webhooks. Select the webhook endpoint you created earlier, set the Resource type of mandates
and the action to cancelled
. You can set the cause and event details however you like. Then, click “Send test webhook”.
Using the GC CLI Sandbox
You can use the gc
CLI to locally test your webhook integrations. Each event from GoCardless contains an Event object with a link referencing the resource that was modified. The CLI can be used to trigger these events and inspect their output or even forward them to your server's webhook handler.
Using the Scenario Simulator Sandbox
In the sandbox environment, we provide scenario simulators that allow you to manually trigger certain cases so you can test how your integration responds. These are available in the Developer section of the dashboard and through the API.
Using TLS client authentication
Using TLS enables us to encrypt data in transit. However, additional security can be achieved by using client authentication in addition to server authentication.
Client authentication adds an extra check in the TLS handshake to validate that the client is authorised to access the endpoint. In this case, it enables you to be certain that it is GoCardless making a request to your webhook endpoint, and not (for example) a malicious entity attempting to spoof GoCardless.
To authorise GoCardless to send webhooks, you need to provide a valid certificate and private key issued by your certificate authority. In practice, this can be a self-signed certificate, and useful instructions for generating certificates can be found in the CoreOS documentation, using Cloudflare’s cfssl toolkit. Note that for the time being, we only support RSA keypairs. We recommend setting a long lifetime for the certificate to avoid unnecessary management overhead.
Once generated, the certificate and key must be entered into the webhook endpoint form in the developers section of the GoCardless dashboard. Both certificate and key must be provided in base64-encoded PEM format.
All subsequent requests from the webhook system will be client-authenticated.
The main disadvantage to using this feature is the overhead of creating, renewing and otherwise managing client certificates. It is up to you to balance this overhead against the additional security risk.
Related Guides
Responding to Billing Requests events