Webhooks deliver an HTTP POST to a URL you control when something happens in the platform, so you don't have to poll.
Configure them in the admin console under Settings → Integrations → Webhooks: choose the events to subscribe to and supply a target URL.
- The target URL must use HTTPS.
- Authentication is optional: none or HTTP Basic, configured per webhook.
- Every delivery attempt is recorded in the webhook history for debugging.
Every delivery is a POST with this JSON body:
| Field | Type | Description |
|---|---|---|
event | string | The event code that fired. |
id | integer | ID of the affected entity. |
entity | string | Entity type, e.g. user, event, event_shift_user. |
api_endpoint | string | Full API endpoint to fetch the entity. Empty string when the entity was deleted. |
meta | object | Additional context. Present only for some events. |
{
"event": "event_shift_user:update",
"id": 84213,
"entity": "event_shift_user",
"api_endpoint": "https://example.rosterfy.com/api/v2/event/912/shift/4471/user/84213"
}The payload is deliberately thin — it tells you what changed, not the full record. Follow api_endpoint with a GET to retrieve current state. That also means you always act on fresh data rather than on a payload that may have been queued or retried.
Requests carry Content-Type: application/json and, where available, an X-Request-Id header you can use to correlate a delivery with its history entry.
Deliveries are not cryptographically signed. There is no HMAC signature header. If you need assurance that a request genuinely originated from Rosterfy, your options today are:
- Enable HTTP Basic auth on the webhook and verify the credentials.
- Treat the payload as untrusted and confirm state by calling
api_endpointwith your own authenticated token before acting.
The second is the stronger control, and we recommend it regardless: it protects you against spoofed, replayed, and out-of-order deliveries alike.
| Event code | Fires when |
|---|---|
user:register | A user registers |
user:update | A user record is updated |
user:delete | A user is deleted |
event:create | An event is created |
event:update | An event is updated |
event_user:create | A user is added to an event, including via expression of interest |
event_user:update | An event user record is updated |
event_user_activity:create | An event user activity is submitted |
event_user_activity:update | An event user activity is updated |
event_shift:create | A shift is created |
event_shift:update | A shift is updated |
event_shift_user:create | A user is assigned to a shift |
event_shift_user:update | A shift user record is updated, including status changes |
role_offer_user:create | A user is added to a role offer |
role_offer_user:update | A role offer user record is updated, including status changes |
training_user:create | Training is assigned to a user |
training_user:delete | A training assignment is removed |
training:complete | A user completes training |
form:process | A form is submitted |
report:generate | A report finishes generating |
Note that *_shift_user:update and role_offer_user:update cover both general updates and status transitions — there is no separate status-changed event. Read the entity via api_endpoint to see the new status.
Beyond the fixed list above, a webhook can be used as an action inside an Automation (Settings → Automations). There you define the trigger yourself, so the event field carries the automation task you selected rather than one of the system codes above.
{
"event": "user:checkpoint:update",
"id": 55231,
"entity": "user",
"api_endpoint": "https://example.rosterfy.com/api/v2/user/55231"
}Because event is driven by your automation task, it is effectively customer-defined. This lets you react to anything the automation builder supports, well beyond the fixed event list.
Design your receiver to tolerate an unrecognised event value rather than rejecting it — the fixed list can grow, and automation codes are open-ended.