Delivery and retries
Delivery is asynchronous. The action that caused the event — a student submitting, an administrator awarding — completes without waiting for your endpoint, and the delivery is queued behind it.
That means a webhook arrives shortly after the change, not during it. If your endpoint calls the REST API to fetch more detail, the change is already committed and visible.
What counts as delivered
The response body is not interpreted — only the status code. AwardSpring keeps the first 500 characters of it in the delivery log, which makes your own error messages the fastest way to diagnose a failure.
Ten seconds is the whole budget, including TLS handshake. Do the work asynchronously: acknowledge with a 200, then process. An endpoint that finishes its work before responding will start timing out the first time your database is slow.
The retry schedule
An event is attempted up to 6 times. The wait before each retry grows:
Roughly 8 hours and 36 minutes pass between the first attempt and the last. An outage shorter than that recovers on its own with no data lost.
Each attempt is signed fresh, so X-AwardSpring-Signature carries a current timestamp on a retry — only X-AwardSpring-Event-Id and the body stay the same. The attempt number is in X-AwardSpring-Delivery-Attempt.
When an endpoint stays down
After the sixth failure the event is dead-lettered: it is no longer retried, the endpoint’s consecutive-failure count increases, and — if the endpoint has a notification email — AwardSpring emails it.
That email names the endpoint URL, the event type and the attempt count. It deliberately carries no event payload, so it is safe to route to a shared inbox or a ticketing system.
A dead-lettered event is not lost. It stays visible in the delivery log and can be replayed once the endpoint is healthy.
Delivery logs and replay
Settings → API → Webhooks shows a log per endpoint: event type, event id, attempt number, HTTP status, duration, and the response snippet, for successes and failures alike. Test sends and replays are marked as such.
From that log, an administrator can replay an event. A replay:
- keeps the original
idandoccurred_at, so your deduplication still recognises it as the same event; - rebuilds
datafrom current records, so a name corrected since the original send arrives corrected; - is limited to 20 replays per hour per institution.
Because the payload is rebuilt, a replay is not a byte-for-byte copy of what was first sent. Treat it as “the current truth about this event”, not as an archive.
Events emitted before payload rebuilding existed have no stored trigger, and those replays fall back to the payload captured at the time. The id behaves identically either way.
Test sends
Before pointing a new endpoint at production traffic, send a test from the endpoint’s action menu. Pick any event type and AwardSpring posts a fully-formed, correctly-signed payload built from sample data.
A test send:
- carries
"is_test": truein the envelope, so your handler can discard it; - uses
evt_test_as the event id prefix; - is signed with the real secret, so it exercises your verification code for real;
- does not count toward the endpoint’s failure count, and never disables an endpoint.
The obvious use is confirming reachability. The more valuable one is confirming your signature check rejects things: change a byte of the secret on your side and check the test send fails.
Where events come from
AwardSpring emits events from the database change itself, not from a particular screen. An application submitted by a student in the portal, and an award recorded by an administrator, produce the same event as the equivalent change made another way. You do not need to know which part of AwardSpring an institution used.
Two consequences worth planning for:
- Bulk imports and bulk data loads may not emit events. High-volume paths that write directly to the database bypass event emission. After a large import, reconcile with the REST API rather than assuming a webhook arrived for every row.
- Delivery is at-least-once, never exactly-once. Combined with unguaranteed ordering, that makes
iddeduplication andoccurred_atsorting the two things your handler cannot skip.