FAQ

Content Encoding

We enforce gzip content compression on the data being received by the endpoints. When "content-encoding" header is set to "gzip", the content body data will be compressed into a stream using gzip format and set to the request body. Therefore upon receiving the request on our endpoints, we must decompress the stream from the request body. Below is an example of how we are decompressing on our own endpoints.

string encodingType = Request.Headers["content-encoding"];
 
Stream decompressionStream = new GZipStream(Request.Body, CompressionMode.Decompress);
 
// Copy decompress stream into a new stream
MemoryStream outputStream = new MemoryStream();
decompressionStream.CopyTo(outputStream);
 
// Write stream to byte array
byte[] decompressedData = outputStream.ToArray();
 
// Decode byte array to string
string decompressedBody = Encoding.UTF8.GetString(decompressedData);
 
// Close the streams to do final buffer flushing
decompressionStream.Close();
outputStream.Close();

Heartbeat

Once started, webhooks will send out a heartbeat event every 5 minutes. This serves to inform clients that the webhook is operational and to verify the status of the receiving endpoint, ensuring there are no network or system issues.

The heartbeat event will look like the below

{
  "subscriptionId": "2fc686a1-123b-400f-86d6-356fcd39372d",
  "sessionId": "079d1e3a-ab87-4f87-8e22-4f4d15d68806",
  "attemptNumber": 1,
  "records": []
 }

Retry Policies

When a webhook delivery fails, the system will automatically retry depending on the type of error returned by your endpoint.

Retriable Errors

The following HTTP response codes trigger automatic retries. These are all temporary or infrastructure-level failures where the issue is likely to resolve on its own:

HTTP StatusNameWhy It's Retriable
408Request TimeoutYour endpoint didn't respond in time — could be a momentary slowdown.
500Internal Server ErrorA generic server-side failure that may clear after a brief recovery.
502Bad GatewayAn intermediary (load balancer, proxy) couldn't reach your server — often transient.
503Service UnavailableYour server is temporarily overloaded or undergoing maintenance.
504Gateway TimeoutAn intermediary timed out waiting for your server — similar to 408 but at the network layer.

How Retries Work

Retries use a linear backoff strategy — the wait time between attempts increases by 30 seconds each time:

AttemptWait Time
1st retry30 seconds
2nd retry60 seconds
3rd retry90 seconds
4th retry120 seconds
...+30s each

The total number of retry attempts depends on your webhook tier:

TierMax RetriesApproximate Total Retry Window
Starter130 seconds
Small10~27 minutes
Medium20~1.75 hours
Large50~10.6 hours

If all retries are exhausted, the webhook moves to a Failed state.

Non-Retriable Errors

For responses like 400 Bad Request, the webhook will fail immediately without retrying. These errors typically indicate a configuration or implementation problem on the receiving endpoint that won't resolve on its own.

What to do: Fix the issue on your endpoint and then manually restart the webhook from the UI.

Tips

  • If you're seeing frequent retries, check your endpoint's availability, response times, and authentication configuration.
  • Upgrading your tier increases both the retry count and overall recovery window.

Record Batching

Events are grouped into batches before being delivered to your endpoint. A single batch can contain different events from the same category (e.g., TrainingAssigned and TrainingCompleted in one delivery).

Batch Size Limits

The maximum number of records per batch depends on your webhook tier:

TierMax Records Per Batch
Starter10
Small100
Medium500
Large1,000

When Batches Are Dispatched

A batch is dispatched to your endpoint when either of the following occurs — whichever comes first:

  • The batch is full — once the maximum record count for your tier is reached, the batch is sent immediately.
  • No more events are available — if the batch is only partially filled and there are no additional events to collect, it is dispatched rather than waiting indefinitely.

Under light load, you'll typically receive smaller batches delivered quickly. Under sustained high load, batches will consistently fill to the tier maximum and dispatch continuously.

What This Means in Practice

  • Batch sizes will vary — don't expect every delivery to contain exactly the maximum number of records.
  • There is no fixed "wait X seconds then send" timer. The system optimizes for both low latency and efficient delivery.
  • If you need to handle high-throughput scenarios with fewer, larger deliveries, consider upgrading your tier.

Tiers and Performance

The following limits and performance targets apply per webhook tier:

TierStarterSmallMediumLarge
Retry1102050
Max Unique Webhooks102050100
Max Lag30 minutes10 minutes1 minuteNo lag (depends on callback endpoint only)

Max Lag Requirements

The Max Lag figures above are targets, not guarantees under every condition. They hold only when the following requirements are met:

  • Throughput must be sustained, not bursty. Max Lag is based on a steady, sustained flow of events. A sudden spike — such as one million records within a single minute — exceeds the sustained-throughput assumption and will introduce additional lag.
  • Your endpoint must be performant. Your endpoint needs to acknowledge and receive messages in a timely manner. We strongly recommend that any downstream processing be handled asynchronously. Acknowledge our message first, then process it — do not perform several seconds of downstream work before acknowledging, as holding the acknowledgment back directly increases lag.
  • Your webhook should use the System Default for Max records in payload. Each webhook has a Max records in payload setting in the UI. Leaving it on System Default provides the best performance for meeting the Max Lag targets. Choosing a fixed Tier Setting instead can cause frequent automatic webhook stops during spikes — see Webhook has been stopped for details.
Max Records in Payload Setting

Initial Webhook Start

Once the webhook feature is enabled on a client portal, event generation begins and events are stored based on the retention period. When a webhook is started, all events stored will be delivered from the beginning of the collection. This means upon initial start of a webhook, there may be a backlog of events to be delivered, resulting in increased load and latency. This should subside as long as the events are delivered successfully to the client endpoint.

Training Event Timing

Training webhook events (such as TrainingAssigned) fire when an enrollment becomes actionable, not necessarily at the moment of initial assignment. The time between assignment and event delivery depends on the assignment source and any workflow gates configured for the learning object.

Expected delivery timing by scenario

ScenarioExpected LatencyDescription
Direct assignment< 10 secondsStandard assignment with no gates
Approval-gated LOHours to daysEvent fires after manager or workflow approval is granted. Delay reflects human action time.
Priced LO (purchase flow)Seconds to minutesEvent fires after the learner completes the purchase/checkout process
External content providerVariableFor aggregated content (e.g., third-party providers), event timing depends on when the upstream provider confirms enrollment
Bulk importMinutesAssignments processed via bulk import queue behind additional processing layers

Implications for the lag field

The lag field in the webhook payload reflects the time between when the event was generated internally and when it was delivered to your endpoint. For approval-gated or purchase-flow content, the event is not generated until the gate clears — so lag will not include approval wait time. However, if you are comparing the webhook delivery timestamp to the original assignment timestamp in a report, the difference will include the full workflow wait time.

Registration numbers

Learning objects that support multiple registrations (e.g., recurring training) will produce separate events for each registration. When comparing assignment and completion timestamps across registrations, ensure you are matching events to the correct trainingRegistrationNumber to avoid apparent timing discrepancies.

Alerts Types

Alerts are a webhook event category that allows end users to set up webhooks in order to better alert and monitor their webhooks.

Types of Alerts

Webhook failure has occurred

When the webhook moves into a failed state, a Failed alert event will be sent. Generally this will occur due to issues with the client's endpoint that needs to be acted upon. On the UI, a warning icon will be displayed which will describe the error (e.g. HTTP status code: Unauthorized). In this example, the client endpoint assigned to the webhook is throwing an Unauthorized error and the client should take action to resolve it before restarting the webhook manually.

Webhook Failure

Average record lag alerts

Lag alerts are triggered when the average record lag exceeds a threshold over a 30-minute window. The following thresholds are monitored:

AlertThreshold
LaggingOver1Hour> 1 hour
LaggingOver1Day> 1 day

Lag is most commonly seen during the initial start of a new webhook when there is a backlog of events to process. If lag alerts persist under normal operation, consider upgrading your tier to handle higher throughput.

Note: For training events, lag alerts may reflect approval workflows, purchase/checkout flows, or external content provider latency rather than system throughput constraints. These are expected workflow-driven delays and upgrading tiers will not reduce them. See Training Event Timing for details on expected delivery timing by assignment source.

Webhook has been stopped

When the webhook moves into a stopped state, a Stopped alert event will be sent. This generally occurs when the webhook is stopped manually from the UI.

As a protective measure, the system may also stop a webhook automatically when it cannot keep up with incoming events — for example, during a sudden spike or influx. If a webhook is configured with a fixed Tier Setting for Max records in payload rather than System Default, it is less able to absorb bursts, which can lead to frequent automatic stops during high load. Using System Default allows the system to adapt the payload size to current throughput and reduces these stops.

In these cases the webhook will restart automatically once it recovers — no manual intervention is required. However, if you have an alert webhook set up, each automatic stop will still emit a Stopped alert, so you may receive what look like false alerts during these recovery cycles.

Example payloads for all of the events above can be found at Alerts Events Referenceopen in new window