If you are viewing this page, it means you are utilizing features in beta versions including our new webhook structure. These enhanced webhooks are designed to optimize communication between our API and your system. We value your collaboration during our BETA phase and welcome any feedback you may have. For inquiries or assistance, please don't hesitate to reach out to our support team at [email protected].
Enabling webhook
To enable webhooks, please access the Developer Tab from your dashboard and add your webhook URL. A webhook secret will be generated and displayed for security purposes; please ensure you store it securely.
PaymentWebhookData
FieldName | Type | Description | Required |
---|---|---|---|
eventType | Enum | Payment | Account | Plan | Yes |
paymentEntryType | Enum | RECEIVED_PAYMENT | CREATED_PAYMENT | Yes |
paymentReferenceId | String | This field is present when payment was executed successfully. In some cases where payment is failed upon submission, there is no paymentReferenceId assigned | No |
paymentType | Enum | LOCAL | INTERNATIONAL | No |
status | Enum | PENDING | SCHEDULED | UNCLAIMED | REQUESTED | PROCESSING | IN_TRANSIT | COMPLETE | CANCELED | DECLINED | FAILED | RETURNED | No |
payer | String | Payer handle (or email if handle doesn’t exist) | No |
description | String | Description of the payment | Yes |
amount | Number | If payment entry type is RECEIVED_PAYMENT the value of the field will be amount received in beneficiary bank currency before fee (if beneficiary pays the fee) If payment entry type is CREATED_PAYMENT, amount is the payment amount before fees (if payer pays the fee) | Yes |
totalAmount | Number | If payment entry type is RECEIVED_PAYMENT the value of the field will be totalAmount received after the fee (if beneficiary pays the fee) If payment entry type is CREATED_PAYMENT, the value of the field will be totalAmount paid after the fee (if payer pays the fee) | No |
fee | Number | If payment entry type is RECEIVED_PAYMENT the value of the field will be fee amount of beneficiary (if beneficiary pays the fee) If payment entry type is CREATED_PAYMENT, the value of the field will be fee amount of payer (if payer pays the fee) | No |
currency | Enum | 3-letter currency code If payment entry type is RECEIVED_PAYMENT currency field reflects beneficiary bank currency If payment entry type is CREATED_PAYMENT currency field reflects payer payment currency | No |
beneficiary | String | Beneficiary handle (if exists) or email | No |
beneficiaryAmount | Number | This field appears only when payment entry type is CREATED_PAYMENT. This field indicates beneficiary amount before fee (if beneficiary pays the fee) | No |
beneficiaryFee | Number | This field appears only when payment entry type is CREATED_PAYMENT. This field indicates beneficiary fee amount (if beneficiary pays the fee) | No |
beneficiaryTotalAmount | Number | This field appears only when payment entry type is CREATED_PAYMENT. This field indicates beneficiary total amount after fee (if beneficiary pays the fee) | No |
beneficiaryCurrency | Enum | This field appears only when payment entry type is CREATED_PAYMENT. This field indicates beneficiary 3 letter currency | No |
batchId | String | If payment was executed via mass payout, batchId of the payout will be assigned | No |
estimatedArrival | String | ISO Date string of estimated arrival | No |
paymentMethod | Enum | BANK_ACCOUNT | FUNDING_BALANCE | No |
clientPaymentRef | String | If payment was executed via api and unique identifier of clientPaymentRef was provided then it will reflect in this field | No |
createdAt | String | ISO Date string of when payment was created | No |
senderName | String | The name of who sent the funds (specific for incoming wire payments) | No |
Webhook Examples
Examples of webhook bodies shown below.
Successfully executed payment (CREATED_PAYMENT)
(this webhook will be sent to payer if payer have webhooks enabled)
{
"eventType": "Payment",
"paymentEntryType": "CREATED_PAYMENT",
"status": "COMPLETE",
"paymentReferenceId": "UATPYXYZ",
"amount": 7,
"fee": 0,
"totalAmount": 7,
"currency": "GBP",
"description": "test pay",
"beneficiary": "US-Buziness",
"beneficiaryAmount": 8.5,
"beneficiaryFee": 0.75,
"beneficiaryTotalAmount": 7.75,
"beneficiaryCurrency": "USD",
"clientPaymentRef": null,
"paymentMethod": "FUNDING_BALANCE",
"paymentType": "INTERNATIONAL",
"estimatedArrival": "2023-10-05T00:00:00.000Z",
"batchId": null,
"createdAt": "2023-10-05T15:09:33.187Z"
}
Received Payment webhook (RECEIVED_PAYMENT)
(this webhook will be sent to beneficiary if beneficiary have webhooks enabled)
{
"eventType": "Payment",
"paymentEntryType": "RECEIVED_PAYMENT",
"status": "PROCESSING",
"paymentReferenceId": "97230",
"payer": "US-Buziness",
"description": "test with attachment",
"amount": 5.76,
"fee": 0.51,
"totalAmount": 5.25,
"currency": "GBP",
"clientPaymentRef": null,
"paymentMethod": "BANK_ACCOUNT",
"paymentType": "INTERNATIONAL",
"estimatedArrival": "2023-10-06T00:00:00.000Z",
"batchId": null,
"createdAt": "2023-10-05T15:06:06.438Z"
}
Payment webhook of failed payment (Failed upon submission) will have very minimal
set of fields because there is no tracking for this payment created:
{
"eventType": "Payment",
"paymentEntryType": "CREATED_PAYMENT",
"beneficiary": "^b5dd1",
"amount": 100,
"reason": "Financial Institution Request Error",
"description": "demo pay to LT",
"status": "FAILED",
"batchId": "3b738307-7"
}
{
"batchId": "3b738307-7",
"successfulPayments": 0,
"failedPayments": 1,
"totalSubmittedPayments": 1,
"paymentsReport": [
{
"id": 1,
"handle": "^b5dd1",
"amount": 100,
"submissionStatus": "FAILED",
"cause": "Financial Institution Request Error"
}
]
}
Verify Webhooks
Webhooks have the following structure:
- Webhook body in json format
- Custom header x-borderless-webhook where we send hashed signature
- Custom header x-borderless-webhook-timestamp where we send timestamp
HOW TO VERIFY
To verify that a request is coming from an expected source (borderless) and that the request has not been tampered with in transit borderless uses Hash-based Message Authentication Code (HMAC). This method is a cryptographic authentication technique that uses a hash function and a shared secret key (webhook secret).
To verify that a webhook is coming from borderless, create HMAC signature using incoming request parameters and your webhooks secret key and cmapre created hash signature with the one received in the header. The verification process and steps can be found below. Please note that the step order DOES matter.
- Create HMAC from invoming request:
- Create signature (using hash 512 algorithm and using your webhookSecret);
- Create a message to be hashed from current timestamp (x-borderless-webhook-timestamp) + webhook body (as string) (First goes timestamp and then attach body to it to create one string);
- Note that the decoding algorithm (digest) is 'hex';
- Compare 2 signatures:
Compare x-borderless-webhook and the created one. If the signatures match then the webhook signature is VERIFIED and that the request came from borderless.