Webhooks are used to immediately notify your server of events that take place in the Lean ecosystem. These are especially useful for events that take place on your front end through the Lean SDK or events that take place asynchronously. Once you receive an event on your server, you can process and act on it as you need.
We consider a webhook as having been successfully delivered when we receive a success status code (200) from the webhook URL you specified in your application dashboard.
If we receive any other status code or do not receive a response within 10 seconds, we will start retrying. We take an exponential back off approach to resending webhooks until we receive a successful response sending retries 1, 2, 5, 10, 60, and 180 minutes after the initial webhook was sent.
It is important to ensure that webhooks sent to your Webhook URL truly came from Lean. Without such verification a bad actor can send a fake request to your Webhook URL and potentially cause your system to react as if the request came from Lean.
Subsequently Lean provides two methods for you to secure your webhooks and ensure they're coming directly from us.
If you inspect the headers sent with our webhooks, you’ll see a lean-signature
with a value that begins with “sha512=“.
This is the signature — a hash-based message authentication code (HMAC) which was constructed by using SHA-512 as the message digest algorithm and your “webhook secret” as the shared secret key to hash the webhook body. Your “webhook secret” can be found in the Integration section of the developer portal.
Upon receiving the webhook you can compute the signature by computing the HMAC yourself using the webhook body and your webhook secret and then comparing it with the value of the lean-signature
header. When you perform your hash calculations, ensure that you use the raw payload of the webhook body to avoid altering the values within the payload prior to calculating the hash. With this you can ensure that the webhook you received came from Lean and nobody else.
You can also configure your server or endpoint to exclusively accept POST requests from the IP Addresses we use to send webhooks. For production applications we send all webhooks from 193.123.71.28 and for sandbox applications we send webhooks from either 15.184.15.24, 15.184.92.63, or 15.184.77.41 and so you will need to whitelist all of these.
All webhooks sent through Lean will follow a standard structure as laid out below.
type string
The event that has taken place. This is composed of the object type followed by the event in the format [object_type].[event]
.
payload object
The object associated with the event that triggered the webhook.
message string
A description of the event.
timestamp string
The time at which the event took place in the format: yyyy-MM-dd*HH:mm:ss.SSSSSSZ
event_id string
A UUID uniquely identifying the event
// This snippet is only use to show the general structure of webhooks sent by Lean, the text in place of values are descriptive and not representative of the objects or values they describe.{"type": "[object].[action]","payload": {[Object]},"message": "[Descriptive message explaining the event]]","timestamp": "[Timestamp in format yyyy-MM-dd*HH:mm:ss.SSSSSSZ]","event_id": "[Unique UUID identifier for the webhook notification]"}
"type": "payment_source.created"
Payload object type: Payment Source
This webhook is triggered when your customer successfully creates a payment source using the Link SDKs Connect() or CreatePaymentSource() functions.
{"payload": {"id": "ab172710-740c-452b-a78f-8a36a9cf48ef","customer_id": "0fd6d135-a4be-40ac-9630-1738ced7da69","status": "AWAITING_BENEFICIARY_COOL_OFF","bank_identifier": "EIB_UAE","bank_name": "Emirates Islamic Bank"},"type": "payment_source.created","message": "A payment source was pre-authorized by your customer.","timestamp": "2021-06-23T14:17:34.342847Z","event_id": "00405221-21fc-4aa2-a237-3edfe4c38411"}}
"type": "payment_source.updated"
Payload object type: Payment Source
This webhook is triggered after a payment source's status is updated from AWAITING_BENEFICIARY_COOL_OFF
to ACTIVE
.
This change in status means that your customer can now initiate payments using this payment source.
Note that some payment sources are active upon creation and this webhook will only be triggered for payment sources with an AWAITING_BENEFICIARY_COOL_OFF
status upon creation. Whether a payment source is ACTIVE
or AWAITING_BENEFICIARY_COOL_OFF
upon creation is dependent on the financial instituition of the payment source.
Deprecation warning: This webhook will soon be deprecated. Since the main use case for this webhook is to let you know that payments can be initiated from a payment source it is important to know which destination the payment can be made to. Therefore it is more useful to trigger an action based on the
payment_source.beneficiary.updated
webhook.
{"payload": {"id": "ab172710-740c-452b-a78f-8a36a9cf48ef","customer_id": "0fd6d135-a4be-40ac-9630-1738ced7da69","status": "ACTIVE","bank_identifier": "EIB_UAE","bank_name": "Emirates Islamic Bank"},"type": "payment_source.updated","message": "A payment source has been updated.","timestamp": "2021-06-24T14:21:04.169186Z","event_id": "5f8f7875-31d9-43ed-9b2a-0bafa9154311"}
"type": "payment_source.beneficiary.created"
Payload object type: Payment Source Beneficiary
This webhook is triggered when your customer successfully creates a payment source using the Link SDKs Connect() or CreatePaymentSource() functions.
This webhook is also triggered when a destination is added to a payment source using the Link SDK UpdatePaymentSource() function which creates a new beneficiary
object within the payment source.
Unlike the payment_source.created
webhook, the focal object for this webhook is the beneficiary
, which represents the pathway between a payment_source
and payment_destination
. Many beneficiaries can be created for the same payment source which in the real world allows the payment source to make payments to many destinations.
{"payload": {"id": "2cd827ab-d0c4-462f-b2a2-12e3ef1b7d8e","customer_id": "0fd6d135-a4be-40ac-9630-1738ced7da69","payment_source_id": "ab172710-740c-452b-a78f-8a36a9cf48ef","payment_destination_id": "99da636d-d022-4e0a-a450-a293ecdcb125","status": "ACTIVE"},"type": "payment_source.beneficiary.created","message": "A beneficiary was added for a payment source.","timestamp": "2021-06-23T15:59:11.02946Z","event_id": "5cf79ddb-ac0e-43fb-894d-5a54eb6c4856"}
"type": "payment_source.beneficiary.updated"
Payload object type: Payment Source Beneficiary
This webhook is triggered when a beneficiary
object changes status from AWAITING_BENEFICIARY_COOL_OFF
to ACTIVE
.
When this webhook is received, the payment source which the beneficiary belongs to can start to make payments to the payment destination that the beneficiary in question refers to.
When received, we suggest notifying the customer who this payment_source belongs to that payments can now be made through this payment source through a push notification.
{"payload": {"id": "2cd827ab-d0c4-462f-b2a2-12e3ef1b7d8e","customer_id": "0fd6d135-a4be-40ac-9630-1738ced7da69","payment_source_id": "ab172710-740c-452b-a78f-8a36a9cf48ef","payment_destination_id": "99da636d-d022-4e0a-a450-a293ecdcb125","status": "ACTIVE"},"type": "payment_source.beneficiary.updated","message": "A beneficiary was updated for a payment source.","timestamp": "2021-06-24T12:27:28.663129Z","event_id": "9a826354-d2ea-499e-9f05-a5ad316ef3f1"}
"type": "payment.created"
Payload object type: Payment
This webhook is triggered when your customer has successfully initiated a payment or when the payment was unsuccessful while going through the Pay() flow within the Link SDK.
The status of the payment is reflected in the status
field within the payload.
{"payload": {"id": "66214bdb-5f1a-4127-9ddc-cc44c0446c82","customer_id": "0fd6d135-a4be-40ac-9630-1738ced7da69","intent_id": "b896af3a-1781-4a48-b173-ce4b2ca6a522","status": "ACCEPTED_BY_BANK","amount": 10.17,"currency": "AED","bank_transaction_reference": "0H129D0RT04YY"},"type": "payment.created","message": "A payment object has been created.","timestamp": "2020-06-22T13:15:28.565512Z","event_id": "f4096636-85f3-42f1-8148-3cf9b5377db2"}
"type": "entity.created"
Payload object type: Entity
This webhook is triggered when your customer succesfullys connects their account through the Link SDK's Link() or Connect().
The entity
object is used by you to retrieve data from your customer's bank account. Where the entity_id
serves as a token representing the holding bank account.
{"payload": {"id": "09934cdd-882c-4638-aa2f-bad17bf1a107","customer_id": "0fd6d135-a4be-40ac-9630-1738ced7da69","app_user_id": "20210908115512","permissions": ["transactions", "balance", "identity", "accounts"],"bank_details": {"name": "Citi Bank","identifier": "CITI_UAE","logo": "https://cdn.leantech.me/img/bank-assets/uae/glyphs/citi/g-white-citi_uae.png","main_color": "#ffffff","background_color": "#003B70"}},"type": "entity.created","message": "An entity object has been created.","timestamp": "2021-09-08T10:57:21.613015Z","event_id": "6573f646-a793-4e5e-897d-61b80e0e835c"}
"type": "results.ready"
Payload object type: Results
The results ready webhook is triggered after Lean's system has retrieved data requested to be delivered asynchronously.
{"payload": {"id": "dbd310a2-ebd9-4a0f-ae10-0f82f25f1bff"},"type": "results.ready","message": "Your results are ready.","timestamp": "2021-09-02T15:38:54.573741Z","event_id": "f8752072-cef2-4056-9ff0-d5d2aa1e4558","results_id": "4e326535-9af6-4f77-a24a-e785f88352e1", // deprecated"status": "ping_results_ready" // deprecated}
"type": "bank.availability.updated"
Payload object type: Bank
The Bank Availability webhook is triggered when a bank is taken offline by either Lean or by you in the Application Dashboard. When a bank is unavailable usage of the LinkSDK is restricted for end-users.
{"payload": {"identifier": "ENBD_UAE","availability": {"active": { "payments": true, "data": true },"enabled": { "payments": true, "data": true }}},"type": "bank.availability.updated","message": "The bank status has been updated.","timestamp": "2021-12-14T15:06:46.083515Z","event_id": "103586d6-e88c-40ba-aa0e-c6ee255aaf2e"}