Balora

Balora App API

Mobile developer guide · best-scenario test flow

Phase 1 — Mobile (USER) happy path

Use this page to understand the recommended call order, request shapes, and what is live vs stubbed. Base path:

Envelope: { success, data, message? } Errors: { success:false, code, message, errors? } Auth header: Bearer <token> Locale: Accept-Language: en | ar
Dev OTP: when Otp:UseStaticCode=true (Development), verify with code 1234. Production uses real SMS — enter the code you receive.

Best scenario (recommended order)

  1. Request OTP live POST /api/app/auth/otp/request → save challengeId
  2. Verify OTP live POST /api/app/auth/otp/verify → save data.token + data.refreshToken (new phone → isFirst: true)
  3. Optional signup complete live POST /api/app/auth/signup/complete with Bearer — set fullName (skippable)
  4. Profile + address live GET /api/app/profile then POST /api/app/profile/addresses
  5. Payment method live POST /api/app/profile/payment-methods → save id for booking
  6. Compare ride offers live POST /api/app/rides/compare → pick an offerId before it expires
  7. Book ride live POST /api/app/rides with offerId + paymentMethodRefId
  8. Get / cancel / rate live GET /rides/{id} · cancel while Processing · rate only after Completed
  9. Public content live GET /api/app/ads?screen=Home · GET /api/app/pages · GET /api/app/pages/about-us
  10. Refresh / logout live POST /api/app/auth/refresh then POST /api/app/auth/logout (last)
Do not cancel and rate the same ride in one pass — cancel needs a cancellable status; rating needs Completed.

Live try panel

Runs against this host. Token is kept in sessionStorage only.

No session yet.
Ready.

Endpoint map (mobile)

Area Method / path Status Notes
Auth POST /api/app/auth/otp/request live { phoneCode, phone, purpose: "login" }
Auth POST /api/app/auth/otp/verify live Returns flat token (not accessToken)
Auth POST /api/app/auth/signup/complete live Bearer USER · optional
Auth POST /api/app/auth/refresh live { refreshToken } → TokenPair
Auth POST /api/app/auth/logout live Bearer · revokes refresh tokens
Profile GET/PATCH /api/app/profile live + addresses, payment-methods, devices, prefs
Rides POST /api/app/rides/compare live Riyadh sample coords work well
Rides POST /api/app/rides live { offerId, paymentMethodRefId }
Rides GET/cancel/rating /api/app/rides/{id} live Status rules apply
Eats discover/order GET restaurants · POST orders… stub 501 Phase 1: not implemented yet
Eats GET /api/app/eats/orders/{id} partial Works when an order exists
Promo POST /api/app/promo/validate live Try code BALORA10 / EATS15
Loyalty GET /api/app/loyalty/balance live Bearer required
Support POST /api/app/issues live Link to ride/order id
Contact POST /api/contact-us live Public · no auth
Content GET /api/app/ads · /api/app/pages live Public
Geo GET /api/app/geo/autocomplete|reverse stub 501 Until Places vendor is wired
Attachments POST /api/attachments live multipart · Bearer

Sample payloads

OTP request

{
  "phoneCode": "+966",
  "phone": "500000010",
  "purpose": "login"
}

OTP verify

{
  "challengeId": "<from request>",
  "code": "1234",
  "deviceToken": "dev-device-token",
  "deviceType": "android"
}

Ride compare (Riyadh)

{
  "pickupLat": 24.7136,
  "pickupLng": 46.6753,
  "pickupText": "Riyadh - Central",
  "dropoffLat": 24.7743,
  "dropoffLng": 46.7386,
  "dropoffText": "Riyadh - West",
  "rideCategory": "standard",
  "passengerCount": 1
}

Book ride

{
  "offerId": "<from compare.offers[0].offerId>",
  "paymentMethodRefId": 1,
  "noteToDriver": "Gate A",
  "promoCode": "BALORA10"
}