Thinkific uses webhooks to provide near-realtime information about events as they happen in a user's Thinkific account. Webhooks are a useful tool for apps that want to execute code after a specific event happens on a site—for example, after a customer purchase a course, or a student completes a course.
All of the currently available Thinkific webhook events are documented here.
Note: Apps that use polling when an available webhook exists will not be approved for use in the Thinkific App Store.
Creating and modifying Webhooks
You can create and modify your webhooks in one of two ways:
- Automatically using the Webhooks API (Recommended)
- Manually using the Thinkific Admin UI.
Webhooks API
Using the Webhooks API is the recommended approach for developers creating Public Apps because it can be done automatically when the app is installed on a new Thinkific Site.
Thinkific Admin UI
When creating or editing a Webhook manually on your Thinkific Site, follow this guide:
Creating a new Webhook (from Thinkific Admin)
-
In your Thinkific Site, go to Settings and select the Code & Analytics tab.
-
Using the menus or scrolling to the bottom of the page, navigate to the Webhooks block and select the Webhooks button
-
Click the New Webhook on the top right.
-
Input the Target URL, Model, and Topic and save *Target URL is the URL you want the webhook to send the event to.
Note: The trouble with testing your webhooks through the API is that you need a publicly visible URL to handle them. Unlike client-side redirects, webhooks originate directly from the server. This means that you cannot use the following as an endpoint in your testing environment:
- Localhost
- "Fake" domains like www.example.com
- Thinkific domains (i.e. thinkific.com)
There are a couple of tools that make working with webhooks during development much easier such as RequestBin, Pagekite and ngrok.
Note: A Webhook's target URL must use SSL encryption (aka use https).
Modifying a Webhook (from Thinkific Admin)
Once your webhook is created, you will see it in your webhooks list. From this page, you can click the Edit button on the right to make any changes. You can also click the ellipsis (3 dot icon) to send a test event, or delete the webhook.
Viewing Webhook Logs
If you need to see the events that have been sent, you can click on the webhook topic itself to get payload information and to check for success messages.
Note: Webhook event record history is stored in Thinkific for 30 days before being removed.
Receiving Webhooks
Once you register a webhook URL with Thinkific, we will issue a HTTP POST request to the URL specified every time that event occurs. The request's POST parameters will contain JSON data relevant to the event that triggered the request.
Anatomy of a Webhook
When an event occurs in a Thinkific site that corresponds to a registered webhook topic, Thinkific sends a webhook notification to the specified URL. The webhook contains a payload formatted as JSON, as well applicable HTTP headers. For example, the following headers are sent as part of the order.created
event.
- X-Thinkific-Topic: orders.created
- X-Thinkific-Hmac-Sha256: some-hex-encoded-weird-token
- X-Thinkific-Subdomain: passion-to-profit
Some of the returned HTTP headers can be useful for your app. For example, X-Thinkific-Hmac-Sha256 is used to authenticate webhooks, and X-Thinkific-Subdomain is useful for determining the site context.
Responding to Webhooks
Upon receiving a webhook, your application must acknowledge that it has received the data by sending a 200 OK response. If Thinkific does not receive a response (or receives a response that is anything outside of the 200 range), we will assume that you did not successfully receive your webhook and will trigger a retry.
Webhooks that consistently fail to receive a successful response may be deactivated and removed in the future.
Note: Thinkific has a 5-second timeout period where we will wait for a response so your application should make an effort to respond within this time frame. We strongly recommend that your application responds to the webhook as soon as your app has successfully captured the data and prior to executing any kind of lengthy processing in your system in order to avoid the timeout.
Webhooks Retries
A Webhook retry is designed to automatically resend a webhook if the target URL does not return a 200 success response for whatever reason. This is useful in the event of a Network timeout, or unforseen error that cause the event to fail to reach your application. This means that there will be multiple attempts to deliver the same webhook data over a span of time.
Note: Failed events are tracked in Thinkific and displayed in the Thinkific Webhook UI Logs)
How often will a webhook retry?
Single webhooks are scheduled to retry a maximum of 14 times over a span of 16 hours before it is terminated. Each retry will be scheduled with an increased delay each time it needs to be retried.
Exponential Delay Example
Retry Attempt | Delay until webhook is fired (in seconds) |
First try | 0 seconds |
2nd try | 10 seconds |
3rd try | 30 seconds |
4th try | 1 minute |
5th try | 2 minutes |
... | |
11th try | 1 hour |
... | |
14th try | 8 hours |
Verifying webhooks created through the API
Webhooks created through Thinkific's API can be verified by calculating a digital signature.
Each webhook request includes a hexadecimal-encoded X-Thinkific-Hmac-Sha256 header generated using one of the following:
-
Site's API Key
-
App Client Secret
To verify that the request came from Thinkific, compute the HMAC digest and compare it to the value in the X-Thinkific-Hmac-Sha256 header. If they match, the Webhook was sent from Thinkific and the data has not been compromised.
Examples
In this section you will find some code samples to validate the webhook payload.
Ruby
If you are using a Rack based framework such as Ruby on Rails or Sinatra the header you are looking for is HTTP_X_THINKIFIC_HMAC_SHA256
Below is a simple example in Ruby using the Sinatra web framework of how one might verify a webhook request.
require 'rubygems'
require 'openssl'
require 'sinatra'
# The Thinkific's api key, viewable from the Tenant's advanced settings
# If the webhooks was created by your app, you can find the App Secret at
# Partners Portal, at your app's details page
API_KEY_OR_APP_SECRET = 'my_api_key_or_my_app_secret'
helpers do
# Compare the computed HMAC digest based on the api key and the request contents
# to the reported HMAC in the headers
def verify_webhook(data, hmac_header)
calculated_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), API_KEY_OR_APP_SECRET, data)
ActiveSupport::SecurityUtils.secure_compare(calculated_hmac, hmac_header)
end
end
# Respond to HTTP POST requests sent to this web service
post '/' do
request.body.rewind
data = request.body.read
verified = verify_webhook(data, env["HTTP_X_THINKIFIC_HMAC_SHA256"])
# Output 'true' or 'false'
puts "Webhook verified: #{verified}"
end
Javascript
An example using Node.JS Crypto library
import crypto from 'crypto';
const SECRET = 'secret' // site's api key or app client secret
const validateHmac = (payload, hash) => {
const hmac = crypto.createHmac('sha256', SECRET).update(payload).digest('hex');
return hmac === hash;
}