We have introduced a structured tour compensation object as the single source of truth for what a driver is paid out for a tour. It consolidates base earnings, bonuses, and tips into one auto-totalled view — exposed via a dedicated API, surfaced to drivers on tour cards via two new configurable labels, and observable for server-to-server integrations through a dedicated webhook.
The new object is purpose-built for the kind of compensation logic 3PL operations need: per-component editing, bonus components with self-provided keys, and a structured breakdown that is accessible to drivers. It is the foundation to build robust payroll reporting on top of, and the place to express anything richer than a flat payout number going forward.
The legacy single-amount earnings attribute it supersedes is now
deprecated
and will be removed on 2026-11-06.
Where to start
The full surface and its conventions live under the Tour Compensation tag — the tag overview goes deeper than this announcement on currency rules, idempotency, and how concurrency is handled. Start there if you’re integrating.
What’s new
A structured object on every tour — read the current breakdown via Get tour compensation. Three slots, all expressed in a single tour-wide currency:
- 💵 Base earnings — set with Set tour base earnings, cleared with Delete tour base earnings.
- 🎯 Bonuses — up to five named incentives, each addressable by a
stable
key. Set with Set tour bonus, cleared with Delete tour bonus. Bonuses come back sorted bykeyso the order is stable across reads. - 💝 Tips — read-only via the API and reserved for platform-side population. Automatic tip calculation on tour completion, driven by configurable strategies, is coming soon.
total_amount is recomputed automatically whenever any component
changes, and labels + metadata are kept on each component for
human-readable display and audit context.
Bonus-key uniqueness as a built-in safeguard. A bonus key is
enforced unique per tour. This is more than a data-model nicety: it
means an accidental retry, a duplicated job, or a re-fired campaign
event can’t double up the same incentive on the same tour. Use this to
your benefit — pick a stable, descriptive key
(completion_q1, peak_hours, late_night) for anything that should
never accidentally stack, and reach for distinct keys when you genuinely
want multiple incentives to coexist on the same tour.
Currency-aware writes. Every write must include currency, and the
API rejects any value that doesn’t match the tour’s resolved currency
(the service area’s local_currency, with fallback to the tenant-wide
base_currency). This keeps tours that span service areas configured
in different currencies from silently miscalculating.
Concurrency-safe writes. Per-component writes are idempotent and
last-write-wins. Concurrent edits on the same component resolve via a
409 Conflict on the losing caller — read back, then retry. Writes to
different components don’t contend and proceed in parallel.
A debounced webhook. Subscribe to
tour.compensation_updated to react to
changes. After a compensation component changes, we wait for a
120-second quiet window before firing — any further change on the
same tour resets the timer. When the timer expires, a single webhook
fires with the current state. Bursts of writes (e.g. setting base
earnings + two bonuses in quick succession) collapse into one delivery
that reflects the final state, not each intermediate step. The payload
excludes labels and metadata so subscribers can act on amounts without
round-tripping to our backend.
Driver-app visibility. Two new configurable labels — Compensation and Tips — surface the breakdown directly on the driver’s tour cards. The Compensation label shows the headline payout (base earnings plus bonuses, with tips excluded so the number stays stable across the tour); the Tips label surfaces the tip row separately when one is set. Both ship with sensible default prefix translations and are configurable on both the off-route and active-tour displays via Update Tour Display Configuration.
Migrating off the legacy earnings surface
The flat earnings attribute on tours, the
⚠️ Update driver earnings endpoint, and the
⚠️ tour.earnings_updated webhook are now
deprecated and will be removed on 2026-11-06. The new compensation
object is the migration target — see the
deprecation announcement
for the side-by-side guide. There’s no behavioural change to the legacy
surface within the deprecation window; switch over at your own pace.