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
| Capability | Vendor | Use |
|---|---|---|
| Ride-hailing — passenger-side request | Uber, Cabify | On-demand transfers initiated by the passenger from the PWA |
| Ride-hailing — operator-dispatched | Uber, Cabify | Pre-booked transfers initiated by the operator at allocation time |
| Contracted transport | Per-tenant contracted carriers | Higher-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:
- Per-route eligibility — does the route fall within the vendor's coverage?
- Capacity — does the vendor have a vehicle available for the requested time + group size?
- Cost ceiling — is the price within the policy's transport-cost budget for the tier?
- 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
| Vendor | Auth |
|---|---|
| Uber | OAuth2 client credentials per tenant |
| Cabify | API key per tenant |
| Contracted carrier | Custom — 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
| Failure | Classification | Action |
|---|---|---|
| No vehicle available within window | Permanent (this attempt) | Try next vendor; if all fail, surface to operator. |
| Vendor rate-limit / 5xx | Transient | Retry with backoff. |
| Cancellation past deadline | Permanent | Record 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.