Mobile app quickstart
Build a native iOS or Android app where operators and drivers log in as themselves, switch between businesses, and run trips, dispatch and quotes from their phone.
Two ways to authenticate
The API accepts two kinds of Bearer token. A business API key is long-lived and bound to one business — great for server-to-server integrations, but never safe to embed in an app a user installs. A user access token is obtained by logging a person in, is short-lived, and can act on every business that person can access. Mobile apps use user tokens.
Every endpoint in the reference accepts a user token except the handful marked as API-key specific.
1. Log in
Exchange the user's email and password for an access token (a
15-minute JWT) and a refresh token (valid 30 days). The response also
lists every business the user can act on — use it to render a business switcher.
Pass an optional device_name so the user can recognise the session later.
Request
curl -X POST https://app.destination.dev/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "•••••••••",
"device_name": "Pixel 9"
}'
Response
{
"data": {
"token_type": "Bearer",
"access_token": "eyJ0eXAiOiJKV1Qi...",
"expires_in": 900,
"refresh_token": "rt_9f2c4e...",
"user": { "id": 42, "email": "[email protected]", "account_type": "A" },
"businesses": [
{ "business_id": 7, "business_name": "Executive Transfers" },
{ "business_id": 9, "business_name": "City Chauffeurs" }
]
}
}
2. Choose the acting business
Send the X-Business-Id header on every request. If the user has access to
exactly one business you can omit it; with several available and none selected, the API
returns 422 business_required listing the choices. Call
GET /api/v1/me/businesses any time to refresh the switcher, and
GET /api/v1/me for the signed-in user's profile.
Request
curl https://app.destination.dev/api/v1/dispatch/trips \
-H "Authorization: Bearer eyJ0eXAiOiJKV1Qi..." \
-H "X-Business-Id: 7"
3. Keep the session alive
When a request returns 401 because the access token expired, exchange the
refresh token for a fresh pair. Refresh tokens rotate: each call
invalidates the token you sent and returns a new one, so always store the newest.
Presenting an already-used refresh token is treated as theft and revokes the whole
session — the user must log in again.
Request
curl -X POST https://app.destination.dev/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "rt_9f2c4e..." }'
Log out (revokes the session)
curl -X POST https://app.destination.dev/api/v1/auth/logout \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "rt_9f2c4e..." }'
4. Sign in with Google
For native Google Sign-In, obtain a Google ID token on the device and
exchange it for API tokens. The response matches /auth/login, with an extra
needs_business_setup flag that is true on a brand-new account (prompt the
user to create their transport business before they can dispatch).
Request
curl -X POST https://app.destination.dev/api/v1/auth/google \
-H "Content-Type: application/json" \
-d '{ "id_token": "eyJhbGciOi...", "device_name": "iPhone 16" }'
Build the operator app
With a user token and a selected business you can drive the whole operation:
- Dispatch board —
GET /api/v1/dispatch/tripsfor the day's jobs; assign withPOST /api/v1/trips/{id}/driversand watchGET /api/v1/drivers/locationslive. - Trips — full CRUD:
GET/POST /api/v1/trips,GET/PATCH/DELETE /api/v1/trips/{id}, plusPATCH /api/v1/trips/{id}/driver-statusto move a job along. - Fleet & drivers — full CRUD over
/api/v1/carsand/api/v1/drivers. - Quotes —
GET/POST /api/v1/quotes, price, send, andPOST /api/v1/quotes/{id}/accept/convertto turn a quote into booked trips. - Bookings & customers — list and manage product bookings and your customer directory.
- Invoices & payments — read invoices with line items and payments under
/api/v1/invoices. - Uploads — attach a driver photo, car image or document with
POST /api/v1/uploads, then reference the returned URL. - Settings — read and update the business profile with
GET/PATCH /api/v1/settings/business. - Platform admin — for super-admins, see the Admin API.
Push notifications
Register the device's push token after login so the app can receive alerts, and remove it on logout. These are user-scoped (not business-scoped): a device follows the person across every business they can act on.
POST /api/v1/me/devices— register (idempotent upsert), body{ platform: ios|android|web, device_token, device_name? }.GET /api/v1/me/devices— list the signed-in user's devices.DELETE /api/v1/me/devices— unregister, body{ device_token }.
Register a device
curl -X POST https://app.destination.dev/api/v1/me/devices \
-H "Authorization: Bearer eyJ0eXAiOiJKV1Qi..." \
-H "Content-Type: application/json" \
-d '{ "platform": "ios", "device_token": "fMEp...token", "device_name": "iPhone 16" }'
Passenger invoice payment
For a hosted pay page or the passenger app, the unauthenticated
consumer-pay routes take an invoice's payment_hash as the capability — no
token needed. GET /api/v1/public/invoices/{hash} returns a sanitised invoice,
and POST /api/v1/public/invoices/{hash}/pay creates a Stripe PaymentIntent and
returns a client_secret to confirm the card client-side (the invoice is marked
paid by the Stripe webhook, so re-GET it to observe the new status).
Start a payment
curl -X POST https://app.destination.dev/api/v1/public/invoices/HASH/pay \
-H "Content-Type: application/json"
Build the driver app
Drivers get a lean, purpose-built surface. After they log in and select the business, point the app at the driver endpoints:
- My next job —
GET /api/v1/driver/tripreturns the driver's current assigned trip. - Share location —
POST /api/v1/driver/locationstreams the driver's position (surfaced to dispatch and the passenger's tracking link). - One-tap status —
POST /api/v1/driver/statusfor en route / arrived / on board / completed.
The passenger-facing side reads GET /api/v1/trips/{id}/location for a
"track your ride" view.
Browse every endpoint in the API reference, and read Errors for the shared error envelope.