Webhooks
Learn how to implement webhooks.
Webhooks
Webhooks are an outbound API that Foundry delivers to customer applications when different events occur in Foundry. Webhooks are effective for notifying a client application when something important happens in Foundry, as opposed to the client application periodically polling Foundry for this same information. The webhook is a HTTP Post sent from Foundry to a payload URL you provide. The webhook contains information specific to the event that the customer application can use to perform various workflows.
Webhook Limitations
Webhooks are a complement to the Foundry API and not a substitute. While EVERFI strives to deliver webhooks reliably and nearly immediately, EVERFI cannot guarantee the deliverability of webhooks. Therefore, EVERFI recommends that if you wish to use webhooks for near-realtime workflows, you must also poll the Foundry API as a regular true-up to ensure all needed information from Foundry is accounted for.
Additionally:
- Webhooks may not happen in order.
- Webhooks that have not been delivered within an hour of happening will not be sent.
- Webhooks will be marked inactive if Foundry cannot verify the DNS record; Foundry verifies the DNS record on a regular schedule.
- Webhooks that are inactive may still deliver queued up requests for a period of time after the webhook changes from active to not active.
Receiving Webhooks
Once you add your webhook, verify your domain, and make your webhooks active, then Foundry will send webhooks to your payload URL when the event types occur.
As an integrator, your domain must have an application that is able to receive webhooks and interpret the data in the webhook and respond accordingly. Your webhook must handle the RESTful request described on this page and send back an appropriate status code. Your webhook must send back to Foundry an HTTP response code that indicates whether or not the event was successfully handled or not. If your webhook handled the event properly, it must send back an HTTP response status code of 2XX
, typically 200
. Foundry will interpret any other response, including 3XX
, that you did not receive the webhook. It is important that your webhook respond appropriately because in the future, Foundry webhooks may implement a retry feature for missed deliveries, and therefore Foundry must know that a delivery succeeded or failed.
Managing Webhooks in Foundry
Adding a Webhook
To add a webhook, login to Foundry as a user with administrative privileges and navigate to Settings → Webhooks.
Add a new Webhook Domain and select the Registered API this webhook will be associated with, and enter the domain of the URL to which Foundry should deliver webhooks. For example, if the complete payload URL of your application is at https://integrations.mysite.com/api/webhooks
then enter integrations.mysite.com
in the domain. Save the Webhook Domain.
After you save the Webhook Domain, you will be on the Webhook Domains page with your newly added Webhook Domain and two values: Verification Token and Secret Token. Copy each of these values and save them somewhere for later use. These values will be visible only for a few moments. If you need to regenerate either value, press the Regenerate button.
Verification Token – this token is used to verify your domain to Foundry.
Secret Token – Foundry uses this value to digitally sign the request. You can verify that a webhook came from EVERFI by signing the request you receive and comparing it to a signature that is provided in the header of the webhook request.
Adding Webhook Path and Events
After adding your domain, you must add a webhook to the domain to specify the path in your domain and which events you want to receive webhooks.
For example, if the complete payload URL of your application is at https://integrations.mysite.com/api/webhooks
then your domain would be integrations.mysite.com
and in the webhook path you will enter api/webhooks
without a leading forward slash character. You will be able to toggle the Active flag to Active to receive webhooks once the domain is verified.
Managing Webhooks
After you’ve added a domain and webhook, you can perform the following actions with the Domain or its Webhooks
Domain
- View verification status of the domain.
- Verify your domain after you perform the verification steps in your domain and want to make sure your domain is verified. Normally this takes less than a moment.
- Regenerate a new Verification Token or Secret Token for the domain.
- Delete the domain.
Webhooks
- Once your domain is verified, send a test webhook by clicking the icon. Foundry will then send a generic sample webhook to you URL.
- Add a new webhook to the domain.
- Delete an existing webhook.
- Edit an existing webhook to toggle it to active (once the domain is verified) or inactive, copy the Webhook ID, or select the events to trigger a delivery of this webhook.
If you want to change the domain, you will need to delete the domain and add a new one. If you want to change the webhook path, you will need to delete the webhook and add a new one with the desired path.
Verifying Your Domain
Foundry will deliver webhooks to your domain only after it has been verified. This is to ensure that Foundry delivers data about your learners only to a valid server under your control.
To verify your domain, in the DNS management tool for your domain, add a new DNS entry. The type should be TXT. The host is your own domain. The answer is _everfi_webhooks=secret-token
where secret-token
is the value provided to you after adding your domain. TTL can be the default.
Foundry will verify this DNS entry approximately 30 minutes after you add the domain. Foundry will re-verify this nightly to ensure the domain is still managed by you. If you need to verify right away or re-verify at any other time, press the Verify button to launch the verification process at once.
The domain must be secured with HTTPS.
Webhook Headers
A webhook contains the following key properties in the header. The receiver of the webhook is strongly advised to use these properties to verify the sender is EVERFI.
Foundry uses the api_auth library to digitally sign its webhooks. Refer to that website for how to generate a signature in the same way, and ensure the signature you generate matches the one in the webhook header. The secret is the secret_token
provided to you when you added the webhook domain in Foundry.
HTTP_AUTHORIZATION – contains a signature so you can verify the authenticity of the webhook. This property contains separate components in the following format.
APIAuth digest public_key:signature
For example:
"HTTP_AUTHORIZATION": "APIAuth-HMAC-SHA256 48841263-8g4q-4c54-8207-38c0ac9b7f0f:fsHRsQTFSlNW+lQY+BFeF7ne8yHzfL0JHqidgOgJEgo="
digest: the digest algorithm to generate the signature, for example HMAC-SHA256
. Always check this header property and do not assume it will always be the same and never change. Foundry may change the digest.
public_key: the Webhook ID of the webhook. You can determine the webhook ID by copying its value in Foundry, or by sending a GET request in the external API to admin/webhooks
and looking at the id
in the response. The integration should store the webhook ID along with the secret token that you get when you add the webhook.
signature: the Base64 encoded signature created using your integration’s private secret key along with the HTTP headers containing the content-type, content-MD5, request URI and the timestamp that is created as described in “How it works” at api_auth.
REQUEST_METHOD – value is always POST
. This is needed to create the signature.
REQUEST_URI – This is needed to create the signature.
CONTENT_TYPE – value will be application/json
. This is needed to create the signature.
HTTP_DATE – The integration should check this date to ensure it is within a reasonable time frame such as less than 15 minutes. This is needed to create the signature.
HTTP_CONTENT_MD5 – This is a base64 MD5 hash of the request body. This is needed to create the signature.
Webhook Data
Every webhook contains the following general properties in the request body.
Property | Datatype | Notes |
event_id | uuid | An id unique to the event; if a webhook is delivered more than once, it will have the same event_id . Since it is possible that Foundry delivers the same webhook more than once in exceptional circumstances, your application should ensure that it does not process a webhook with the same event_id more than once. |
event_type | string | The event type that triggered the webhook. Currently available: user_assignment.progress.completed and program_user.progress.completed |
event_time | timestamp | When the event actually occurred. Example: 2020-04-08T15:01:20.12200:00 |
data | array | An array containing additional information about the specific webhook. Each event_type returns different data relevant to that specific event as described in Event-specific Data below. |
Event-specific Data
user_assignment.progress.completed
A webhook for user_assignment.progress.completed
contains the following objects in the data
array that help you identify who completed the learning activity, and what the learning activity is. This contains the same keys and value in the progress array that the API delivers to progress/user_assignments
in the external API. Since this event fires for a single progress, this is just a single progress and not an array.
User
Property | Datatype | Notes |
id | uuid | The Foundry user’s id |
first_name | string | User’s first name |
last_name | string | User’s last name |
array | An array containing additional information in user and progress objects, each of which have a set of properties. | |
employee_id | string | User’s employee id, if any |
sso_id | string | User’s sso id for single sign-on, if any |
active | boolean | true if active, false if inactive |
location | object | Contains the name of the user’s location |
groupings | array | Array of user’s categories and labels |
Progress
Property | Datatype | Notes |
id | uuid | The unique id of the progress record |
content_id | uuid | The id of the learning activity |
due_on | date | The due date in YYY-MM-DD format |
last_progress_at | timestamp | Timestamp of the last time the learner accessed the content |
name | string | The name of the learning activity |
percent_completed | integer | The approximate percentage the learner has completed |
content_status | string | The status of the progress. One of: not_started, in_progress, completed, skipped |
started_at | timestamp | When started |
completed_at | timestamp | When completed |