Alvys emits webhook events for the trip lifecycle, so external systems stay in sync in real time instead of polling the Trips API.
| Event | Fires when | Carries data.diff |
|---|---|---|
trip.status.changed | A trip's status transitions | No |
trip.changed | Any meaningful trip write (carrier, driver, stops, appointments, rates, …) | Yes (optional) |
Subscribe to either or both when creating or updating a webhook (see Webhook Lifecycle & Configuration). The full list of valid event-type strings is returned by GET /api/p/v1/webhooks/event-types.
Status vs. changed
trip.status.changed fires only on a status transition and never includes a data.diff.
trip.changed fires on every meaningful write — including status changes — and can include an optional data.diff describing what changed. See Change Diffs (data.diff).
A single underlying write can emit both events — one
trip.status.changedand onetrip.changed. They are distinguished by the suffix on the eventid:-1for the status event and-0for the changed event. UseX-Alvys-Event-Idfor idempotency so the two are processed independently and duplicates are ignored.
Payload
Trip events use the standard Alvys webhook envelope. The data.trip object carries the full current snapshot of the trip — the same shape the Trips API returns from its GET endpoint.
trip.status.changed
trip.status.changed{
"id": "7be1220a-1c22-4f10-b8a1-2d3e4f5a6b7c-1",
"type": "trip.status.changed",
"timestamp": "2026-02-23T15:19:35.8794642+00:00",
"version": "v1",
"data": {
"trip": { "...": "full current Trip snapshot (matches GET /api/p/v1/trips)" }
}
}trip.changed
trip.changed{
"id": "7be1220a-1c22-4f10-b8a1-2d3e4f5a6b7c-0",
"type": "trip.changed",
"timestamp": "2026-02-23T15:19:35.8794642+00:00",
"version": "v1",
"data": {
"trip": { "...": "full current Trip snapshot" },
"diff": {
"changes": [
{ "kind": "CarrierChanged" },
{ "kind": "AppointmentChanged", "target": { "type": "Stop", "id": "abc123" } },
{ "kind": "StopReordered" }
],
"previousAttributes": { "...": "previous values (opt-in)" }
}
}
}Trip stop-scoped changes (
StopAddressChanged,AppointmentChanged,StopReordered, …) carry atargetof{ "type": "Stop", "id": "<StopId>" }, whereidis the stable stop identity from the snapshot — never a positional index.
Notes
- Because
data.tripalways carries the full snapshot, you can apply the current state directly without a follow-upGET. To react to only what changed, usedata.diff. - Delivery is at-least-once — deduplicate on
X-Alvys-Event-Id. See Event Delivery & Reliability. data.diffis omitted on the first event for a trip (create) and is never present ontrip.status.changed.