What You'll Build — and Why Fleetbase
Shipping an on-demand delivery or ride-hailing app from scratch means solving a cluster of hard infrastructure problems at once: broadcasting an order to nearby drivers, letting them accept or decline in real time, streaming their GPS position to the customer, and capturing proof of delivery at the end. Most teams either buy an expensive proprietary platform or spend months building these primitives themselves.
Fleetbase is open-source logistics and fleet operations software that ships every one of those primitives out of the box. Its Fleet-Ops module handles ad hoc order dispatch, driver broadcast, real-time location via SocketCluster, and proof of delivery. The open-source Navigator driver app — available on iOS and Android — handles the driver-side experience without any custom mobile development on your part.
This guide walks through every layer of the stack so you leave with a working end-to-end architecture, not just a list of concepts.
The On-Demand App Architecture at a Glance
The finished system has three moving parts:
- Your React Native customer app — creates orders, shows a live driver pin on a map, and displays delivery confirmation.
- Fleetbase Fleet-Ops — receives the order, broadcasts it to nearby drivers, tracks activity steps, and stores proof of delivery.
- Navigator (driver app) — surfaces the incoming broadcast, lets the driver accept or decline, and guides them through each activity step to completion.
How Fleet-Ops Maps to the Uber Model
| Uber / food-delivery concept | Fleet-Ops equivalent |
|---|---|
| Rider requests a trip | POST /v1/orders with adhoc: true |
| App broadcasts to nearby drivers | Fleet-Ops broadcasts automatically based on adhoc_distance |
| Driver accepts on their phone | Driver taps Accept in Navigator |
| Customer sees driver moving on map | React Native subscribes to the SocketCluster driver channel |
| Trip status updates (en route, arrived, etc.) | Fleet-Ops activity steps defined on the Order Config |
| Delivery confirmation / receipt | GET /v1/orders/:id/proofs |
Prerequisites
- A Fleetbase account — Fleetbase Cloud (fastest to start) or a self-hosted instance. Both expose the same API surface.
- A Fleetbase API secret key — found in Console → Developers.
- A React Native development environment — follow the official React Native setup guide for iOS (Xcode + Watchman) and Android (Android Studio + JDK 17).
- Navigator installed on a test device — iOS App Store or Google Play. See the Navigator App Setup guide for full instructions.
- At least one driver account created in Fleet-Ops → Resources → Drivers.
Step 1 — Configure Fleet-Ops for Ad Hoc Dispatch
Create an Order Config
Every order in Fleet-Ops is governed by an Order Config. The Order Config defines the type of order, its activity steps, and any custom fields. Navigate to Fleet-Ops → Operations → Order Config and click New Config.
Give it a descriptive name — for example, On-Demand Delivery — and note the generated key (e.g., on_demand_delivery). You will pass this key as the type field when creating orders via the API.
Define Activity Steps
Activity definitions live in the Order Config. Inside your new config, add the following activity steps in order:
- En Route to Pickup
- Picked Up
- En Route to Dropoff
- Completed
Each step becomes a discrete status that Fleet-Ops tracks and that your customer UI can reflect. Drivers advance through these steps inside Navigator as they complete each stage of the delivery.
All order configs start with the static activity statuses of "created" → "dispatched" → "started". Created is the initial status, dispatched is triggered programmatically or by a dispatcher, and started is triggered when the driver begins the trip.
Why Activity Definitions Live on the Order Config
Fleetbase supports multiple order types on the same instance — a same-day parcel delivery and a multi-stop freight run can coexist with completely different activity flows. By scoping activity definitions to the Order Config rather than the platform, you can evolve each workflow independently without affecting other order types.
Step 2 — Create an Ad Hoc Order via the Fleetbase API
POST /v1/orders with adhoc: true
An ad hoc order tells Fleet-Ops to broadcast the job to nearby drivers automatically — no manual dispatch or driver pre-assignment required. Here is a minimal request:
POST https://api.fleetbase.io/v1/orders
Authorization: Bearer YOUR_SECRET_KEY
Content-Type: application/json
{
"adhoc": true,
"adhoc_distance": 10000,
"type": "on_demand_delivery",
"payload": {
"pickup": {
"name": "Pickup Location",
"street1": "123 Pickup Street",
"city": "Singapore",
"country": "SG"
},
"dropoff": {
"name": "Dropoff Location",
"street1": "456 Dropoff Avenue",
"city": "Singapore",
"country": "SG"
},
"entities": [
{
"name": "Customer",
"type": "passenger",
"qty": 1
}
]
}
}Setting adhoc_distance to Control the Broadcast Radius
The adhoc_distance field sets the radius — in metres — within which Fleet-Ops will broadcast the order to available drivers. In the example above, 10000 means any driver within 10 km of the pickup point will receive the broadcast. Tune this value to match your service area density: a dense urban zone might use 3 000–5 000 m; a suburban or rural zone might need 15 000–25 000 m.
Required Payload Fields
adhoc— set totrueto enable driver broadcast.adhoc_distance— broadcast radius in metres.type— the key of the Order Config you created in Step 1.payload.pickup— the origin address object.payload.dropoff— the destination address object.payload.entities— at least one item describing what is being delivered.
What Happens Next
Once the order is created, Fleet-Ops immediately calculates which drivers are within the broadcast radius and pushes a notification to their Navigator apps. Your API response includes the order id — store this; you will use it in every subsequent step.
{
"id": "order_xxxxxxxxxxxxxxxx",
"status": "created",
"adhoc": true,
"adhoc_distance": 10000,
"type": "on_demand_delivery",
...
}Step 3 — Driver Acceptance Flow in Navigator
How Navigator Surfaces the Incoming Broadcast
When Fleet-Ops broadcasts an ad hoc order, every eligible driver within the radius receives a push notification and an in-app alert inside Navigator. The alert shows the pickup location, dropoff location, and any relevant order details from the payload.
Accept or Decline — No Manual Dispatch Needed
The driver taps Accept or Decline directly in Navigator. If they accept, Fleet-Ops assigns the order to that driver and advances the status to Dispatched. If they decline — or if no response arrives within the broadcast timeout — Fleet-Ops can re-broadcast to the next available driver. No manual intervention from an operations team is required for this flow.
Linking Navigator to Your Fleetbase Instance
Fleet-Ops generates a shareable deep link that, when opened on a phone with Navigator installed, automatically configures the app to connect to your specific Fleetbase instance — no manual host entry required. Find this link in Fleet-Ops → Resources → Drivers on the driver's profile, or share it during driver onboarding. Full instructions are in the Navigator App Setup documentation.
Step 4 — Subscribe to Real-Time Driver Location in React Native
Connecting to the Fleetbase SocketCluster Instance
Fleetbase uses SocketCluster for real-time events. Install the SocketCluster client in your React Native project:
yarn add socketcluster-clientThen open a connection to your Fleetbase instance:
import { create } from 'socketcluster-client';
const socket = create({
hostname: 'socket.fleetbase.io', // replace with your instance host if self-hosted
secure: true,
port: 443,
path: '/socketcluster/',
});Subscribing to the Accepted Driver Channel
Once a driver accepts an ad hoc order, subscribe to that driver's channel to receive live location updates. The channel name follows the pattern driver.{driver_id}:
async function subscribeToDriver(driverId, onLocationUpdate) {
const channel = socket.subscribe(`driver.${driverId}`);
for await (const data of channel) {
if (data.location) {
onLocationUpdate(data.location);
}
}
}You can obtain the driver_id from the order object returned by GET /v1/orders/:id once the order has been accepted — it will appear in the driver_assigned relationship.
Rendering the Driver's Live Position on a Map
Pass the incoming coordinates to a map component. The example below uses react-native-maps:
import React, { useState, useEffect } from 'react';
import MapView, { Marker } from 'react-native-maps';
export default function TrackingMap({ driverId }) {
const [driverLocation, setDriverLocation] = useState(null);
useEffect(() => {
subscribeToDriver(driverId, (location) => {
setDriverLocation({
latitude: location.coordinates[1],
longitude: location.coordinates[0],
});
});
}, [driverId]);
return (
<MapView style={{ flex: 1 }}>
{driverLocation && (
<Marker coordinate={driverLocation} title="Your Driver" />
)}
</MapView>
);
}Step 5 — Reflect Order Activity Steps in the Customer UI
Listening to the Order Channel via SocketCluster
Rather than polling the orders API endpoint for status changes, subscribe to the order's SocketCluster channel. Fleet-Ops publishes activity updates to the order.{order_id} channel in real time as the driver advances through each step. This gives your customer UI instant feedback without the overhead or latency of repeated HTTP requests.
Using the same SocketCluster connection you opened in Step 4, subscribe to the order channel:
async function subscribeToOrder(orderId, onActivityUpdate) {
const channel = socket.subscribe(`order.${orderId}`);
for await (const data of channel) {
if (data.status) {
onActivityUpdate(data.status);
}
}
}Call this function as soon as you have the order ID from the POST /v1/orders response, so your UI is ready to receive updates the moment the driver acts.
Wiring It Into a React Native Component
Here is a minimal component that subscribes to the order channel and renders the current activity step to the customer:
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function OrderStatusBanner({ orderId }) {
const [label, setLabel] = useState('Locating a driver…');
useEffect(() => {
subscribeToOrder(orderId, (status) => {
setLabel(getCustomerLabel(status));
});
}, [orderId]);
return (
<View style={styles.banner}>
<Text style={styles.text}>{label}</Text>
</View>
);
}
const styles = StyleSheet.create({
banner: { padding: 16, backgroundColor: '#f0f4ff', borderRadius: 8 },
text: { fontSize: 16, fontWeight: '600' },
});Handling Edge Cases
- Driver cancels after accepting — the order channel will publish a status update reflecting the reversion. Listen for a
pendingorsearchingstatus to show the customer a "Finding another driver" message. - No drivers available — if no driver accepts within the broadcast window, the order channel will surface this state. Show a clear message and offer the customer the option to retry or cancel.
- Connection interruption — SocketCluster handles reconnection automatically, but you should also fetch the current order status via
GET /v1/orders/:idon reconnect to resync the UI with any updates missed during the gap.
Step 6 — Capture and Retrieve Proof of Delivery
How Drivers Submit Proof of Delivery in Navigator
When a driver completes the final activity step, Navigator prompts them to capture proof of delivery. Depending on how your Order Config is set up, this can include a photo, a customer signature, and free-text notes. The driver submits this directly from Navigator — no separate integration is required on the driver side.
Fetching Proof via GET /v1/orders/:id/proofs
GET https://api.fleetbase.io/v1/orders/order_xxxxxxxxxxxxxxxx/proofs
Authorization: Bearer YOUR_SECRET_KEYThe response returns an array of proof objects. Each object includes the proof type (photo, signature), a URL to the captured asset, any notes the driver added, and a timestamp.
[
{
"id": "proof_xxxxxxxxxxxxxxxx",
"type": "photo",
"url": "https://fleetbase.io/...",
"notes": "Left at front door",
"created_at": "2025-01-15T14:32:00Z"
}
]Displaying Confirmation to the Customer in React Native
import React, { useEffect, useState } from 'react';
import { View, Image, Text } from 'react-native';
export default function DeliveryConfirmation({ orderId, apiKey }) {
const [proofs, setProofs] = useState([]);
useEffect(() => {
fetch(`https://api.fleetbase.io/v1/orders/${orderId}/proofs`, {
headers: { Authorization: `Bearer ${apiKey}` },
})
.then((r) => r.json())
.then((json) => setProofs(json.data ?? []));
}, [orderId]);
return (
<View>
<Text>Delivery confirmed</Text>
{proofs.map((proof) => (
<View key={proof.id}>
{proof.type === 'photo' && (
<Image source={{ uri: proof.url }} style={{ width: 300, height: 200 }} />
)}
{proof.notes ? <Text>{proof.notes}</Text> : null}
</View>
))}
</View>
);
}Step 7 — (Optional) White-Label Navigator for Your Brand
Forking the Open-Source Navigator App
Navigator is fully open source. The source lives at github.com/fleetbase/navigator-app. Fork the repository, clone it locally, and follow the README to install dependencies and configure your development environment.
Configuring Your Fleetbase Instance URL and Branding
Update the environment configuration to point at your Fleetbase instance host, replace the app name, icons, splash screen, and colour scheme with your brand assets, and adjust any copy that references "Fleetbase Navigator" directly.
Publishing Under Your Own App Store Listing
White-labeled deployments require a commercial license. Once licensed, you can publish the app under your own App Store and Google Play listings. Contact the Fleetbase team via fleetbase.io or the Fleetbase Discord to discuss commercial licensing options.
Architecture Summary and Next Steps
Full Request and Event Flow
Here is the complete sequence from order creation to delivery confirmation:
- Customer app calls
POST /v1/orderswithadhoc: trueandadhoc_distance. - Fleet-Ops broadcasts the order to all drivers within the radius.
- A driver accepts in Navigator; Fleet-Ops assigns the order and advances status to Dispatched.
- Customer app subscribes to the driver's SocketCluster channel (
driver.{driver_id}) and renders a live map pin. - Customer app subscribes to the order's SocketCluster channel (
order.{order_id}) and reflects each activity step update in the UI in real time. - Driver completes the final step and submits proof of delivery in Navigator.
- Customer app calls
GET /v1/orders/:id/proofsand displays the confirmation screen.
Extending with Storefront for Product Catalogs and Multi-Vendor Networks
If your on-demand app needs a product catalog — think food delivery or grocery — Fleetbase's Storefront module adds headless e-commerce on top of Fleet-Ops. For multi-vendor marketplaces (multiple restaurants or merchants in one app), Storefront Networks let you group stores into a single customer-facing experience with shared payment gateways and notification channels.
Adding Webhooks to Push Order Events to Your Own Backend
If you need to react to order events in your own systems — updating a database, sending a custom notification, or triggering a billing event — register a webhook endpoint in the Fleetbase Developer Console. Fleetbase will POST a JSON payload to your endpoint the moment an event fires. Follow the Connect Your First Webhook recipe to get started.
Frequently Asked Questions
Can I use Fleetbase Cloud or do I need to self-host?
Both options expose the same API and the same Fleet-Ops feature set. Fleetbase Cloud is the fastest way to start — no infrastructure to manage. Self-hosting on your own servers is available under the AGPL-3.0 open-source license and is the right choice if you have data residency requirements or want full control over your deployment. See the documentation for self-hosting instructions.
How do I set the broadcast radius for drivers?
Pass the adhoc_distance field in your POST /v1/orders request body. The value is in metres. For example, "adhoc_distance": 5000 broadcasts to drivers within 5 km of the pickup location. You can set a different radius per order, so a premium tier could use a wider radius than a standard tier.
Where do I manage order activity steps?
Activity steps are configured per Order Config at Fleet-Ops → Operations → Order Config. Select the config you want to edit and add, reorder, or remove activity steps from there. Changes apply to all new orders created with that config type — existing in-progress orders are not affected.
Ready to Build?
Fleetbase gives your team the dispatch engine, driver app, real-time location layer, and proof of delivery infrastructure to ship an on-demand delivery experience without rebuilding those primitives from scratch. Start free on Fleetbase Cloud or explore the full API reference at fleetbase.io/docs to begin building today.
