# Nearle Rider — API Reference Generated from a source sweep of `lib/`. Every endpoint the app talks to, with request payloads for all write operations. ## Base hosts | Host | Used for | Notes | |---|---|---| | `jupiter.nearle.app` | all **reads** | env segment from `ApiConstants.mainRoute` (`live`) / `mainDev` (`dev`) | | `queue.workolik.com` | all **writes** (status updates + logs) | hardcoded `live`, DNS pinned to `66.116.225.226`, TLS cert validation bypassed (`lib/providers/deliverylog/deliverylog_provider.dart:20`) | | `msg.lionsms.com` | OTP SMS | | | `maps.googleapis.com` | route distance | | | `sgp1.digitaloceanspaces.com` → `images.nearle.app` | proof / ticket images (Minio SDK, not REST) | | | `66.116.225.226:1883` | MQTT telemetry | | **No auth header on any call.** Every request sends only `Content-Type: application/json` / `Accept: application/json`. Identity is carried as a `userid` field in the query string or body. Endpoint constants live in `lib/views/helpers/constants/apiconstants.dart`. --- ## 1. Auth ### POST `https://jupiter.nearle.app/live/api/v2/users/rider/login` `lib/providers/auth/auth_provider.dart:19` ```json { "contactno": "9876543210", "devicetype": "android", "configid": 1, "deviceid": "", "userfcmtoken": "", "pin": 1234 } ``` `pin` is only included when non-null. Response `details` is persisted to SharedPreferences: `userid`, `shiftid`, `logid`, `riderid`, `partnerid`, `configid`, `logseconds`, `locationid`, `tenantid`, `applocationid`, `userfcmtoken`, `firstname`, `lastname`, `username`, `onduty`, `fuelcharge`, `firstmilecharge`, `starttime`, `endtime`, `deliveryradius` (default 100 m). ### PUT `https://jupiter.nearle.app/live/api/v2/users/update` Set / change MPIN — `lib/providers/auth/auth_provider.dart:186` ```json { "userid": 1242, "pin": 1234 } ``` ### GET `https://jupiter.nearle.app/live/api/v1/platform/getsmsprovider?templatetypeid=1` Fetches `templateid` + SMS `content` template. Cached 1 hour. `lib/controllers/auth.dart:367` ### GET `https://msg.lionsms.com/api/smsapi` `lib/controllers/auth.dart:407` | Param | Value | |---|---| | `key` | `e57f5c9679af26077be1a7eadabb1b2a` | | `route` | `7` | | `sender` | `NEARLE` | | `number` | `+91` | | `templateid` | from `getsmsprovider` | | `sms` | URL-encoded body with OTP substituted for `{#var#}` | The OTP is **generated on-device** and stored in `SharedPreferences('lastOtp')`. --- ## 2. Deliveries — reads (all GET) | Endpoint | Query | Caller | |---|---|---| | `…/{env}/api/v2/deliveries/getdeliveryqueues` | `userid, fromdate, todate, t` (+ optional `orderstatus`) | `lib/providers/delivery/delivery_provider.dart:34` | | `…/{env}/api/v1/deliveries/getdeliveries` | `userid, fromdate, todate, t` | `lib/background/backgroundservice.dart:68` | | `…/{env}/api/v2/deliveries/getdeliveries` | `userid, fromdate, todate, t` | hardcoded in `homepage.dart:1074`, `cartpage.dart:79`, `deliveries.dart:563` | | `…/{env}/api/v3/deliveries/getdeliveries` | `userid, fromdate, todate, t` | picked orders — `delivery_provider.dart:92` | - `fromdate` / `todate` are always **today** in `YYYY-MM-DD`. - `t` is a cache-buster (epoch ms). - Response shape: `{ "code": 200, "status": true, "message": "Success", "details": [ … ] }`. Readers fall back to `data` then the raw body. --- ## 3. Delivery status updates ### PUT `https://queue.workolik.com/live/api/v1/deliveries/updatedelivery` One endpoint, eight payload shapes. All from `lib/controllers/deliveries_controller.dart`. Most variants share this GPS block: `riderslat`, `riderslon`, `raw_latitude`, `raw_longitude`, `velocity_lat`, `velocity_lng`, `speed`, `heading`. #### accepted — `:695` ```json { "deliveryid": 0, "orderheaderid": 0, "orderstatus": "accepted", "acceptedtime": "YYYY-MM-DD HH:MM:SS", "riderslat": "", "riderslon": "", "raw_latitude": "", "raw_longitude": "", "velocity_lat": "", "velocity_lng": "", "speed": "", "heading": "", "deliverylat": "", "deliverylong": "", "actualkms": "", "deliveryamt": 0.0, "notes": "" } ``` #### active (start navigation) — `:1317` Same as accepted, plus: ```json { "orderstatus": "active", "activetime": "YYYY-MM-DD HH:MM:SS", "starttime": "YYYY-MM-DD HH:MM:SS", "activelat": "", "activelon": "" } ``` Aborts if rider coordinates resolve to `0`. #### arrived — `:1429` Same as accepted, with `"orderstatus": "arrived"` and `"arrivaltime": "YYYY-MM-DD HH:MM:SS"`. Geofence-checked against the pickup location before sending. #### picked — `:280` No `raw_*` / velocity block on this one. ```json { "deliveryid": 0, "orderheaderid": 0, "pickuplocationid": 0, "orderstatus": "picked", "pickuptime": "YYYY-MM-DD HH:MM:SS", "riderslat": "", "riderslon": "", "deliverylat": "", "deliverylong": "", "actualkms": "0.00", "deliveryamt": 0.0, "deliverytype": "", "address": "", "city": "", "state": "", "suburb": "", "postcode": "", "notes": "", "pickupimage": "", "proofimage": "" } ``` `actualkms` is computed rider→pickup when not supplied. Geofence-checked. #### delivered — `:1229` ```json { "deliveryid": 0, "orderheaderid": 0, "deliverylocationid": 0, "orderstatus": "delivered", "deliveredtime": "YYYY-MM-DD HH:MM:SS", "deliverytime": "YYYY-MM-DD HH:MM:SS", "smsdelivery": 0, "riderslat": "", "riderslon": "", "raw_latitude": "", "raw_longitude": "", "velocity_lat": "", "velocity_lng": "", "speed": "", "heading": "", "pickuplat": "", "pickuplong": "", "deliverylat": "", "deliverylong": "", "riderkms": "", "ridercharges": 0, "deliveryamt": 0, "collectionamt": 0, "collectedamt": 0, "collectionstatus": "", "ridertime": 0, "notes": "", "wasskipped": false, "bonuspts": 0, "dropimage": "" } ``` Returns `false` without sending if rider **or** drop coordinates are `0` or out of range (`|lat| > 90`, `|lng| > 180`). #### skipped — `:1758` ```json { "deliveryid": 0, "orderheaderid": 0, "orderstatus": "skipped", "skippedtime": "YYYY-MM-DD HH:MM:SS", "riderslat": "", "riderslon": "", "deliverylat": "", "deliverylong": "", "actualkms": "", "deliveryamt": 0.0, "notes": "", "riderkms": "0.00" } ``` `riderkms` is added only when the computed distance is > 0 (Google Directions, falling back to straight-line). #### rejected — `:1477` Status block only, no timestamp: `"orderstatus": "rejected"` plus the shared GPS block, `deliverylat`/`deliverylong`, `actualkms`, `deliveryamt`, `notes`. #### cancelled — `:1813` ```json { "deliveryid": 0, "orderheaderid": 0, "orderstatus": "cancelled", "canceltime": "YYYY-MM-DD HH:MM:SS", "riderslat": "", "riderslon": "", "raw_latitude": "", "raw_longitude": "", "velocity_lat": "", "velocity_lng": "", "speed": "", "heading": "", "deliverylat": "", "deliverylong": "", "riderkms": "0.00", "ridercharges": 0, "deliveryamt": 0.0, "notes": "" } ``` --- ## 4. Delivery log (background heartbeat) ### POST `https://queue.workolik.com/live/api/v2/deliveries/createdeliverylog` **The body is wrapped in an array** — `json.encode([data])` (`lib/providers/deliverylog/deliverylog_provider.dart:73`). ```json [ { "logid": 0, "tenantid": 0, "partnerid": 0, "locationid": 0, "orderheaderid": 0, "deliveryid": 0, "userid": 1242, "orderid": "ORD123", "orderstatus": "active", "logdate": "YYYY-MM-DD HH:MM:SS", "latitude": "", "longitude": "", "raw_latitude": "", "raw_longitude": "", "velocity_lat": "", "velocity_lng": "", "speed": "", "heading": "", "riderkms": 0.0, "logstatus": 0 } ] ``` Base fields come from `_createPayload` (`backgroundservice.dart:236`); GPS, `logdate`, `riderkms` and `logstatus` are merged in `_postDeliveryLog` (`:180`). Posted roughly every 30 s per active delivery. 10 s timeout; failures are queued in SharedPreferences and retried. --- ## 5. Rider log ### GET `…/{env}/api/v1/partners/getriderlog?userid=` Response `details` is cached as `riderlog_template` and reused as the base for every subsequent create-log payload. ### GET `…/{env}/api/v1/partners/getridercount?userid=` ### POST `https://queue.workolik.com/live/api/v2/partners/createriderlog` Periodic on-duty ping — `lib/controllers/riderlog.dart:289`, `lib/background/foreground_service.dart:289` ```json { "logid": 0, "userid": 1242, "partnerid": 0, "shiftid": 0, "logdate": "YYYY-MM-DD HH:MM:SS", "login": "HH:MM:SS", "latitude": "", "longitude": "", "raw_latitude": "", "raw_longitude": "", "velocity_lat": "", "velocity_lng": "", "speed": "", "heading": "", "onduty": 1, "status": "active", "contactno": "", "username": "", "firstname": "", "lastname": "", "tenantid": 0, "locationid": 0, "applocationid": 0, "userfcmtoken": "", "orderid": "" } ``` - Built by spreading the cached `riderlog_template`, then overriding time, GPS and identity fields. - `status` is `"active"` when deliveries are live, otherwise `"idle"`. - `firstname` / `lastname` keys are **removed** when empty; `username` is always sent even if blank. - Interval = `logseconds` from login, forced to **30 s** while deliveries are active. 3 retries with 1 s backoff, then the offline queue (capped at 50). ### PUT `…/{env}/api/v1/partners/updateriderlog` Duty toggle — `lib/controllers/riderlog.dart:520`, model at `lib/Models/riders/riders_models.dart:275` ```json { "userid": 1242, "logstatus": null, "Logout": null, "workhours": null, "shorthours": null, "latitude": "", "longitude": "", "onduty": 1 } ``` Note the capitalized `Logout` key (and `Login` in `RiderLogin.toJson`). --- ## 6. Breaks ### POST `https://queue.workolik.com/live/api/v2/partners/createbreaklog` `lib/controllers/riderlog.dart:925` ```json { "breakid": 427, "logid": 0, "breakdate": "YYYY-MM-DD HH:MM:SS", "userid": 1242, "partnerid": 0, "shiftid": 0, "breakstart": "HH:MM:SS", "breakend": "", "breakhours": 0.0, "latitude": "", "longitude": "" } ``` `breakid` is a **client-generated random 3-digit** value (100–999), replaced by the server id when one comes back. Also emitted by the auto-shift-end flow at `backgroundservice.dart:765`. ### PUT `https://queue.workolik.com/live/api/v2/partners/updatebreaklog` `lib/controllers/riderlog.dart:196` Same shape, with `breakend` filled and `breakhours` as fractional hours (`duration.inSeconds / 3600`). --- ## 7. Stats & rewards (GET) | Endpoint | Source | |---|---| | `…/live/api/v2/partners/getdeliverystats?userid=` | `lib/providers/summary/summary.dart:10` | | `…/live/api/v1/partners/getriderweeklykms?userid=` | `lib/views/Dashboard/summary/summary.dart:318` | | `…/live/api/v1/utils/getuserbonussummary/?userid=` | `lib/controllers/rewards_controller.dart:16` | --- ## 8. Support tickets ### GET `…/live/api/v1/partners/getridersupport/?userid=` ### POST `…/live/api/v1/partners/createridersupport/` `lib/controllers/support_ticket.dart:186` ```json { "userid": 1242, "category": "", "priority": "", "subject": "", "issue": "", "image": "https://images.nearle.app/support/ticket-1234-1242.jpg" } ``` Images are uploaded directly to DigitalOcean Spaces with the Minio SDK (bucket `nearle`, folder `support`, region `sgp1`) — not through the API. The returned CDN URL is what goes in `image`. --- ## 9. External services - **GET** `https://maps.googleapis.com/maps/api/directions/json?origin=&destination=&key=&units=metric&mode=driving` — road distance for km calculation, 5 s timeout (`deliveries_controller.dart:1115`) - `launchUrl` only (no HTTP from the app): - `https://www.google.com/maps/dir/?api=1&destination=,` (`nav.dart:444`) - `https://nearle.in/terms`, `https://nearle.in/privacy`, `https://nearle.in/faq` - `https://play.google.com/store/apps/details?id=com.nearle.partner` - `https://apps.apple.com/us/app/nearle/id1596895375ls=1` ### MQTT `66.116.225.226:1883`, user `admin` (`lib/views/helpers/constants/mqtt_constants.dart`) | Topic | Payload | |---|---| | `nearle/riders/{riderId}/status` | `Online` / `Offline` / `Idle` / `Active` | | `nearle/riders/{riderId}/profile` | `userid, username, firstname, lastname, contactno, userfcmtoken, app_version, device_info` | | `nearle/riders/{riderId}/location` | `userid, orderid, lat, lng, raw_lat, raw_lng, speed, heading, velocity_lat, velocity_lng, timestamp` | | `nearle/riders/{riderId}/telemetry` | battery, charging, speed, connection, accuracy | | `nearle/riders/{riderId}/logs` | `rider_periodic_log`, `delivery_picked`, `critical_battery`, alerts | --- ## Known issues found during the sweep 1. **`lib/controllers/riderkm.dart:11` builds a broken URL.** `baseUrl` is already `…/v1/partners/getriderweeklykms`, and the code appends `/getriderweeklykms?userid=` → `…/getriderweeklykms/getriderweeklykms?userid=`. The summary *view* calls it correctly, so this controller path is likely dead or silently failing. 2. **`lib/controllers/support_ticket.dart:66` hardcodes `userId = 1242`** in `fetchTickets()` — every rider sees user 1242's ticket list. 3. **Secrets shipped in the APK**: DO Spaces access key + secret (`support_ticket.dart`, `deliveries_controller.dart`), LionSMS API key, MQTT `admin` / `Package@321#`, Google Maps key. 4. **OTP is generated and verified on-device**, stored in `SharedPreferences('lastOtp')` — trivially bypassable. 5. **TLS verification disabled** for `queue.workolik.com` plus a hardcoded IP pin (`66.116.225.226`). If that VPS IP changes, every write endpoint breaks at once. 6. **`backgroundservice.dart:845` POSTs to `updateriderlog`** while every other caller PUTs it. If the server is method-strict, auto-shift-end never marks the rider offline. 7. `updateDeliveryDev`, `createRiderLogDev`, `createBreakRiderLogDev`, `updateBreakRiderLogDev` and `createDeliveryLogDev` all point at **live** — there is no working dev environment for writes. 8. `lib/providers/support/support_ticket.dart` is a dead duplicate of the controller and references an `…/partners/uploadimage/` endpoint nothing else uses.