An app like Porter is three products wearing one logo, and the one that decides whether the business survives its first month is the one nobody screenshots: the operations panel where carriers get verified, disputes get settled and money goes out. Founders budget for the shipper app, half-budget for the driver app, and discover the ops panel when the first payout is wrong. This guide is written in build order so that does not happen to you.
It is for a founder or logistics operator who wants an on-demand goods transport platform built: a shipper posts a load, a nearby carrier with the right vehicle takes it, everyone gets paid. Porter made that shape familiar for intra-city goods in India, so it appears here as a description of the category, not a spec, and none of its pricing or internals is quoted.
The first-hand reference is XpressFly, a logistics marketplace we built that works the way Porter does with one deliberate difference: carriers bid on each shipment and the shipper picks, rather than the platform quoting a fixed rate. The portfolio page says what that product is; this post goes underneath it, decision by decision, in build order.
A delivery app like Porter is three products, and the ops panel is the expensive one
Say "an app like Porter" to an estimator and they picture one app store listing. What they should picture is three codebases with three different users and one shared backend.
- The shipper app. Post a load: pickup, drop, what it is, how big, when. See a price or see offers. Confirm. Track. Pay. Rate.
- The driver or carrier app. A different product for a different person, used one-handed in a moving cab, on a mid-range Android phone, in patchy coverage. Find work nearby, accept or bid, navigate, prove delivery, see earnings.
- The operations panel. A web application your own staff live in. Who is allowed on the platform and in what state. Which jobs are stuck. Which delivery is disputed and what the evidence says. What is owed to whom, and the button that pays it.
The ops panel is where the effort hides because it is where the exceptions live. The happy path is perhaps a third of the code. The rest is a carrier's documents expiring mid-week, a shipper saying the parcel arrived damaged, a driver's cash not matching, a payout bouncing. Each needs a screen, a state and a person, and none of them are in the founder's wireframes.
Three things to put in the ops panel from release one: carrier verification as a state machine (applied, in review, verified, suspended, rejected) with an audit trail; a dispute queue that shows the job, the proof of delivery and the tracking trail on one screen; and a payout ledger an accountant could read without a developer explaining it. On XpressFly, carrier payouts, accounting and reporting all live in the ops panel, and that placement is the point: money leaves the business from a screen your team controls, not from a background job.
Fixed pricing with auto-assignment, or carrier bidding: the decision that is hard to reverse
Every other design choice bends around this one, and it is painful to change once carriers have habits.
Fixed platform pricing with auto-assignment is the model most people picture. The shipper enters pickup and drop, sees a number, taps once, and the platform picks the carrier. It is the better shipper experience by a distance. What it costs you: a pricing engine you own and have to get right across distance, vehicle class, load type, waiting time, tolls and demand, plus a matching service that assigns the job well enough that carriers do not decline it. Both need data you do not have at launch, and a wrong price fails in one of two directions: shippers leave, or carriers refuse the job.
Carrier bidding is what XpressFly does: the shipper posts the shipment, verified carriers see it and put in a price, the shipper chooses. You skip the pricing engine on day one and the market finds the rate. The engineering cost is a bidding subsystem instead: bids with expiry, notifications to carriers in range, a comparison screen, rules for when nobody bids. The liquidity cost is the larger one. Bidding needs enough carriers online and looking for the auction to produce a sensible price in a sensible time. With four carriers in the city, a shipper posts a load and waits, and the wait is the product they remember.
The honest split: bidding suits heterogeneous loads and irregular runs where a fair price genuinely varies. Fixed pricing suits short, repeated, commoditised runs where speed of booking is the product. Bidding also yields a price observation per route, vehicle class and time of day, so a fixed-price engine built later starts from evidence. Whichever you choose, record where a job's price came from (platform quote, accepted bid, negotiated by ops) as a field, so the other model can exist later.
The driver app, built for one hand in a moving cab
Onboarding and identity verification
A shipper is handing goods to a stranger, so identity is the first real feature, not a settings screen. On XpressFly, carriers verify through Aadhaar integration and then a manual signup review in the ops panel before the account can take work. The two steps do different jobs: the automated check confirms a document is real and belongs to the applicant; a person catches what documents cannot, such as a vehicle that does not match its registration, a phone number shared across three accounts, or an applicant rejected before under a different name.
Collect identity, driving licence, vehicle registration and insurance, a photo of the vehicle with its plate visible, and bank details for payout. Store documents with expiry dates and a scheduled check, because a licence expiring on Tuesday is a carrier who must not be assigned on Wednesday. Make the journey one sitting on a phone, resumable; every extra required field loses the busy drivers with work elsewhere.
One-handed use
Big targets, high contrast, no two-finger gestures.The core loop is a handful of screens: available, job offer, en route to pickup, loaded, en route to drop, delivered, each with one primary action filling the bottom of the screen. Sound and vibration for a new offer, because the phone is on the dashboard. Test on a cheap Android device in bright sun with battery saver on, because that is the phone.
Job discovery by proximity
A driver's home screen is a list, not a map: jobs they are eligible for (vehicle class matches, capacity fits, documents valid), sorted by distance to pickup, showing where it starts, where it ends, and what it pays or what others have bid. Under bidding, the bid action lives on the job card and takes two taps: a suggested price and a confirm.
Navigation hand-off
Do not build turn-by-turn navigation. Deep-link to the maps app the driver already uses, and come back to your app for the state change. Your app owns the state and the position trail, not the route guidance.
Proof of delivery
Photo of the goods at drop, receiver name, and a signature or a one-time code the shipper shares with the receiver. Timestamp and GPS captured at the moment of the photo, not when the upload finishes. The upload has to survive no coverage: queue it locally, mark the job delivered on the device, sync when the network returns, and show ops "reported, proof pending". This one screen settles most disputes.
Earnings
Drivers check earnings more than any other screen. Show today, this week, and a per-job line: what it paid, what the platform kept, cash collected on the shipper's behalf, when the balance pays out. If this number does not match the bank account you lose the driver, so the earnings screen reads from the same ledger the payout does.
Dispatch and matching: a ranked list beats a clever optimiser at launch
At launch, matching is a filter followed by a sort. Anything cleverer is months spent on a subsystem with no data to optimise against.
The filter removes everyone who cannot do the job: wrong vehicle class, insufficient capacity, documents expired, on another job, offline, outside the radius. A plain weighted score sorts the rest: distance to pickup first, then acceptance rate, rating, and how recently they completed a job. Under fixed pricing, offer the job to the top of the list with a short window and cascade down on decline or timeout. Under bidding, notify the top of the list and let bids come in. Either way, log every offer, decline and timeout, because that log is the training data for anything smarter later. And give ops a manual reassign from day one: a dispatcher who can move a job or pin a carrier to a shipper solves more problems in the first six months than any routing algorithm.
Live tracking, and what to store
Tracking demos beautifully and behaves badly in the field: phones throttle background location, coverage drops in the industrial estates you operate in, and a pin frozen for four minutes produces a support call. So the driver app buffers positions locally and flushes them in batches, the shipper sees the last known position with an honest timestamp rather than a stale pin, and ops has a button to call the driver.
Store the whole trail per job (timestamp, position, accuracy, speed, battery), not just the current point: it proves waiting time, settles "the driver never came" disputes, and later tells you what a route costs a carrier in time. Expire it after the dispute window and keep the summary (distance, duration, waits) on the job.
Pricing engine anatomy, if you choose fixed pricing
The engine is a product in its own right. Its inputs, in the order they usually enter the formula:
- Distance and duration. From the maps provider's route, not a straight line. Duration matters as much as distance in a congested city; estimate both at booking and measure both at completion.
- Vehicle class. A base fare and a per-kilometre rate per class, because a two-wheeler and a light truck are different businesses with different costs.
- Load type. Fragile, heavy, needs a helper, needs two people at each end. Surcharges with rules, each visible to the shipper before confirming.
- Waiting time. Free minutes at pickup and drop, then a per-minute rate, measured from the tracking trail, which is why the trail has to be stored.
- Tolls and parking. Estimated from the route and added, or logged by the driver with a photo and reimbursed. The second is more accurate and more disputed.
- Demand. A multiplier when more loads are open than carriers online in a zone. Introduce it late, cap it, and show it. Uncapped surge in a goods market sends shippers back to their phone broker.
Two engineering rules. The engine returns a breakdown, not a number, stored on the job at booking so a later rate change cannot alter a completed job's price. And every rate lives in configuration ops can edit per city and vehicle class without a deploy, with an effective-from date, because you will change these weekly in the first quarter.
Payments and payouts: collect, hold, pay carriers, reconcile
Collecting from the shipper is the easy half: card, UPI or wallet at booking or at delivery, and the payment provider handles the instrument. The other half is a ledger.
The design we use for marketplace money at the studio is on Nestlet, an in-house marketplace for short-term residential leases that is still in build. It uses Stripe Connect with separate charges and transfers: the platform charges the payer, the funds are held on the platform balance, and a transfer to the other party is a distinct later step, released only once the contract is finalised. For goods transport: the shipper's payment is charged and held, the job reaching a delivered state after a short dispute window is the gate, and the transfer to the carrier is a separate operation that reads that state.
On XpressFly, paying truckers happens from the admin panel, and that is the right place for it in a first release. A payout screen shows, per carrier, completed jobs since the last settlement, gross amount, commission, adjustments (a reimbursed toll, a penalty, cash to net off) and net owed; an operator confirms and the system records the batch. Automate the calculation from day one and the execution only once the calculation has been right for a few cycles, because a wrong automated payout has no undo.
Cash on delivery is the reality, so model it
In Indian logistics a large share of shipments are still paid in cash at delivery, and often the driver collects it, which makes the driver a cash-handling node in your ledger. Each collection is a liability the driver owes, netted off against what the platform owes them, on a settlement cycle short enough that no driver carries more cash than they could stand to lose. Give drivers a way to deposit and record cash, show the running balance on the earnings screen, and cap outstanding cash before a driver stops receiving cash jobs. It is a reconciliation feature, not a payments feature.
Reconciliation is the daily job: what the payment provider says it collected, what the ledger says shippers owe, what drivers say they collected in cash, what the payout batches say went out. When the four disagree, the ops panel has to show where, by job. Build that report before the first live transaction.
The stack is unremarkable, and the first-release feature table
XpressFly runs Flutter for both mobile apps, a Node and MongoDB backend on AWS, Google Maps for geocoding, routing and distance, an SMS gateway for one-time passwords and job notifications, and Firebase cloud storage for documents and proof-of-delivery photos. Nothing in that list is exotic, and that is the recommendation: pick the mainstream option in each slot and spend the argument budget elsewhere.
The choice matters less than the ops design because every part of this stack could be swapped for its nearest competitor without changing a screen, a state or a reconciliation rule. What cannot be swapped later is a job model with no "delivered, proof pending" state, a carrier model with no "suspended", or a ledger that stores net amounts without the breakdown. Those are made in the schema, not the framework, and they are what produces a rewrite. The one place the framework bites is the driver app: background location, push and offline queuing differ per platform, so whoever does the mobile app development should have shipped background location on Android before.
| Feature | Shipper app | Driver app | Ops panel | First release |
|---|---|---|---|---|
| Carrier onboarding and identity verification | No | Document capture, status view | Review queue, state machine, expiry checks | Yes |
| Post a load (pickup, drop, size, timing, load type) | Yes | No | Create on behalf of a shipper | Yes |
| Fixed price quote | Shows breakdown | Shows payout | Rate configuration per city and class | Only if fixed pricing |
| Bidding | Compare and accept offers | Bid on the job card | See bids, override | Only if bidding |
| Matching and dispatch | No | Ranked job list, offer window | Manual assign and reassign | Yes, ranked list only |
| Live tracking | Last known position and timestamp | Background location, offline buffer | Trail per job, call driver | Yes |
| Proof of delivery | View | Photo, receiver, code, offline queue | View in the dispute screen | Yes |
| Payments | Card, UPI, wallet, cash at delivery | Record cash collected | Ledger, reconciliation report | Yes |
| Carrier payouts | No | Earnings and settlement history | Payout batches, adjustments, confirm | Yes, operator-confirmed |
| Disputes | Raise with reason | Respond | Queue with evidence on one screen | Yes |
| Scheduled, recurring, multi-stop and part-load | Later | Later | Later | No |
| Demand-based pricing and a matching optimiser | No | No | Later | No |
What a Porter like app costs, how long it takes, and when not to build one
It is a two-sided marketplace, so the published marketplace band of $15,000 to $150,000+ applies, and a sensible first release sits in the lower half of it. At the studio's published blended rate of about $20 per hour for a senior offshore team, the arithmetic is mostly scope: which pricing model, how much of the payout flow is automated, and whether every "Later" in the table becomes a "Yes".
An illustration, not a quote, reasoned from team-weeks. Take the first-release column above: one city, one or two vehicle classes, bidding rather than a pricing engine, operator-confirmed payouts. A team of four (one backend engineer, two mobile engineers on the Flutter apps, one person across product, design and QA) for roughly 14 to 18 weeks is 56 to 72 person-weeks. At about $20 per hour and 40-hour weeks, that is $800 per person-week, so roughly $45,000 to $58,000. A fixed-price engine or end-to-end automated payouts grows both the figure and the calendar; a single vehicle class and manual dispatch shrinks both. The calendar also has a floor: carrier recruitment, app store review, identity and payment provider onboarding each take their own weeks, so start them in week one.
A Scoping Sprint ($2,300 fixed, two weeks) turns this into a real number: it ends with a clickable prototype, a technical plan and a fixed quote, credited in full if we go on to build.
When not to build: services like Porter and white-label options exist
If you searched for services like Porter or a transport app like Porter, there is a fair chance the right answer is to use one rather than build one. Aggregator platforms already operate in most large Indian cities, and white-label logistics platforms will put your brand on a shipper app, a driver app and a dispatch panel for a subscription, with pricing, tracking and payouts already built.
Marketplaces fail on supply, not software. If you do not have carriers, an app that works perfectly has nothing happening on it. A shipper with volume should list loads on the existing platforms first and learn what carriers charge. A fleet owner with trucks and drivers already should try a white-label platform first; a quarter on it shows whether customers will book through an app at all.
Build your own when one of these is true and you can show it: you have carrier supply the aggregators do not, such as a regional fleet network or a vehicle class they do not serve; the pricing model you need (bidding, contracted rates, part-load) is one the white-label products do not support; or the workflow is specific to your industry, such as construction materials or cold chain, and the generic products fight it. That is on-demand app development in the specific sense: the value is in the dispatch and settlement logic, not the app store listing. It sits inside logistics software development, which is work we have shipped.
Building a goods transport platform and trying to decide between bidding and fixed pricing before the first carrier signs up? A Scoping Sprint ($2,300, two weeks) ends with the pricing model, the job and carrier state machines and the payout ledger designed for your case, a prototype, and a fixed quote. Or just start a conversation.


