Webhooks

This section of the documentation would help you learn how to listen to events when actions occur on your profile

What are webhooks?

As a bank, various activities are constantly happening by the second across many accounts and whenever these actions occur on your profile, we trigger events which your application can listen for.

This is where webhooks come in. A webhook is a URL on your server where we send a JSON payload over HTTP as such events occur. For example, if you implement webhooks, once a payment is completed -- whether successful or failed -- we will immediately notify your server with a payable.completed event.

Webhooks on Brass

Webhooks are broken into scopes -- scopes define the domain within which an action is happening and scopes contain events.

Let's look at an example, we have the payable scope which describes activities involving Instant Payments and it has the completed event which indicates that all actions on the resource are done (nothing else will happen on the Payment) -- when the webhook is fired, it will come with event name payable.completed.

Enabling webhook notifications

Webhooks are not enabled by default for users. Visit the Update Customer Preferences section of the documentation to see how to enable or disable webhooks.

Supported Events

Below, you'll find the most important scoped events in Brass

ScopeDescription
account.createdAn account has just been created on your customer profile. This is important when dealing with subaccounts
account.creditedOne of your accounts has just been credited with funds
account.debitedOne of your accounts has just been debited for funds
payable.auth_concludedAuthorisations have been concluded on the payment. This means it has entered hold-off or has been declined
payable.completedProcessing for the payment has concluded -- it can either be successful or failed.
payable.createdA payment has been created on your customer profile
payable.hold_offA payment has gone into hold-off mode -- this is the grace period within which it can be cancelled after it has been successfully approved
payment_request.createdAn invoice has been created on your customer profile
payment_request.status_updatedThe status of the invoice has been update (for instance, it was marked as paid)

Verifying webhook events

It is very important to always verify that events that reach your webhook endpoint actually originated from Brass. You can do so by validating the signature of the webhook.

📘

Brass webhook events are sent with an added header called X-Brass-Signature which is the HMAC SHA256 signature of the event payload signed using your webhook secret key.

var crypto = require('crypto');

// webhook secret key set on your profile
var secret = process.env.SECRET_KEY;

// using Express
app.post("/my/webhook/url", function(req, res) {
  	// retrieve the request's body
  	const event = req.body;
  
  	// validate event
    const hash = crypto.createHmac('sha256', secret)
    	.update(JSON.stringify(event))
    	.digest('hex');
  
  	// return appropriate response if the request hash does not match the header
    if (hash != req.headers['X-Brass-Signature']) {
      return res.status(401).json({message: "Unauthorized request."});
    }
  
    // do something with event  
  
    res.send(200);
  
});
// using Slim 4 framework

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

$app->post("/my/webhook/url", function (Request $request, Response $response) {
  
    // calculate the hash of the request
    $calculatedHash = hash_hmac(
        'SHA256',
        $request->getBody()->getContents(),
        $_ENV('BRASS_WEBHOOK_SECRET_KEY')
    );

    $response->withHeader('Content-Type', 'application/json');

    // return appropriate response if calculated hash is not equal to header
    if ($calculatedHash !== $request->getHeader('X-Brass-Signature')) {
        $data = ['message' => "Unauthorized request"];

        $response->getBody()->write(json_encode($data));

        return $response->withStatus(401);
    }

    // do something with the request body

    return $response->withStatus(200);
});

Responding to webhook events

You should respond to an event with a 200 OK. We consider this an acknowledgement by your application. If your application responds with any status outside of the 2xx range, we will consider it unacknowledged and thus retry 3 more times.

You don't need to send a request body or some other parameter as it would be discarded - we only pay attention to the status code.

🚧

If your application is likely to start a long running task in response to the event, Brass may timeout waiting for the response and would ultimately consider the event unacknowledged and queue to be raised later. You can mitigate this by having your application respond immediately with a 200 before it goes on to perform the rest of the task in the background

Webhook Samples

{
  "event": "payable.completed",
  "data": {
    "embeds": [
      "authorizations",
      "attachments",
      "customer",
      "counterparties",
      "initiated_by",
      "payment_request",
      "recurring_payment_mandate",
      "source_account",
      "tags"
    ],
    "id": "pay_4JbTQ4dQZZGSzx3xwH4B1u",
    "customer_reference": null,
    "title": "We're paying up to the kobo",
    "description": "The level of accuracy with this payment is very refreshing",
    "currency": "NGN",
    "amount": {
      "raw": "1567025",
      "formatted": "15670.25",
      "formatted_display": "₦15,670.25"
    },
    "fee": {
      "raw": "0",
      "formatted": "0.00",
      "formatted_display": "₦0.00"
    },
    "status": "success",
    "hold_off_ends_at": "2021-06-03T16:04:23+01:00",
    "scheduled_for": null,
    "paid_at": null,
    "is_trashed": false,
    "deleted_at": null,
    "created_at": "2021-06-02T08:56:45+01:00",
    "updated_at": "2021-06-03T16:10:02+01:00",
    "display_status": "Success",
    "is_recurring": false,
    "recurring_payment_mandate_id": null,
    "counterparties_count": null,
    "failure_reason": null,
    "authorizations": {
      "data": [
        {
          "embeds": [
            "authorizable",
            "customer",
            "user"
          ],
          "id": "aut_uYXa1rQGu3xR54VDKRqE0",
          "is_required": true,
          "status": "approved",
          "comment": "Approve",
          "responded_at": "2021-06-03T15:04:21+01:00",
          "created_at": "2021-06-02T08:56:45+01:00",
          "updated_at": "2021-06-03T15:04:21+01:00",
          "authorizable_type": "payment",
          "user": {
            "data": {
              "embeds": [
                "addresses",
                "customers",
                "role",
                "partner",
                "agent"
              ],
              "id": "usr_vwrVsHrHwrynXO9sMrdpx",
              "firstname": "Octonauts",
              "lastname": "Assemble",
              "phone": "+2348123320811",
              "password": null,
              "email": "[email protected]",
              "remember_token": null,
              "gender": null,
              "photo_url": "https://s3.eu-west-1.amazonaws.com/sandbox-private.getbrass.co/cus_1Gdl3cC14y6nUOoxOPhPcz/bb693e28-a393-48cc-9792-9a3fc1d39297.jpeg",
              "email_verified": false,
              "email_verified_at": null,
              "disabled_at": null,
              "is_trashed": false,
              "deleted_at": null,
              "created_at": "2020-08-23T11:55:07+01:00",
              "updated_at": "2021-05-05T14:15:01+01:00",
              "preferences": {
                "security": {
                  "enabled_2fa": true,
                  "otp_channel": "email"
                }
              },
              "role": {
                "data": {
                  "embeds": [
                    "permissions"
                  ],
                  "id": "rol_7h8f07GPpE17GGgrBA2vmN",
                  "name": "business.owner",
                  "display_name": "Owner",
                  "is_active": true,
                  "is_restricted": true,
                  "created_at": "2020-03-23T22:41:20+01:00",
                  "updated_at": "2020-03-23T22:41:20+01:00",
                  "abilities": {
                    "dashboard": {
                      "section": "Dashboard",
                      "abilities": [
                        "Full access to all dashboard services",
                        "Read cash flow, cash-in and cash-out"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "account": {
                      "section": "Account",
                      "abilities": [
                        "Access to company accounts",
                        "Download company statements"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "invoices": {
                      "section": "Invoices",
                      "abilities": [
                        "Can prepare all invoices",
                        "Can read all invoices"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "payments": {
                      "section": "Payments",
                      "abilities": [
                        "Can prepare all payments",
                        "If required, can approve all payments",
                        "Can read all payments",
                        "Can cancel all payments"
                      ],
                      "lacks_abilities": [],
                      "is_important": true
                    },
                    "team_management": {
                      "section": "Team management",
                      "abilities": [
                        "Can manage: add, remove new team members",
                        "Can change the privileges of other team members",
                        "Can remove another owner without their permission"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "contact_management": {
                      "section": "Contact management",
                      "abilities": [
                        "Can manage: add, remove contacts",
                        "Can read payments and transactions for all contacts"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "company_settings": {
                      "section": "Company settings",
                      "abilities": [
                        "Can update company profile including documents",
                        "Can update company settings",
                        "Can reset company account preferences"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    }
                  }
                }
              }
            }
          }
        },
        {
          "embeds": [
            "authorizable",
            "customer",
            "user"
          ],
          "id": "aut_58OCgcANODJ21lPHdd39di",
          "is_required": false,
          "status": "unprocessed",
          "comment": null,
          "responded_at": null,
          "created_at": "2021-06-02T08:56:45+01:00",
          "updated_at": "2021-06-02T08:56:45+01:00",
          "authorizable_type": "payment",
          "user": {
            "data": {
              "embeds": [
                "addresses",
                "customers",
                "role",
                "partner",
                "agent"
              ],
              "id": "usr_7b8WPGR2brnzg2GHEwAYn3",
              "firstname": "Simi",
              "lastname": "Jombo",
              "phone": null,
              "password": null,
              "email": "[email protected]",
              "remember_token": null,
              "gender": null,
              "photo_url": null,
              "email_verified": false,
              "email_verified_at": null,
              "disabled_at": null,
              "is_trashed": false,
              "deleted_at": null,
              "created_at": "2020-10-01T12:45:00+01:00",
              "updated_at": "2020-10-01T12:45:00+01:00",
              "preferences": {
                "security": {
                  "enabled_2fa": true,
                  "otp_channel": "email"
                }
              },
              "role": {
                "data": {
                  "embeds": [
                    "permissions"
                  ],
                  "id": "rol_LbhnugthyweEB151E6On4",
                  "name": "business.admin",
                  "display_name": "Admin",
                  "is_active": true,
                  "is_restricted": true,
                  "created_at": "2020-05-15T07:04:11+01:00",
                  "updated_at": "2020-05-15T07:04:11+01:00",
                  "abilities": {
                    "dashboard": {
                      "section": "Dashboard",
                      "abilities": [
                        "Full access to all dashboard services",
                        "Read cash flow, cash-in and cash-out"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "account": {
                      "section": "Account",
                      "abilities": [
                        "Access to company accounts",
                        "Download company statements"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "invoices": {
                      "section": "Invoices",
                      "abilities": [
                        "Can prepare all invoices",
                        "Can read all invoices"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "payments": {
                      "section": "Payments",
                      "abilities": [
                        "Can prepare all payments",
                        "If required, can approve all payments",
                        "Can read all payments",
                        "Can cancel all payments"
                      ],
                      "lacks_abilities": [],
                      "is_important": true
                    },
                    "team_management": {
                      "section": "Team management",
                      "abilities": [
                        "Can manage: add, remove new team members",
                        "Can change the privileges of other team members"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "contact_management": {
                      "section": "Contact management",
                      "abilities": [
                        "Can manage: add, remove contacts",
                        "Can read payments and transactions for all contacts"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "company_settings": {
                      "section": "Company settings",
                      "abilities": [
                        "Can update company profile including documents",
                        "Can update company settings",
                        "Can reset company account preferences"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    }
                  }
                }
              }
            }
          }
        },
        {
          "embeds": [
            "authorizable",
            "customer",
            "user"
          ],
          "id": "aut_7hiPsSkjFBK6UpBGnOFLr5",
          "is_required": false,
          "status": "unprocessed",
          "comment": null,
          "responded_at": null,
          "created_at": "2021-06-02T08:56:45+01:00",
          "updated_at": "2021-06-02T08:56:45+01:00",
          "authorizable_type": "payment",
          "user": {
            "data": {
              "embeds": [
                "addresses",
                "customers",
                "role",
                "partner",
                "agent"
              ],
              "id": "usr_KHf0B0bPWwBBhOgDckHfc",
              "firstname": "Bowale",
              "lastname": "Omode",
              "phone": null,
              "password": null,
              "email": "[email protected]",
              "remember_token": null,
              "gender": null,
              "photo_url": null,
              "email_verified": false,
              "email_verified_at": null,
              "disabled_at": null,
              "is_trashed": false,
              "deleted_at": null,
              "created_at": "2020-10-05T17:10:47+01:00",
              "updated_at": "2020-10-05T17:10:47+01:00",
              "preferences": {
                "security": {
                  "enabled_2fa": true,
                  "otp_channel": "email"
                }
              },
              "role": {
                "data": {
                  "embeds": [
                    "permissions"
                  ],
                  "id": "rol_LbhnugthyweEB151E6On4",
                  "name": "business.admin",
                  "display_name": "Admin",
                  "is_active": true,
                  "is_restricted": true,
                  "created_at": "2020-05-15T07:04:11+01:00",
                  "updated_at": "2020-05-15T07:04:11+01:00",
                  "abilities": {
                    "dashboard": {
                      "section": "Dashboard",
                      "abilities": [
                        "Full access to all dashboard services",
                        "Read cash flow, cash-in and cash-out"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "account": {
                      "section": "Account",
                      "abilities": [
                        "Access to company accounts",
                        "Download company statements"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "invoices": {
                      "section": "Invoices",
                      "abilities": [
                        "Can prepare all invoices",
                        "Can read all invoices"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "payments": {
                      "section": "Payments",
                      "abilities": [
                        "Can prepare all payments",
                        "If required, can approve all payments",
                        "Can read all payments",
                        "Can cancel all payments"
                      ],
                      "lacks_abilities": [],
                      "is_important": true
                    },
                    "team_management": {
                      "section": "Team management",
                      "abilities": [
                        "Can manage: add, remove new team members",
                        "Can change the privileges of other team members"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "contact_management": {
                      "section": "Contact management",
                      "abilities": [
                        "Can manage: add, remove contacts",
                        "Can read payments and transactions for all contacts"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    },
                    "company_settings": {
                      "section": "Company settings",
                      "abilities": [
                        "Can update company profile including documents",
                        "Can update company settings",
                        "Can reset company account preferences"
                      ],
                      "lacks_abilities": [],
                      "is_important": false
                    }
                  }
                }
              }
            }
          }
        }
      ]
    },
    "attachments": {
      "data": [
        {
          "embeds": [
            "attached_to",
            "customer",
            "uploaded_by"
          ],
          "id": "att_7e7b9A97DpCwKAXfH2r9HE",
          "filename": "https://s3.eu-west-1.amazonaws.com/sandbox-private.getbrass.co/cus_1Gdl3cC14y6nUOoxOPhPcz/07cb4719-4e20-4045-8f5e-71c41beb4f63.jpeg?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAYOX7CAIIYQ2GESN7%2F20210603%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20210603T151004Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=e4ceadaa00ccd037352187e28937c150cb1e5a09e60de5e5469a1f3ff357e54b",
          "note": "begging-meme.jpeg",
          "created_at": "2021-06-02T08:56:45+01:00",
          "updated_at": "2021-06-02T08:56:45+01:00",
          "attached_to_type": "payment",
          "uploaded_by": {
            "data": {
              "embeds": [
                "addresses",
                "customers",
                "role",
                "partner",
                "agent"
              ],
              "id": "usr_677kDUWkAdGJMrhppCDB8W",
              "firstname": "Octonaut",
              "lastname": "Pay",
              "phone": "+2348123320811",
              "password": null,
              "email": "[email protected]",
              "remember_token": null,
              "gender": null,
              "photo_url": null,
              "email_verified": false,
              "email_verified_at": null,
              "disabled_at": null,
              "is_trashed": false,
              "deleted_at": null,
              "created_at": "2020-09-02T10:04:10+01:00",
              "updated_at": "2021-05-18T17:00:44+01:00",
              "preferences": {
                "security": {
                  "enabled_2fa": true,
                  "otp_channel": "email"
                }
              }
            }
          }
        }
      ]
    },
    "customer": {
      "data": {
        "embeds": [
          "accounts",
          "addresses",
          "country",
          "customer_type",
          "industry",
          "preferred_branch",
          "partner"
        ],
        "id": "cus_1Gdl3cC14y6nUOoxOPhPcz",
        "domain_slug": null,
        "name": "Octonauts Ltd",
        "registered_name": "Octonauts Ltd",
        "description": "Pay your transportation fare with this",
        "contact_firstname": "Octonauts",
        "contact_lastname": "Assemble",
        "contact_phone": "+2348123320811",
        "contact_email": "[email protected]",
        "channel": "direct",
        "logo_url": null,
        "is_registered": false,
        "is_onboarding_completed": true,
        "onboarding_completed_at": "2020-08-27T13:30:33+01:00",
        "approved_auto_verification_at": null,
        "kyc_verified_at": "2020-08-27T13:31:46+01:00",
        "legal_search_started_at": "2020-10-07T13:14:30+01:00",
        "kyc_completed_at": null,
        "disabled_at": null,
        "is_trashed": false,
        "deleted_at": null,
        "created_at": "2020-08-23T11:55:07+01:00",
        "updated_at": "2021-05-04T16:27:27+01:00",
        "customer_id": "001743",
        "scoped_customer_id": 54,
        "welcome_tracker": [
          "welcome-pack"
        ],
        "preferences": {
          "webhook_enabled": true,
          "webhook_url": "https://enyy64yxbbytl8y.m.pipedream.net",
          "cashflow_questionnaire_submitted": false
        },
        "customer_type": {
          "data": {
            "embeds": [
              "country"
            ],
            "id": "cty_2Far8Fl7n0WoKsXt8gIxzc",
            "label": "sole proprietorship",
            "display_name": "Sole Proprietorship",
            "is_trashed": false,
            "deleted_at": null,
            "created_at": "2020-03-23T23:14:02+01:00",
            "updated_at": "2020-03-23T23:14:02+01:00"
          }
        }
      }
    },
    "counterparties": {
      "data": [
        {
          "embeds": [
            "customer",
            "added_by_user",
            "counterparty",
            "disbursements",
            "transactable"
          ],
          "id": "cpt_7KXhpeLKXTRlMJE7Qr34Br",
          "status": "unprocessed",
          "responded_at": null,
          "created_at": "2021-06-02T08:56:45+01:00",
          "updated_at": "2021-06-02T08:56:45+01:00",
          "counterparty_type": "contact",
          "transactable_type": "payment",
          "counterparty": {
            "data": {
              "embeds": [
                "customer",
                "contact_tag",
                "added_by_user",
                "recipient_customer_profile",
                "bank"
              ],
              "id": "con_1W8RJVzuqqCEYgC8RhzHu1",
              "number": "0106857286",
              "name": "OCAKES EMMANUEL OBOY",
              "alias": "Emmanuel Okeke",
              "currency": "NGN",
              "phone": null,
              "email": null,
              "is_beneficiary": true,
              "disabled_at": null,
              "is_trashed": false,
              "deleted_at": null,
              "created_at": "2021-03-18T16:58:16+01:00",
              "updated_at": "2021-03-18T16:58:16+01:00",
              "bank": {
                "data": {
                  "embeds": [
                    "country"
                  ],
                  "id": "bnk_1mHfTTp03uzgVyof2L28lC",
                  "code": "044",
                  "name": "Access Bank",
                  "is_visible": true,
                  "is_trashed": false,
                  "deleted_at": null,
                  "created_at": "2020-03-23T22:41:36+01:00",
                  "updated_at": "2020-03-23T22:41:36+01:00"
                }
              }
            }
          }
        }
      ]
    },
    "initiated_by": {
      "data": {
        "embeds": [
          "addresses",
          "customers",
          "role",
          "partner",
          "agent"
        ],
        "id": "usr_677kDUWkAdGJMrhppCDB8W",
        "firstname": "Octonaut",
        "lastname": "Pay",
        "phone": "+2348123320811",
        "password": null,
        "email": "[email protected]",
        "remember_token": null,
        "gender": null,
        "photo_url": null,
        "email_verified": false,
        "email_verified_at": null,
        "disabled_at": null,
        "is_trashed": false,
        "deleted_at": null,
        "created_at": "2020-09-02T10:04:10+01:00",
        "updated_at": "2021-05-18T17:00:44+01:00",
        "preferences": {
          "security": {
            "enabled_2fa": true,
            "otp_channel": "email"
          }
        }
      }
    },
    "source_account": {
      "data": {
        "embeds": [
          "bank",
          "bank_branch",
          "customer",
          "total_outgoing",
          "signatories"
        ],
        "id": "acc_7711L8SDEjw5dN4NqAZpCB",
        "number": "0000100024",
        "name": "Octonauts Ltd",
        "currency": "NGN",
        "ledger_balance": {
          "raw": "50166464495",
          "formatted": "501664644.95",
          "formatted_display": "₦501,664,644.95"
        },
        "available_balance": {
          "raw": "49999088051",
          "formatted": "499990880.51",
          "formatted_display": "₦499,990,880.51"
        },
        "is_default": true,
        "is_virtual": false,
        "is_partner_managed": false,
        "is_wallet": false,
        "wallet_type": null,
        "callback_time_minutes": 60,
        "locked_reason": null,
        "locked_at": null,
        "disable_reason": null,
        "disabled_at": null,
        "is_trashed": false,
        "deleted_at": null,
        "created_at": "2021-03-27T16:43:43+01:00",
        "updated_at": "2021-06-03T16:05:08+01:00",
        "masked_number": "00*****024",
        "preferences": {
          "monthly_budget": null
        },
        "bank": {
          "data": {
            "embeds": [
              "country"
            ],
            "id": "bnk_1Pl1vnSMWep0rd8FNXkLyK",
            "code": "100022",
            "name": "GoMoney",
            "is_visible": true,
            "is_trashed": false,
            "deleted_at": null,
            "created_at": "2021-01-04T09:05:07+01:00",
            "updated_at": "2021-01-04T09:05:07+01:00"
          }
        }
      }
    },
    "tags": {
      "data": [
        {
          "embeds": [
            "customer",
            "added_by_user"
          ],
          "id": "tag_1cISYnOd1sX2WPH7yqHNDa",
          "tag": "Accounting",
          "description": null,
          "is_trashed": false,
          "deleted_at": null,
          "created_at": "2020-08-23T11:55:07+01:00",
          "updated_at": "2020-08-23T11:55:07+01:00"
        }
      ]
    }
  }
}