Webhooks
Webhooks are used to notify your platform about events on finmid side. finmid sends these notifications to an endpoint hosted in your environment configured to receive and process them.
What is a webhook?
A webhook is an asynchronous notification in the shape of an HTTP request. Webhooks are a well known practice used by many services. We use webhooks to notify your platform asynchronously about events on finmid side (e.g. a Business has agreed to share Personally Identifiable Information). This allows you to react to certain events and avoids the need for polling.
How to start receiving webhooks?
To start receiving webhooks, an endpoint has to be configured on both your and finmid ends. You need to provide a URL to which webhooks will be sent. This must be an HTTPS URL that is under your control or trusted by you. Additionally, we need certain security parameters from you to protect your endpoint. There are two ways to configure a webhook endpoint on finmid's end.
Setting up an endpoint via customer support
Please contact [email protected] and provide the following data points:
url
โ URL of your webhook endpoint (only HTTPS URLs)basic_auth_username
โ HTTP basic authentication username, for webhook authenticationbasic_auth_password
โ HTTP basic authentication password, for webhook authenticationsignature_secret
โ HMAC signature secret, for verifying the webhook payload
You can configure multiple webhook endpoints: each of them will be receiving webhook notifications.
Protecting you webhook endpoint
Webhooks will be sent to your endpoint over the public internet. Therefore we only support HTTPS endpoint URLs. Custom self-signed certificates are not supported. We provide two important security features which will help you to protect your endpoint:
- Webhooks are using HTTP basic authentication
- The webhook payload is digitally signed using HMAC-SHA-256 algorithm
It is strongly recommended to utilize the above security features to protect your endpoint.
Authentication
Webhooks utilize the HTTP basic authentication method. This method has very good support and is easy to implement while providing a sufficient level of protection.
This is just one example how easy the implementation is for an Express.js based app:
const app = require("express")();
const basicAuth = require("express-basic-auth");
app.use(
basicAuth({
users: { admin: "supersecret" },
})
);
Payload verification
All webhooks provide a X-Payload-Signature
header. It contains a HMAC-SHA-256
signature of the payload which was generated using the signature secret of the webhook endpoint. Please note that the header value is encoded as Base64.
You can check the signature like so:
- Read the signature from HTTP header
X-Payload-Signature
- Base64-decode the signature value (if necessary)
- Generate your signature from the webhook payload using
signature_secret
- Compare signature from webhook header with your generated signature. The webhook is verified if signatures match.
Pseudo code example of the above steps:
var signature = request.header("X-Payload-Signature");
var payload = request.body();
// Assume generatedSignature is a Base64-encoded signature value already
var generatedSignature = HMAC.createSha256(payload, env.SIGNATURE_SECRET);
if (signature === generatedSignature) {
// Webhook verified
}
Additional security tips
Your webhook endpoint already has quite good protection if you have implemented the above security features. However, you might consider the following additional tips:
- Choose a random, hard to guess webhook endpoint URL. This will make it hard for attackers to identify your webhook endpoint.
- Don't expose sensitive error information with your webhook endpoint. Make sure to log errors internally and only return
HTTP 404 Not Found
in case of an error. Even if an attacker identifies your webhook endpoint, they might get distracted by the not found error and stop their efforts.
Webhook delivery guarantees
In the event of an error when posting webhooks to your endpoint, finmid will attempt to deliver your webhooks for up to one day, with exponential backoff.
Payload structure
This is a breakdown as to how finmidโs webhooks are structured, at a global level, and event-specific level.
General payload
The webhook payload might contain multiple events. This allows us to reduce HTTP traffic.
Our webhooks all follow the same general payload structure, which can be found below.
Fields labelled as event specific are detailed in the next section.
{
"webhook_id": "e8cce989-0c48-4036-9bf2-1f0206398743",
"timestamp": "2022-02-10T13:48:48.892708722Z",
"events": [
{
"event_id": "ebda8288-8889-45e8-b672-0741e3553754",
"timestamp": "2022-02-10T13:42:35.282908722Z",
"type": // Event Specific,
"data": {
// Event Specific
}
},
{
"event_id": "4907a0f7-b53f-4fe7-90bd-bded64a55707",
// ...
}
]
}
Generic Fields
Field | Type | Description |
---|---|---|
webhook_id | string | |
timestamp | string | Corresponds to when the webhook was created. |
events | list of event objects |
Event Object Fields
Field | Type | Description |
---|---|---|
event_id | string | |
timestamp | string | Corresponds to when the event occured, and should be used as the source of truth to reconstruct event timelines. |
type | string | Type of the event |
data | object | Event-related data |
Types of Events & Payloads
This is a list of all the types of events we currently send. Do be aware that new events may be added.
Events are distinguished by the โtypeโ field in the payload, and additional data is provided in the โdataโ field.
Webhooks can be tested via the post Simulate Offer acceptance API.
capital_offer.created
capital_offer.created
This webhook is published when a financing Offer has been created by finmid and is available to share with a Business. Platforms can request Offer status for a relevant Business after this webhook is published.
{
"event_id": "ebda8288-8889-45e8-b672-0741e3553754",
"timestamp": "2022-02-10T13:42:35.282908722Z",
"type": "capital_offer.created",
"data": {
"business_id": "business-id",
"max_amount": 123.45,
"currency": "EUR"
}
}
Data Fields:
Field | Type | Format | Description |
---|---|---|---|
business_id | string | ^[a-zA-Z0-9_.\-]{1,100}$ | ID of the Business for which the Offer has been created |
max_amount | number | decimal | The maximum Funding amount available in the current Offer |
currency | string | EUR , DKK , SEK , PLN | ISO 4217 currency code in which Business operates, e.g. does sales. Currency will be associated with Sales statements and performance data |
capital_funding.created
capital_funding.created
This webhook is published when a new financing Offer has been accepted by a Business and a relevant Funding has been created.
{
"event_id": "ebda8288-8889-45e8-b672-0741e3553754",
"timestamp": "2022-02-10T13:42:35.282908722Z",
"type": "capital_funding.created",
"data": {
"business_id": "business-id",
"funding_id": "funding-id"
}
}
Data Fields:
Field | Type | Format | Description |
---|---|---|---|
business_id | string | ^[a-zA-Z0-9_.\-]{1,100}$ | ID of the Business for which the Offer has been created |
funding_id | string | UUID | ID of the Funding that has been created after the Offer has been accepted by the Business |
kyb_data_consent.granted
kyb_data_consent.granted
This webhook is triggered when Business grants finmid consent to collect its Personally Identifiable Information (PII).
After the webhook is published, finmid expects to receive the Business's PI data for further processing.
{
"event_id": "ebda8288-8889-45e8-b672-0741e3553754",
"timestamp": "2022-02-10T13:42:35.282908722Z",
"type": "kyb_data_consent.granted",
"data": {
"business_id": "business-id"
}
}
Data Fields:
Field | Type | Format | Description |
---|---|---|---|
business_id | string | ^[a-zA-Z0-9_.\-]{1,100}$ | ID of the Business that has granted data sharing consent |
Updated 28 days ago