Delivery and retries

What happens between the event and your 200.

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

Your responseResult
Any 2xxSuccess. Nothing further is sent for that event.
Any 3xx, 4xx, 5xxFailed. Retried on the schedule below. Redirects are not followed.
No response within 10 secondsFailed, recorded as a timeout, and retried.
Connection refused, DNS failure, TLS errorFailed, recorded as a transport error, and retried.

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:

After attemptNext attempt in
11 minute
25 minutes
330 minutes
42 hours
56 hours
6— dead-lettered

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 id and occurred_at, so your deduplication still recognises it as the same event;
  • rebuilds data from 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": true in 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 id deduplication and occurred_at sorting the two things your handler cannot skip.