From 86ae2ab41ec2abd7d91dfc10634dc2650d5aaab7 Mon Sep 17 00:00:00 2001 From: dharaneesh-r Date: Tue, 8 Sep 2026 13:23:42 +0530 Subject: [PATCH] updates on the customer app api --- docs/customer-app-api-crisp.md | 291 +++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 docs/customer-app-api-crisp.md diff --git a/docs/customer-app-api-crisp.md b/docs/customer-app-api-crisp.md new file mode 100644 index 0000000..86335a6 --- /dev/null +++ b/docs/customer-app-api-crisp.md @@ -0,0 +1,291 @@ +# Doormile Customer App (`doormile_cx`) API — Quick Reference + +> **Base URL:** `https://api.doormile.com/api/v1` +> **Namespace:** `/customer/*` | **Auth Role:** `9` (Customer) | **Data Envelope:** `{ "success": true, "data": { ... } }` + +--- + +## 1. Global Conventions + +| Aspect | Specification | Details / Rules | +|---|---|---| +| **Naming** | `camelCase` | All request & response JSON fields use camelCase. | +| **Timestamps** | Epoch milliseconds (UTC, `int64`) | Parse directly with `DateTime.fromMillisecondsSinceEpoch(ts)`. | +| **Identifiers** | Sequence-backed Feistel permutation | **Booking Reference:** `DM-482913`
**Tracking Number:** `DMX10482913` | +| **Headers** | `Authorization: Bearer `
`X-Client: doormile-cx/+`
`X-Platform: android | ios`
`Idempotency-Key: ` | • Required on all routes except pre-auth & catalogue.
• Client telemetry logged on every request.
• Idempotency supported on booking creation & OTP verification. | +| **Token Lifetime** | Access: `1 hour` \| Refresh: `60 days` | Refresh tokens rotate on every use. Replaying a revoked token revokes the entire chain. | + +--- + +## 2. Complete Endpoint Reference (28 Routes) + +### 🔐 Authentication (Pre-Auth & Session) +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `POST` | `/customer/auth/otp/request` | ❌ | Request OTP via SMS/Email (returns uniform success regardless of account existence). | +| `POST` | `/customer/auth/otp/verify` | ❌ | Verify OTP, returns JWT tokens & customer profile. | +| `POST` | `/customer/auth/signup` | ❌ | Register new customer or treat existing phone as sign-in. | +| `POST` | `/customer/auth/refresh` | ❌ | Rotate refresh token to issue a new access token. | +| `POST` | `/customer/auth/logout` | ✅ | Revoke session (omit `refreshToken` to sign out everywhere). | +| `GET` | `/customer/auth/me` | ✅ | Fetch currently authenticated customer identity. | + +### 📦 Serviceability & Catalogue +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `GET` | `/customer/serviceability/states` | ❌ | List serviceable states (`ETag` / 304 supported). | +| `GET` | `/customer/serviceability/states/:code/districts` | ❌ | List serviceable districts in state (`ETag` / 304). | +| `GET` | `/customer/pickup-slots` | ❌ | List today's & tomorrow's time slots with zone capacity (`ETag` / 304). | +| `GET` | `/customer/config/booking-limits` | ❌ | Get booking limits (`maxDestinations`, `maxPackages`, `maxCodAmount`). | + +### 📍 Places & Geocoding +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `GET` | `/customer/places/search?q=:query&lat=:lat&lng=:lng` | ✅ | Place search / autocomplete (empty query returns recent/saved). | +| `GET` | `/customer/places/reverse-geocode?lat=:lat&lng=:lng` | ✅ | Reverse geocode coordinates to structured address. | + +### 💰 Fare Estimation +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `POST` | `/customer/fare/estimate` | ✅ | Compute estimated fare band (`minRupees`–`maxRupees`) & route distance. | + +### 🚚 Bookings & Tracking +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `POST` | `/customer/bookings` | ✅ | Create multi-destination pickup booking (`Idempotency-Key` supported). | +| `GET` | `/customer/bookings?limit=20&cursor=:cursor&status=active` | ✅ | Keyset paginated customer bookings list. | +| `GET` | `/customer/bookings/:reference` | ✅ | Get full booking detail & live tracking snapshot (`ETag` supported). | +| `POST` | `/customer/bookings/:reference/cancel` | ✅ | Cancel booking (allowed strictly before rider status `arrived`). | +| `PATCH` | `/customer/bookings/:reference/destinations/:index` | ✅ | Update recipient details on a pending destination stop. | +| `GET` | `/customer/orders/:trackingId` | ✅ | Look up single order/parcel status by tracking number. | + +### 👤 Profile & Saved Locations +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `GET` | `/customer/profile` | ✅ | Get customer profile details. | +| `PUT` | `/customer/profile` | ✅ | Update customer name/email. | +| `GET` | `/customer/locations` | ✅ | List up to 10 saved delivery/pickup addresses. | +| `POST` | `/customer/locations` | ✅ | Save a new location. | +| `PUT` | `/customer/locations/:id` | ✅ | Update an existing saved location. | +| `DELETE` | `/customer/locations/:id` | ✅ | Delete a saved location. | + +### 🔔 Devices & Push Notifications +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `POST` | `/customer/devices` | ✅ | Register FCM device token for milestone push updates. | +| `DELETE` | `/customer/devices/:token` | ✅ | Unregister device token on logout. | + +### 🛠️ Ops QA Testing (Non-Production Only) +| Method | Endpoint | Auth | Description | +|---|---|:---:|---| +| `POST` | `/customer/ops/bookings/:reference/stage` | ✅ | Double-gated test helper to walk a booking through stages. | + +--- + +## 3. Core Request & Response Payloads + +### 1) OTP Verification (`POST /customer/auth/otp/verify`) +```json +// Request +{ + "identifier": "+919876543210", + "otp": "1234" +} + +// Response (200 OK) +{ + "success": true, + "data": { + "accessToken": "eyJhbGciOi...", + "refreshToken": "d8f1e2a3...", + "expiresIn": 3600, + "customer": { + "id": 1042, + "name": "Alex Kumar", + "phone": "+919876543210", + "email": "alex@example.com" + } + } +} +``` + +### 2) Fare Estimate (`POST /customer/fare/estimate`) +```json +// Request +{ + "pickup": { + "latitude": 13.0827, + "longitude": 80.2707, + "stateCode": "TN", + "districtCode": "CHN" + }, + "destinations": [ + { + "stateCode": "TN", + "districtCode": "CHN", + "packages": [{ "weightKg": 2.5 }] + }, + { + "stateCode": "KA", + "districtCode": "BLR", + "packages": [{ "weightKg": 1.0 }] + } + ] +} + +// Response (200 OK) +{ + "success": true, + "data": { + "minRupees": 240, + "maxRupees": 310, + "routeKm": 348.5, + "breakdown": { + "baseFare": 180, + "additionalStopsUplift": 60, + "estimatedTax": 0 + } + } +} +``` + +### 3) Booking Creation (`POST /customer/bookings`) +```json +// Request +{ + "slotId": "slot_20260908_t2", + "pickup": { + "title": "Home", + "sub": "Flat 4B, Green Towers, Anna Nagar", + "latitude": 13.0827, + "longitude": 80.2707, + "contactName": "Alex Kumar", + "contactPhone": "+919876543210" + }, + "destinations": [ + { + "recipientName": "Priya S", + "recipientPhone": "+919840123456", + "building": "12/A", + "street": "MG Road", + "landmark": "Near Metro", + "districtCode": "CHN", + "stateCode": "TN", + "latitude": 13.0850, + "longitude": 80.2100, + "packageCount": 1, + "codAmount": 450 + } + ], + "remarks": "Handle with care" +} + +// Response (201 Created) +{ + "success": true, + "data": { + "reference": "DM-482913", + "stage": "booked", + "status": "active", + "cancellable": true, + "createdAt": 1788775499000, + "slotId": "slot_20260908_t2", + "pickup": { + "title": "Home", + "sub": "Flat 4B, Green Towers, Anna Nagar", + "latitude": 13.0827, + "longitude": 80.2707 + }, + "destinations": [ + { + "index": 0, + "stateName": "Tamil Nadu", + "districtName": "Chennai", + "packageCount": 1, + "codAmount": 450, + "trackingId": null, + "stage": null + } + ] + } +} +``` + +--- + +## 4. Lifecycle & Stage Machine + +### Stage Progression Sequence +``` +[ booked ] ──► [ assigned ] ──► [ arrived ] ──► [ picked_up ] ──► [ order_created ] + │ (cancel window closes) + ▼ + [ delivered ] ◄── [ out_for_delivery ] ◄── [ in_transit ] +``` + +### Stage Vocabulary +| Stage Key | Meaning / Trigger | Cancellable? | Scope | +|---|---|:---:|---| +| `booked` | Order submitted by customer | ✅ Yes | Booking | +| `assigned` | Rider assigned to visit | ✅ Yes | Booking | +| `on_the_way` | Rider accepted assignment | ✅ Yes | Booking | +| `arrived` | Rider arrived at pickup point (**cancellation cutoff**) | ❌ No | Booking | +| `picked_up` | Parcels collected and weighed | ❌ No | Booking | +| `order_created` | Tracking IDs generated per destination | ❌ No | Per Destination | +| `in_transit` | Parcels sorted / inwarded at hub | ❌ No | Per Destination | +| `out_for_delivery` | Dispatched with delivery agent | ❌ No | Per Destination | +| `delivered` | Successfully delivered to recipient | ❌ No | Per Destination | +| `cancelled` | Cancelled by customer or ops before arrival | — | Terminal | + +> [!IMPORTANT] +> **Rollup Rule:** The overall booking stage reflects the **slowest order**. If Destination 1 is `delivered` but Destination 2 is `in_transit`, the booking rollup remains `in_transit`. + +--- + +## 5. Cross-App Impact & Compatibility + +| Client / Component | Observable Change | Impact / Handling | +|---|---|---| +| **Miler App (Flutter)** | Multi-stop collection | Post-collection returns multiple stops sharing one `bookingid`. Keys must resolve by `consignmentid`. | +| **Admin Console** | Booking numbers & Search | Display format is now `DM-482913`. Searches match exact substring. | +| **Hub Console** | Tracking IDs & Inbound | Tracking numbers are now `DMX10482913`. | +| **Safety Mitigation** | `maxDestinations` Gate | Configured in DB (`customerbookinglimits.maxdestinations = 1`) to keep fanout single-destination until mobile updates deploy. | + +--- + +## 6. Standard Error Codes & Envelopes + +All errors return JSON in standard format: +```json +{ + "success": false, + "error": { + "code": "SLOT_UNAVAILABLE", + "message": "That pickup time has passed — pick a new slot" + } +} +``` + +| HTTP Status | Error Code (`error.code`) | Meaning / Recommended Client Action | +|---|---|---| +| `400` | `INVALID_INPUT` / `SLOT_EXPIRED` | Validation error or expired slot date. Prompt user to re-select. | +| `401` | `UNAUTHORIZED` | Token missing or expired. Redirect to OTP login / refresh session. | +| `403` | `FORBIDDEN` | Caller lacks role 9 customer access. | +| `404` | `NOT_FOUND` | Booking reference or tracking ID does not exist. | +| `409` | `SLOT_CAPACITY_FULL` | Slot filled up during checkout race. Prompt user to choose another time. | +| `409` | `BOOKING_NOT_CANCELLABLE` | Customer attempted cancel after rider `arrived`. Show un-cancellable alert. | +| `422` | `UNSERVICEABLE_PINCODE` | Location is outside active operating zones. | +| `429` | `RATE_LIMITED` | OTP requests exceeded limit (max 5/hour). Show countdown timer. | +| `500` | `INTERNAL_ERROR` | Generic server error (`X-Request-Id` logged). | + +--- + +## 7. Environment Variables & Deploy Flags + +```bash +GEOCODER_URL=https://nominatim.openstreetmap.org # Geocoding proxy +GEOCODER_EMAIL=ops@doormile.com # Nominatim contact policy +MILER_CALL_PROXY= # Set to proxy number in production (protects rider PII) +CX_STAGING_OTP=1234 # Fixed OTP for staging QA (disabled if ENV=production) +CX_ID_SCRAMBLE_KEY= # Optional custom key for Feistel sequence permutation +CX_ALLOW_STAGE_OVERRIDE=false # Double-gated QA stage override tool +```