Webhook lifecycle

Webhook lifecycle

Why webhooks exist

Polling an API on a fixed schedule is straightforward but inherently wasteful: most calls return no changes, and when changes do occur, the consumer discovers them only at the next poll interval. For integrations that need near-real-time awareness of workforce data changes – a dashboard refreshing shift assignments, a payroll system reacting to corrected clockings – the delay and overhead of polling are unacceptable.

Webhooks invert the communication direction. Instead of the consumer asking “has anything changed?”, the Protime API Connector pushes change events to the consumer the moment they occur. This reduces latency to seconds and eliminates empty polling cycles entirely.

Event model

When a resource in a subscribed collection changes – whether through the API, the Protime user interface, or an internal calculation – the connector raises a change event. The event payload contains the same structure as a delta response item: a changeType (InsertOrUpdate or Delete) and the affected data, including a changeVersion for ordering and deduplication.

The connector delivers each event as an HTTP POST request to the destinationUrl that the consumer specified when creating the webhook subscription.

Multiple events from a single action

Certain operations in Protime trigger automatic recalculations. For example, inserting a single clocking may cause the system to recalculate totals, counters, and paid presences. Each affected collection emits its own webhook event. Consumers should expect that one user action can produce multiple webhook deliveries across different subscribed collections, and should use changeVersion to handle this correctly.

Lifecycle states

A webhook subscription moves through a well-defined set of states:

  stateDiagram-v2
    [*] --> Enabled : POST /webhooks
    Enabled --> Enabled : Events delivered successfully
    Enabled --> Disabled : Retries exhausted
    Enabled --> Disabled : validUntil reached
    Disabled --> Enabled : Renewed (POST /webhooks)
State Description
Enabled The subscription is active and events are being delivered to the consumer. This is the initial state after creation.
Disabled The consumer’s endpoint failed to respond with a success status code after all retry attempts, or the subscription’s validUntil timestamp has passed. Event delivery has stopped.

A disabled webhook can be renewed by calling POST /webhooks with the same destination URL and collection name. The system re-enables the existing subscription with a new key and validity period rather than creating a duplicate. However, events that occurred while the webhook was disabled are not replayed, so the consumer must perform a full data re-synchronization before renewing to ensure no changes were missed during the gap.

Delivery guarantees

The Protime API Connector provides at-least-once delivery. This means:

  • Every event will be delivered at least once, assuming the consumer’s endpoint is reachable within the retry window.
  • The same event may be delivered more than once – for example, if the consumer’s response was lost in transit or if a network timeout occurred after the consumer processed the event.

Consumers must therefore implement idempotent processing. The changeVersion field on each event serves as the idempotency key: if an incoming event has a changeVersion that is lexicographically less than or equal to the version already stored for that record, the event can be safely discarded.

Retry strategy

When an event delivery fails (the consumer returns a non-success HTTP status code, or the connection times out), the connector retries on an escalating schedule:

Retry Delay since previous attempt
1st 1 hour
2nd 3 hours
3rd 8 hours
4th 24 hours
5th (final) 36 hours

If the consumer still fails after the fifth retry, the webhook is disabled and all pending events in a retry state are purged. The total retry window spans approximately 72 hours, giving the consumer a finite opportunity to recover from outages.

HMAC-SHA256 signature

Every webhook delivery includes an Authorization header with the scheme HMAC-SHA256 followed by a Base64-encoded signature. The signature is computed over the exact JSON request body using the private webhook key that was returned when the subscription was created.

This mechanism provides two guarantees:

  1. Authenticity – the consumer can verify that the request genuinely originated from the Protime API Connector, not from an external attacker.
  2. Data integrity – any tampering with the event payload during transmission will cause the signature check to fail.

Validating this header is the consumer’s responsibility and is strongly recommended. The signature must be computed against the raw request body; deserializing and re-serializing the payload may produce a different byte sequence and a mismatched signature.

Recovery after expiration or disablement

When a webhook is no longer active – whether due to expiration or retry exhaustion – the consumer should not simply renew and continue as if nothing happened. Changes that occurred while the webhook was inactive are not replayed upon renewal. Recovery requires a full data re-synchronization before renewing the subscription, because the renewed webhook only delivers events that occur after the renewal. Any changes during the inactive period exist only in the collection’s current state, not in the event stream.

For the step-by-step recovery procedure, see Handle webhook expiration.

Further reading

  • Set up webhooks – step-by-step instructions for creating, validating, and managing webhook subscriptions
  • Webhooks reference – properties, supported collections, HMAC specification, and retry schedule
  • Delta synchronization – the pull-based alternative to webhooks