Files
doormile_backend/docs/customer-app-api-crisp.md

11 KiB
Raw Blame History

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 <accessToken>
X-Client: doormile-cx/<version>+<build>
`X-Platform: android
ios<br>Idempotency-Key: `
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)

// 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)

// 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)

// 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:

{
  "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

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