# Gishen-Mob Backend Spec **Base URL (TBD):** `https://api.gishen.example/v1` **Auth:** Bearer JWT after verified sign-in (phone OTP, email, Google, or Telegram) **Headers:** `Authorization`, `Accept-Language` (`en` | `am`), `Content-Type: application/json` Shared with Gishen-Ecom / Gishen-B2B where noted. Patch this file whenever a feature is added or finalized. ## Auth | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/auth/otp/request` | Required | `{ phone }` — SMS OTP | | POST | `/auth/otp/verify` | Required | `{ phone, code }` → session + user | | POST | `/auth/email/login` | Required | `{ email, password }` → session + user | | POST | `/auth/email/register` | Optional | `{ name, email, password, phone? }` | | POST | `/auth/oauth/google` | Required | `{ idToken }` (or auth code) → session + user | | POST | `/auth/oauth/telegram` | Required | Telegram Login Widget payload → session + user | | POST | `/auth/guest` | Required | Optional device id → limited guest session (`isGuest: true`) | | POST | `/auth/biometric/bind` | Required | Device biometric public key | | GET | `/users/me` | Required | Profile, locale, points, tier, `authProvider` | | PATCH | `/users/me` | Required | name, email, phone, `locale`, biometric flag | **Providers (mobile UI):** `google` \| `email` \| `phone` \| `telegram` \| `guest` Guest sessions may browse catalog and generate **pharmacist order codes**; loyalty, corporate, and some care features require a non-guest account. ## Locale | Method | Path | Status | Notes | |--------|------|--------|-------| | PATCH | `/users/me` | Required | `{ locale: "en" \| "am" }` | | — | Accept-Language | Required | All requests | ## Catalog | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/catalog/products` | Required | q, category, badge, max — parity with Ecom | | GET | `/catalog/products/:idOrSlug` | Required | | | GET | `/catalog/categories` | Required | | ## Favorites | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/favorites/me` | Required | Product ids | | PUT | `/favorites/:productId` | Required | Add | | DELETE | `/favorites/:productId` | Required | Remove | ## Addresses | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/users/me/addresses` | Required | Saved delivery addresses | | POST | `/users/me/addresses` | Required | label, street, area, landmark?, isDefault? | | PATCH | `/users/me/addresses/:id` | Required | | | DELETE | `/users/me/addresses/:id` | Required | | ## Branches / Stock | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/branches` | Required | | | GET | `/branches/nearby` | Required | `lat`, `lng` | | GET | `/stock/product/:productId` | Required | Nearby availability | ## Orders | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/orders` | Required | items, fulfillment, branchId?, location, paymentMethod, prescriptionFileKeys?, notes, credit?, `anyBranch?` | | GET | `/orders/me` | Required | Authenticated user’s orders | | GET | `/orders/:id` | Required | | | GET | `/orders/by-code/:code` | Required | Lookup by `GSH-XXXX` (guest + pickup). Mobile uses this for “find my code”. | | GET | `/orders/:id/tracking` | Required | Rider trail when assigned | | POST | `/orders/:id/cancel` | Required | | ### Guest / pharmacist order codes (parity with Gishen Ecom Web) Guests (and optionally signed-in pickup) receive a short **pharmacist reference code** (`GSH-XXXX`). | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/orders/guest-codes` | Required | Basket snapshot + customer name/phone → `{ code, orderId, status: "requested" }`. Mobile shows copy / share / screenshot card. | | GET | `/admin/orders/by-code/:code` | Required | **Admin** — pharmacist enters code to create / hydrate the POS order (shared with Ecom admin). | | POST | `/admin/orders/by-code/:code/fulfill` | Required | Mark created / confirmed after admin processing | **Mobile contract** - Guest checkout forces pickup + `pay_at_branch` + any-branch code. - Response includes `pickupCode`, `status: requested` until pharmacist creates the order in admin. - Share payload should include code, customer, line items, total (plain text for WhatsApp / clipboard). ## Payments | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/payments/initiate` | Required | `chapa` \| `telebirr` \| `mpesa` only for delivery | | POST | `/payments/webhook/*` | Required | Gateway callbacks | | — | `pay_at_branch` | Required | Allowed **only** when `fulfillment=pickup` (required for guest pharmacist codes) | ## Prescriptions (Rx Care) | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/uploads/signed-url` | Required | Rx images | | POST | `/prescriptions` | Required | Multi-page keys, medicines[], patient, memberId? | | POST | `/prescriptions/check` | Required | Match catalog → ready/review/unavailable | | GET | `/prescriptions/me` | Required | | | GET | `/prescriptions/:id` | Required | Detail + attached reminders | | POST | `/prescriptions/:id/reorder` | Required | | ## Reminders | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/health/reminders` | Required | Dose/refill schedules (times[], graceMinutes, escalate?) | | POST | `/health/reminders/:id/confirm` | Required | `dose.confirmed` | | POST | `/health/reminders/:id/snooze` | Required | | | GET | `/health/reminders/me` | Required | | | — | Local + remote push | Required | Daily dose window; calendar UI on `/prescriptions/:id/calendar` | ## Emergency contacts | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/users/me/emergency-contacts` | Required | | | POST | `/users/me/emergency-contacts` | Required | name, phone, relationship | | DELETE | `/users/me/emergency-contacts/:id` | Required | | | — | Job `dose.missed_escalation` | Required | After grace (default 30m) SMS/push to contact if no confirm | ## Family | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/family/members` | Required | | | POST | `/family/invites` | Required | phone or link code | | POST | `/family/invites/accept` | Required | | | DELETE | `/family/members/:id` | Required | | ## Subscriptions | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/subscriptions/me` | Required | | | POST | `/subscriptions` | Required | | | POST | `/subscriptions/:id/pause` | Required | | | POST | `/subscriptions/:id/resume` | Required | | | POST | `/subscriptions/:id/cancel` | Required | | ## B2B / Corporate (shared with Gishen-B2B) | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/users/me/contexts` | Required | personal + org memberships | | POST | `/orgs/join` | Required | `{ code }` | | GET | `/company/me` | Required | Member view: plan, allowance | | POST | `/checkout/credit/quote` | Required | Basket split covered vs selfPay | ## Loyalty | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/loyalty/me` | Required | | | GET | `/loyalty/me/ledger` | Required | | | POST | `/loyalty/redeem` | Required | | | GET | `/referrals/me` | Required | | ## Notifications (in-app inbox) Distinct from order list. Home bell → inbox. | Method | Path | Status | Notes | |--------|------|--------|-------| | GET | `/notifications/me` | Required | kinds: `order` \| `rx` \| `dose` \| `loyalty` \| `promo` \| `system` | | POST | `/notifications/:id/read` | Required | | | POST | `/notifications/read-all` | Required | | | DELETE | `/notifications/:id` | Required | | | POST | `/devices` | Required | push token registration | ## Push / Tracking | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/devices` | Required | push token | | — | Events | Required | order.*, dispatch.*, dose.*, refill.*, escalation.*, guest_code.* | | GET | `/orders/:id/tracking` | Required | | ## Contact / Support | Method | Path | Status | Notes | |--------|------|--------|-------| | POST | `/contact` | Required | | | — | Chatwoot | Deeplink | https://chat.yaltopia.com | | — | WhatsApp / Call | Deeplink | Branch support numbers | ### Changelog - 2026-08-06: Scaffold — skeleton created with all domains. - 2026-08-06: Auth/Locale — OTP mock, biometric bind flag, language picker en/am, Accept-Language noted. - 2026-08-06: Catalog — products/categories from Ecom data port; shop/search/favorites. - 2026-08-06: Branches/Stock — GPS nearest sort; pickup selection (stock map stub). - 2026-08-06: Orders/Payments/B2B — checkout with Chapa/Telebirr/M-Pesa; pay_at_branch pickup-only; WhatsApp handoff; credit quote split stub. - 2026-08-06: Prescriptions/Reminders/Emergency — camera multi-page scan, check statuses, calendar dose push, escalation job contract. - 2026-08-06: Family/Subscriptions — invite/manage; refill subscription CRUD. - 2026-08-06: B2B/Account — contexts, join codes, profile switcher. - 2026-08-06: Loyalty/Push/Tracking — wallet redeem/referral; order tracking map mock; device push channels. - 2026-08-06: Contact/Support — contact form + Chatwoot/WhatsApp/call deeplinks. - 2026-08-07: Auth providers — Google, Email, Phone OTP, Telegram, and Guest session contracts; `authProvider` on `/users/me`. - 2026-08-07: Guest pharmacist codes — `POST /orders/guest-codes`, `GET /orders/by-code/:code`, admin fulfill-by-code (Ecom parity); mobile copy/share/screenshot card. - 2026-08-07: Notifications inbox — dedicated `/notifications/me` (separate from Orders); Favorites + Addresses endpoints documented; Rx Care dose reminder confirm/snooze.