Skip to main content

Ground Transport

When a disruption requires ground transport between the airport and the hotel — or between the hotel and the next-flight airport — Nexa orchestrates the transfer through ride-hailing or contracted transport vendors. The transport domain is the saga participant on the transport leg, with the same idempotency and async behavior as booking.

What we use it for

CapabilityVendorUse
Ride-hailing — passenger-side requestUber, CabifyOn-demand transfers initiated by the passenger from the PWA
Ride-hailing — operator-dispatchedUber, CabifyPre-booked transfers initiated by the operator at allocation time
Contracted transportPer-tenant contracted carriersHigher-cost / pre-negotiated transport for VIP tiers, group transfers

When transport fires

Transport is policy-driven. Three modes:

AUTOMATIC

The default for higher tiers. When the booking saga succeeds and the policy authorizes transport, the transport leg of the saga is enqueued automatically. Transfer details (pickup time, vehicle, ETA) appear in the passenger voucher.

ON_DEMAND

The default for lower tiers and routes with established airport shuttles. The passenger taps "Request transport" in the PWA when they need it. The dispatcher chooses the vendor based on availability, price, and tenant policy.

MANUAL

Operator-driven from the operations console. Used for irregular cases — VIP escalation, large group transfers, vendor outages. The operator picks the vendor and provides any custom instructions to the dispatch.

Architecture

Vendor selection

When the dispatcher needs to pick a vendor:

  1. Per-route eligibility — does the route fall within the vendor's coverage?
  2. Capacity — does the vendor have a vehicle available for the requested time + group size?
  3. Cost ceiling — is the price within the policy's transport-cost budget for the tier?
  4. Vendor preference — tenant policy may pin specific routes to specific vendors (e.g., "always Cabify from SCL terminal to airport hotels").

The first vendor that satisfies all four wins. If none qualify, the case enters transport-failed state and the operator is alerted.

Authentication

VendorAuth
UberOAuth2 client credentials per tenant
CabifyAPI key per tenant
Contracted carrierCustom — typically API key + IP allowlist

All credentials are tenant-managed under nexa/<tenant>/vendor/<vendor>/.

Rate limiting

Each vendor has its own egress token bucket (uber.rides, cabify.rides, plus one per contracted carrier) keyed in the cluster-wide limiter. Configured per-tenant per published vendor TPS.

Idempotency

Every transport request carries a Nexa-side transfer URN (urn:transfer:<id>). The vendor adapter passes the URN as the request's external reference. Replays return the existing transfer without creating a duplicate dispatch.

Webhook flow

Each vendor delivers state updates via HMAC-signed webhooks:

  • Dispatched — vehicle assigned, ETA known.
  • In-progress — pickup confirmed.
  • Completed — drop-off confirmed.
  • Cancelled — passenger or driver cancelled.
  • Failed — no vehicle available within the requested window.

The transport domain reconciles the webhook against the local transfer record, updates the case timeline, and pushes a transport-updated event over the operator WebSocket and the passenger SSE stream.

Saga compensation

If the booking is cancelled (passenger declines, vendor rolls back), the transport leg is cancelled too. The transport domain emits CancelTransfer to the appropriate vendor adapter; the vendor adapter calls the vendor's cancel endpoint with the transfer URN.

Transport cancellations have shorter deadlines than hotel cancellations — typically 5–15 minutes before the dispatched pickup time. Past-deadline cancellations charge the tenant a no-show fee (per vendor terms) but do not block the saga. Operators see a "transport cancellation incurred fee" indicator on the case timeline.

Permanent-failure classification

FailureClassificationAction
No vehicle available within windowPermanent (this attempt)Try next vendor; if all fail, surface to operator.
Vendor rate-limit / 5xxTransientRetry with backoff.
Cancellation past deadlinePermanentRecord fee; do not retry.

Operator monitoring

The operations console shows live transport state per case:

  • Pending dispatches (vehicle yet to be assigned).
  • In-progress (vehicle assigned, passenger en route).
  • Completed (drop-off confirmed).
  • Failed (no dispatch possible).

Failed dispatches surface in the manual-review queue so operators can fall back to direct contact with the hotel's shuttle service or a phone-call dispatch.

Compliance

Vendors are data sub-processors under Nexa's tenant DPAs. Per-passenger data sent: lead-passenger name, contact (for vendor SMS), pickup + drop-off addresses, group size. No PNR, no document numbers.

Onboarding checklist

  • Tenant procures vendor accounts (Uber Business, Cabify Business, etc.) + API keys.
  • Credentials in nexa/<tenant>/vendor/<vendor>/.
  • Per-vendor TPS configured.
  • Webhook endpoints registered.
  • Per-route policy configured (vendor preference, cost ceiling).
  • First end-to-end transfer validated against sandbox case.
Was this helpful?