Any events that occur within the lifecycle of a borrower on Canopy will send webhook notifications.


Webhooks and Canopy

Activity that occurs in Canopy drives many downstream dependent actions. For example, sending email or text notifications to borrowers, executing logic in response to missed borrower payments, and more. All events that occur within the lifecycle of any borrowers on Canopy send webhook notifications for your dependent systems.

Subscribing & Modifying Webhooks

There are two ways to subscribe to webhook notices from within Canopy.

Canopy API

Subscribe to receive webhook events through the Canopy API with the /organization/subscribe endpoint.

This endpoint can be called multiple times to have webhooks sent to more than one URL.

This endpoint will also allow you to specify which event types you would like to receive webhook notices for by specifying in the filter_events property. This property take an array of event type names. If not provided, all webhook types will be sent by default.

Refer to the API section of the docs for more details on the specific fields.


To assign your webhook URL to your Canopy organization, navigate to the “App Keys” page from the top right account dropdown. Under the Webhook URL section, paste your webhook URL into that input and hit the save button. Once configured in the Canopy UI, this URL will receive all webhook events.

Note: CanopyOS currently only allows for modifying one URL record. The ability to subscribe to multiple URLs as well as configuring them through CanopyOS is coming soon.

Listing Webhook URLs

You can get a full list of all URLs you have subscribed to by calling the /organization/subscriptions endpoint.

Unsubscribe and Resubscribe

You can pause and unpause receiving webhook notifications to a given URL by referencing the ID value returned from the list above when calling the /organization/subscriptions/{{webhook_uuid}}/resubscribe and /organization/subscriptions/{{webhook_uuid}}/unsubscribe endpoints.

Delivery Guarantees

Webhook messages have an ‘at least once’ guarantee. In order to facilitate this, a message may be delivered more than once. It is up to the receiver to detect duplicate messages. This can currently be done with the hmac_signature.


There is no guarantee on delivery order of webhooks. If there is an error in receiving the webhook there will be a retry which might change the ordering of webhooks. Additionally, webhooks are batched together and sent every minute, meaning any webhook generated within a one minute time frame of another is not guaranteed to always be delivered in the same order they were created.

Response Pattern

Events will hit your webhook URL in the following pattern:

  "event": String, // The name of the event type
  "data": Object, // The webhook payload
  "hmac_signature": String // The signature of the field "data"

Your endpoint must respond with a 200 or 202

Other response codes and Retry

  • Events associated with error codes 429 and 5XX are retried before sent to dead letter queue (DLQ).
  • Events associated with error codes 1XX, 3XX, and 4XX (excluding 429) aren't retried before sent to DLQ.
  • Canopy will retry a single webhook event with exponential backoff, with the first retry 1 minute after the first failure, and will stop with the last retry approximately 24 hours after the first failure.
  • The endpoint will pause if several error codes are received consecutively or if one 401 code is received.
  • Events stored in the dead letter queue (DLQ) are kept for 5 days, and you have the option to resend all DLQ events back to your webhook endpoint. A single put on the Canopy API route /organization/subscribe/replay_failed_events will replay all failed events to your webhook endpoint again.

Verifying HMAC signatures

  • You can verify the key on any HMAC library with encryption SHA256 and on Base64. This algorithm needs to be applied on the payload data field, and needs to be equal to the hmac_signature field.
  • You can retrieve your HMAC secret key via a GET call to Canopy:
  • To manually verify, you can do so within an online SHA256 generation tool such as the one found here.


const CryptoJS = require("crypto-js");

const data = {...};

const HMACData = JSON.stringify(data);

secret_key = '***'***';
const generatedHMAC = CryptoJS.HmacSHA256(HMACData, secret_key);
const generatedHMACBase64 = CryptoJS.enc.Base64.stringify(generatedHMAC);


Testing Webhooks

If you are testing using controlled processing for webhooks, you will need to include an additional query parameter in you request to admin/roll/account called roll_webhooks set to true. This will send every webhook up to the effective_at of the roll time request.

Configurable Webhooks

Configurable Webhooks are not enabled by default. You need to explicitly subscribe to them on behalf of each account, with a request to: PUT /accounts/{{account_id}}/notification_config

When subscribing, the body of the request must provide the event type being subscribed to as well as the time offset or periodic interval that the webhook should be scheduled that. Each [configurable-webhooks](Configurable Webhooks) describes what configuration type it supports. Additionally, an optional time parameter can be provided to have the webhook be scheduled at a specific time of the day, rather than based on when the event scheduling it occurs.

The following is an example of subscribing to a notification at 5PM, 1 day before the payment due date for the account:

    "notification_type": "payment_due_date", // the event type
    "time_offset": "-1 days", // time offset from the notification event
    "time": "17:00:00" // at which time the webhook will be triggered in product timezone

What’s Next