Skip to content

Trip Edit Mode (Soft Lock)

Taxi & Private HireProductsTrip › Trip Edit Mode (Soft Lock)

Generally available

Time-bound soft indicator that an operator is currently editing a trip. Background workers (dispatch sweep, optimiser merge, recurring releaser, capacity sweep, health auto-resolve) check the flag and defer derived-state writes while it's active so the operator's edits aren't clobbered mid-flight. The lock auto-expires so a crashed FE never permanently stalls a trip.

Example request

POST /client/{clientId}/trip

{
  "pricingMode": "METERED",
  "tripSegments": [
    {
      "customer": {
        "phone": "<E.164 phone>"
      },
      "tripSegmentStops": [
        {
          "type": "PICKUP",
          "pickupAddress": "<address>",
          "pickupLatitude": "<lat>",
          "pickupLongitude": "<lng>"
        },
        {
          "type": "DROPOFF",
          "pickupAddress": "<address>",
          "pickupLatitude": "<lat>",
          "pickupLongitude": "<lng>"
        }
      ],
      "requestedPickupDate": "<unix-seconds>"
    }
  ],
  "maxSeatCapacity": "<seats>"
}

Endpoints

MethodPath
POST /client/{clientId}/trip · primary
GET /client/{clientId}/trip
POST /client/{clientId}/trip/{tripId}/assign/{transporterId}
POST /client/{clientId}/trip/{tripId}/reclaim
POST /client/{clientId}/trip/{tripId}/designate
DELETE /client/{clientId}/trip/{tripId}/designate
POST /client/{clientId}/trip/{tripId}/status
POST /client/{clientId}/trip/{tripId}/health/resolve
GET /client/{clientId}/rejected-trip
POST /client/{clientId}/trip/{tripId}/copy
GET /client/{clientId}/trip/{tripId}
GET /client/{clientId}/trip/{tripId}/dispatch-audit/{transporterId}
GET /client/{clientId}/trip/{tripId}/dispatch-log
POST /client/{clientId}/trip/{tripId}/edit/release
POST /client/{clientId}/trip/{tripId}/guard-override
GET /client/{clientId}/trip/{tripId}/guard-status
GET /client/{clientId}/trip/{tripId}/health
GET /client/{clientId}/trip/{tripId}/logs
POST /client/{clientId}/trip/merge
POST /client/{clientId}/trip/merge/analyze
POST /client/{clientId}/trip/{tripId}/merge/candidates
POST /client/{clientId}/trip/{tripId}
GET /client/{clientId}/trip/count
GET /client/{clientId}/trip/optimizable
GET /client/{clientId}/trip/optimizable-accounts
GET /client/{clientId}/trip/sync

Full request/response schemas and an interactive explorer will live in the API reference (coming soon).

Use cases

Operator flows that exercise this feature.

Create a booking

action risk: low

Take a new ASAP booking — optionally quote first, then create the trip.

  1. POST /client/{clientId}/quote/trip
  2. POST /client/{clientId}/trip
Book on a corporate account

action risk: low

Create a trip billed to a corporate account rather than the individual rider.

  1. POST /client/{clientId}/trip
Force-assign a driver

action risk: medium

Immediately assign a trip to a chosen driver (force-now) — distinct from designate, which reserves through allocation.

  1. POST /client/{clientId}/trip/{tripId}/assign/{transporterId}
Reclaim a trip from a disconnected driver

action risk: low

Detect a trip whose assigned driver has gone stale (lost GPS / disconnected) and reclaim it back to allocation so it can be re-dispatched.

  1. POST /client/{clientId}/trip/{tripId}/health/resolve
  2. POST /client/{clientId}/trip/{tripId}/reclaim
Manual dispatch (designate a driver)

action risk: low

Operator manually dispatches a trip by designating a chosen driver, who then holds the trip through allocation (the engine reserves/offers to them rather than dispatching openly). Industry "manual dispatch" lives on the designate endpoint.

  1. POST /client/{clientId}/trip/{tripId}/designate
Clear a designation

action risk: low

Remove a manual driver designation so the trip returns to open dispatch.

  1. DELETE /client/{clientId}/trip/{tripId}/designate
Cancel a booking

action risk: low

Cancel a trip. Cancel is NOT its own endpoint — it is a status transition to CANCELLED (Finding 1). If you only have a passenger name / destination, resolve the tripId first with find-trip.

  1. POST /client/{clientId}/trip/{tripId}/status
Re-book by copying

action risk: low

Duplicate an existing trip to quickly re-book a repeat journey.

  1. POST /client/{clientId}/trip/{tripId}/copy
Diagnose allocation

read_diagnose risk: low

Explain why a trip wasn't allocated: read the dispatch audit + decision log.

  1. GET /client/{clientId}/trip/{tripId}/dispatch-audit/{transporterId}
  2. GET /client/{clientId}/trip/{tripId}/dispatch-log
Release a trip edit lock

action risk: low

Release a stuck operator edit lock on a trip so others can edit it.

  1. POST /client/{clientId}/trip/{tripId}/edit/release
Override a dispatch guard

action risk: high approval required

Override a capacity/time/proximity guard to push a trip past a block. Audit-logged; operator/system only.

  1. POST /client/{clientId}/trip/{tripId}/guard-override
Merge into a shared ride

action risk: medium

Combine compatible trips into one shared-ride vehicle: analyse compatibility, then execute the merge.

  1. POST /client/{clientId}/trip/merge/analyze
  2. POST /client/{clientId}/trip/merge
Find merge candidates

read_diagnose risk: low

Suggest nearby trips that could merge with a given trip.

  1. POST /client/{clientId}/trip/{tripId}/merge/candidates
Amend a booking

action risk: low

Modify an existing booking (pickup, time, passengers).

  1. POST /client/{clientId}/trip/{tripId}
Find a trip

read_diagnose risk: low

Look up live / scheduled trips by free-text keyword (passenger name, pickup/drop-off address, reference) to resolve a tripId — e.g. before cancelling, amending or diagnosing a trip. Reads the dispatch grid via trips_sync. The keyword is passed as a QUERY param, not a body: search is a JSON-encoded string (see trip-search-query note).

  1. GET /client/{clientId}/trip/sync

Fields

FieldTypeDescription
creatorId bigint Actor that created the trip — the underlying record varies by `creator_type` (User, Driver, App, or System). Pinned for audit; never rewritten after the trip is built.
appKeyId bigint API key that was used to create the trip. Identifies the originating integration (customer app, partner booking system, internal console) for support + analytics.
bookingSource BookingSource · PHONE | APP | WEB | OPERATOR | INTEGRATION Channel the booking came through (OPERATOR / APP / WEB / PHONE / INTEGRATION), derived from the authenticated application (its app key's channel) at creation — never from the payload. Denormalised into TripSegmentArchive for customer-retention analytics.
pickupDate integer Derived earliest pickup time across non-finished segments (Unix). Recomputed by `SetPickupDate` on segment edits; drives dispatch ordering, ETA, and the dispatch index.
pickupH3Index string Resolution-8 H3 cell containing the primary pickup point. Used by RES-016 fleet metrics, scheduled-demand lookups, and the H3 heat map.
releaseDate integer Time the trip becomes dispatch-eligible (Unix). ASAP trips ≈ creation time; pre-bookings stage until this fires. `effectiveReleaseDate` carries the priority-adjusted variant.
dispatchedDate integer Unix timestamp the trip most recently entered the dispatch loop (ALLOCATION). Re-stamped on re-allocation cycles — pair with `initialDispatchedDate` for the original release moment.
initialDispatchedDate integer Unix timestamp the trip first entered dispatch. Latched on first transition — never re-stamped on re-allocation so urgency + priority metrics see the original release moment.
pausedDate integer Unix timestamp the trip was last moved to PAUSED. Stamped on each PAUSE; drives the stuck-dispatch failsafe auto-cancel (a trip left PAUSED beyond the threshold is cancelled).
assignedDate integer Unix timestamp a transporter was assigned. Stamped inside `setAssignedTransporter`; cleared when assignment falls through (rejection, no-show, manual revoke).
acceptDate integer Unix timestamp the driver accepted the assignment. Distinct from `assignedDate` — there is a brief offer window between the two for the driver to accept or reject.
startDate integer Unix timestamp the first segment entered ENROUTE. The trip is "live" from this moment for monitoring, guards, and time-window enforcement.
finishedDate integer Unix timestamp the trip reached a terminal state (FINISHED or CANCELLED). Anchors the archive cursor — trips older than the cursor get archived in batch.
lastEditTouch integer Soft "edit mode" timestamp set when an operator opens the trip for editing. Background workers consult `isEditModeActive()` to defer derived-state writes during the EDIT_MODE_BUFFER_SECONDS window so concurrent edits do not clobber each other.
status TripLifecycleEnum · NONE | SCHEDULED | SCHEDULED_PAUSED | ALLOCATION | PAUSED | DESIGNATED | ASSIGNED | ASSIGNED_STAGING | INPROGRESS | FINISHED | CANCELLED | RECURRING_SCHEDULE Trip lifecycle state: NONE → RECURRING_SCHEDULE / SCHEDULED → ALLOCATION → DESIGNATED → ASSIGNED → INPROGRESS → FINISHED, with PAUSED, ASSIGNED_STAGING, and CANCELLED branches. Single source of truth for dispatch eligibility, visibility, and pricing windows.
cancellationActor CancellationActor · CUSTOMER | OPERATOR | DRIVER | SYSTEM Who initiated the cancellation (CUSTOMER / OPERATOR / DRIVER / SYSTEM), asserted at the cancel call — there is no CUSTOMER auth type, so a customer cancellation is one an operator marks on the customer's behalf. Drives customer-fault penalties (no-show / late-cancel miles). Null until the trip is cancelled.
tripSegments Collection Child segments — the actual units of work. Trip is a coordinator that holds shared lifecycle, capacity, and trip-level pricing state across them; the segments carry customer, account, stops, quote, and price per-fare.
assignedTransporter Transporter Transporter currently holding the trip (post-acceptance). Set by `setAssignedTransporter`, cleared on cancel/no-show. If a `designatedTransporter` is set, only that driver can be assigned.
designatedTransporter Transporter Driver the trip is locked to (offer designation). Set by manual operator action or automated rescue (`ProblemTripDesignationService`); only this driver can accept. Distinct from `assignedTransporter` — designation is the offer, assignment is the acceptance.
tripUnitOfWorks Collection Materialised driver itinerary — each UoW is one execution leg (co-located stops grouped by proximity). Recomputed by `UnitOfWorkMaterialiser` on every trip mutation; preserves INPROGRESS/FINISHED UoWs as anchors and rebuilds the remaining NONE UoWs.
originatingFleet Fleet Fleet the trip was booked under — the trip's single ownership identity. Grouped reads may expand to a wider operating pool via `FleetContextResolver` + `FleetGroup`, but the trip itself always belongs to exactly one fleet.
friendlyId string Human-readable short identifier (e.g. T-1234). Surfaced in the driver app, customer SMS, and support tools; never changes across the trip's lifetime.
isSchedule bool True for a recurring master that spawns worker trips on schedule. The master itself never dispatches; `setIsSchedule()` swaps status between RECURRING_SCHEDULE and SCHEDULED.
schedule string Schedule spec defining when the recurring master spawns worker trips (cron-like syntax). Only meaningful when `isSchedule=true`; ignored on one-off bookings.
parentTripId bigint Id of the recurring master that spawned this worker trip. Null on one-off bookings; populated by `CopyTrip` when the scheduler releases a worker.
pickupZone Zone Resolved dispatch zone containing the pickup point. Drives zone-scoped supply, capacity gates, and the operator dispatch board grouping.
schedulePlan TripSchedulePlan Time-window plan for the trip — owns pickup/dropoff window targets, anchor metadata, and the projected itinerary timestamps used by the optimiser.
tripQuote TripQuote Trip-level Quote. Carries the BILLING role when `singlePriced=true`; otherwise it carries a SHADOW fixed-fare alternate for comparison. See `Quote.role` and `BillingQuoteResolver` for the source-of-truth picker.
tripPrice TripPrice Trip-level realised Price (mirrors `tripQuote` when active). FIXED-mode trips lock it at booking; METERED-mode would recompute at completion. Read through `BillingQuoteResolver`, not directly.
isScheduleWorker bool True when this trip was spawned by a recurring master. Excluded from the FE's "Recurring Schedules" list (which only shows masters) and from re-scheduling UX.
archivedDate integer Unix timestamp the trip was archived by `ArchiveTrips`. Archived trips are read-only and excluded from live dispatch queries; they remain visible in history.
maxSeatCapacity smallint Upper bound on combined occupants across overlapping segments. Enforced consistently by the capacity sweep, UoW materialiser, and our optimisation engine optimiser — all three layers agree on this number.
minSeatCapacity smallint Fixed seat requirement when set — anchors vehicle-size selection and skips the capacity sweep. Used for group bookings or trips where a specific seat count is contractually required.
capacitySweepStatus TripCapacitySweepStatus · PENDING | COMPLETED | BYPASSED State of the async capacity sweep that re-evaluates plan feasibility across vehicle sizes after segment edits. BYPASSED when `minSeatCapacity` short-circuits or the trip is too small; PENDING during recompute; COMPLETED once a plan is locked in.
autoDispatchEligibility AutoDispatchEligibility · ELIGIBLE | OUT_OF_POLICY Whether the auto-dispatch worker will consider this trip. Set to OUT_OF_POLICY by `PlanResolver` when the trip's seat requirement exceeds the client's `planningSweepCapacities`; affected trips stay in ALLOCATION for operator manual assignment.
vehicleType VehicleType Resolved vehicle-type requirement (saloon, MPV, accessible, etc.). Derived from segment-level capabilities + capacity; narrows the eligible-driver pool during dispatch scoring.
route Route Cached the routing service-derived route across the merged trip itinerary (duration, distance, polyline, provider/accuracy). Refreshed by `PlanResolver`; consumed by the optimiser and customer-facing ETAs.
planCompressionPercentage smallint Legacy denormalised plan-compression metric. Stale-prone — the FE now computes this live from UnitOfWork routes via the Quote Roles work. Kept for backwards compatibility; do not consume in new code.
bypassCapacityCheck bool Write-only operator override that suppresses the capacity sweep for this trip. Never serialised back to the client; only consumed during the create/update pipeline.
requiredClientCapabilities Collection Tenant capabilities (wheelchair, child seat, etc.) the assigned vehicle must satisfy. Aggregated from segment-level requirements and frozen on the trip so dispatch filtering can run against a single bitmask.
capabilityMask string 32-bit bitmask precomputed from `requiredClientCapabilities`. Lets the dispatch query filter eligible vehicles with a single bitwise AND instead of a join across the capability tables.
bypassProximityGuards bool Operator override that disables arrival-proximity guards. Used for trips where the driver legitimately cannot pull right next to the address (gated communities, large venues, ferry terminals).
bypassTimeGuards bool Operator override that disables time-window guards. Used for trips where late starts are expected (long wait scenarios, special events) and should not trigger health alerts.
multiLoading bool True when the trip has been chained with others into a shared driver itinerary. Set by the merge analyser; flips on shared-pricing pathways and the multi-load UI affordances.
singlePriced bool True when the trip uses trip-level pricing (one Quote/Price across all segments). False = per-segment pricing. Drives which discount model field is consulted (`singlePricedShareDiscountModel` vs `rideShareDiscountModel`).
pricingMode PricingMode · FIXED | METERED Trip-level METERED vs FIXED. Only consulted when `singlePriced=true` (where Quote/Price live on the trip, not on each segment). Defaults from `Client.defaultPricingMode` at trip-create time; the column default is the fallback when no client context is available.
operatorManagedModel bool When false, the backend re-matches the discount model via the decision tree on every save. When true, the backend uses the operator-attached model verbatim and the validator requires a non-null model for the active mode.
operatorManagedShares bool When false, share percentages are recomputed by `ShareStrategyComputer` on every save. When true, the operator-supplied per-segment shares are used verbatim; validator requires sum=100 and every share > 0.
singlePricedShareDiscountModel SinglePricedShareDiscountModel Active discount model when `singlePriced=true`. Snapshot resolved by `the system`; mutually exclusive with `rideShareDiscountModel`.
rideShareDiscountModel RideShareDiscountModel Active discount model when `singlePriced=false` (ride-share / pool). Mutually exclusive with `singlePricedShareDiscountModel`; use `getActiveDiscountModel()` to pick the right one without branching.
upliftPercentage integer Cost-basis multiplier applied to the trip total. 0 = no uplift; the resolver falls back to the active model's default uplift when this is 0 and the model carries one. The value itself carries the operator-vs-default intent — no separate source flag.
hasHealthAlert bool Denormalised "any check in WARNING" flag set by the health pipeline. Drives the FE's amber health badge and the operator dashboard filter — the underlying checks live on TripHealthCheck.
hasHealthCritical bool Denormalised "any check in CRITICAL" flag set by the health pipeline. Drives the FE's red health badge and surfaces the trip in the support escalation queue.
allocationIssueType string · HIGH_DEMAND | LOW_SUPPLY | CAPABILITY_MISMATCH | REJECTION_PATTERN | TIMING_MISMATCH Classification of why a trip is stuck in allocation (LOW_SUPPLY, NO_ELIGIBLE_DRIVER, etc.) — set by `AllocationRiskCheck`. Powers the dispatch-issues panel and gates automated rescue designation.
meta json Free-form JSON for service-specific annotations (allocation-radius snapshots, sweep diagnostics, projected dispatch radius for AllocationRiskCheck). Schema is convention-based; do not rely on a stable shape.
prebooked bool True when the trip is in the pre-booking staging pipeline (ASSIGNED_STAGING). Drives driver self-scheduling UX and the confirm-window enforcement on the driver app.
region Region Geographic region scope. `RegionFilter` restricts cross-tenant queries by this field; null = global. Set by `RegionResolver` at trip-create time based on the pickup location.
tripProfiles Collection Operator-curated profiles applied to the trip (Corporate, VIP, etc.). Drive bespoke pricing/dispatch behaviour without modifying the booking itself; resolved at trip-create time from Customer/Account context.
scheduleExclusionGroups Collection Operator-managed groups that can pause this recurring trip's release. Any linked group resolving to OFF blocks the next release; curated via the schedule editor's Admin column. Must NOT be `passive` — that would skip change-tracking on save.
clientId bigint Tenant scope. Every tenant-aware entity carries this; `ClientFilter` enforces row-level isolation on read; the multi-tenancy routing layer (`/client/{clientId}`) sets it at create time. Surfaced only under `admin` / `tripLog` groups — never to end users.
internalKey string Optional client-supplied external reference / idempotency key. When present, lets external systems correlate platform-side records back to their own source-of-truth ids. Not persisted to a column — populated by the request handler when the caller sets it.
__objectType string Discriminator string (entity class short-name) emitted alongside the id in serialized output. Resolved at read time by `getObjectType()`; lets the FE dispatch entity-specific rendering without inspecting the URL.
id bigint Snowflake-style primary key (unsigned BIGINT). Generated by `IdFactory` at create time; surfaced to the FE / API as a `G`-prefixed string and stripped back to plain bigint server-side before Doctrine lookup.
createdDate integer Unix timestamp the row was first persisted. Set in the entity's PrePersist hook; never rewritten on subsequent updates.
updatedDate integer Unix timestamp the row was last touched. Bumped on every commit that hits the Doctrine UoW for this entity; drives FE invalidation + the listing change cursor.
passiveUpdatedDate int Read-through alias for `updatedDate` exposed under different serializer groups. Lets the FE distinguish "real edit" from "background touch" projections without changing the underlying column.
listingUpdatedDate int Listing-projection timestamp surfaced only under the `listMode` group. Driven by `TripCache` and other listing-shape refreshers separately from `updatedDate` so a listing rebuild doesn't trigger detail-page invalidation.