# Endpoints: Members Member CRUD, quick import, invites, join flow, and dependants. **Workspace:** `/Users/kirukib/Desktop/Yaltopia Project/Gishen-B2B` **Entity:** [`../entities/member.md`](../entities/member.md) --- ## GET /v1/members List members. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN, FINANCE (read metadata) | ### Query `?page=1&status=active&department_id=dept_01H&package_id=pkg_01HGOLD&q=abel&member_type=primary&has_dependants=true` | Param | Notes | |-------|--------| | `q` | Search name, email, phone, employee_id | | `status` | `invited` \| `active` \| `inactive` \| `offboarded` | | `department_id` | Filter by department | | `package_id` | Filter by assigned package | | `member_type` | `primary` \| `dependant` | | `has_dependants` | `true` \| `false` — primaries with/without dependants | Portal UI: when more than three filters are shown, they open in an Apply modal (client-only); API still accepts all query params above. ### Response 200 Paginated members. HR/Finance receive withhold-safe fields (no Rx detail). ### Clinical withhold Response omits prescription arrays; includes `prescription_count` only. --- ## POST /v1/members Create member. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN | ### Request ```json { "full_name": "Sara Hailu", "phone": "+251933445566", "email": "sara.h@acme.et", "employee_id": "EMP-2001", "department_id": "dept_01HABC", "package_id": "pkg_01HGOLD", "member_type": "primary", "start_date": "2026-04-01", "send_invite": true } ``` ### Response 201 Created [`Member`](../entities/member.md). ### Errors | Code | HTTP | When | |------|------|------| | `ORG_PENDING` | 422 | Org not active | | `DUPLICATE_MEMBER` | 409 | Phone/employee_id conflict | | `NOT_FOUND` | 404 | Invalid department/package | | `DEPENDANT_LIMIT_EXCEEDED` | 422 | For dependant create | --- ## GET /v1/members/:id Member detail. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN, FINANCE (metadata); MEMBER (own only) | ### Errors | Code | HTTP | |------|------| | `FORBIDDEN` | 403 — MEMBER accessing other member | | `NOT_FOUND` | 404 | ### Clinical withhold HR/Finance: no linked prescriptions. SUPER_USER: may include `prescriptions_summary`. MEMBER own: full allowance, order pointers. Detail payload includes `avatar_url`, `card_id`, `verification_id` for pharmacy ID card (safe for HR). --- ## GET /v1/members/:id/id-card Printable pharmacy verification card payload (B2B print UI + Admin/POS scan). | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN; MEMBER (own `member_id` only) | ### Response 200 ```json { "data": { "member_id": "mbr_01HMEM001", "full_name": "Abel Mekonnen", "employee_id": "EMP-1042", "card_id": "GSH-1042", "verification_id": "EMP-1042", "avatar_url": "https://api.dicebear.com/9.x/lorelei/svg?seed=mbr_01HMEM001", "org_name": "Acme Bank", "org_join_code": "ACME-2026", "package_name": "Gold Executive", "status": "active", "qr_payload": "gishen://member/mbr_01HMEM001?v=EMP-1042" } } ``` ### QR / scan contract | | | |---|---| | **Format** | `gishen://member/{member_id}?v={verification_id}` | | **Consumer** | Gishen-Admin POS / pharmacist checkout — resolve covered member | | **Not included** | Prescription images, medicine lines, diagnosis | ### Errors | Code | HTTP | |------|------| | `FORBIDDEN` | 403 | | `NOT_FOUND` | 404 | | `MEMBER_INACTIVE` | 422 — offboarded / inactive cards may still print with watermark (product TBD) | ### Clinical withhold ID card is verification metadata only — allowed for HR. No clinical fields. --- ## PATCH /v1/members/:id Update member. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN | ### Request (partial) ```json { "department_id": "dept_01HNEW", "package_id": "pkg_01HSILVER", "avatar_url": "https://cdn.gishen.../avatars/mbr_01H.png", "overrides": { "copay_percent": 5 } } ``` `avatar_url` may also be set via future `POST /v1/members/:id/avatar` (multipart). Mock phase uses deterministic portrait URLs. --- ## POST /v1/members/:id/offboard Offboard member. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN | ### Request ```json { "end_date": "2026-03-31", "reason": "resignation" } ``` ### Response 200 `status: "offboarded"`. Prescriptions remain on `customer_id`. --- ## POST /v1/members/import Quick Excel/CSV import (simplified migration). | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN | ### Request `multipart/form-data`: `file`, optional `send_invites=true` ### Response 202 ```json { "data": { "job_id": "mig_01HQUICK", "status": "validating" } } ``` Delegates to migration engine — see [`migration.md`](migration.md). --- ## POST /v1/members/:id/invite Resend or create invite. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN | ### Response 200 ```json { "data": { "invite_url": "https://b2b.gishen.../invite/tok_abc123", "expires_at": "2026-03-20T00:00:00Z" } } ``` --- ## GET /v1/invite/:token Public invite preview. | | | |---|---| | **Auth** | Public | ### Response 200 ```json { "data": { "org_name": "Acme Bank", "member_name": "Sara Hailu", "expires_at": "2026-03-20T00:00:00Z", "valid": true } } ``` ### Errors | Code | HTTP | |------|------| | `INVITE_EXPIRED` | 422 | | `NOT_FOUND` | 404 | --- ## POST /v1/invite/:token/accept Accept invite and activate member account. | | | |---|---| | **Auth** | Public (creates session) | ### Request ```json { "password": "SecurePass1", "locale": "en" } ``` --- ## POST /v1/join Self-join via join code or email domain. | | | |---|---| | **Auth** | Public | ### Request ```json { "join_code": "ACME-2026", "full_name": "New Employee", "email": "new@acme.et", "phone": "+251944556677" } ``` Or domain-verified email flow. ### Response 201 Pending or active member + session depending on org verification settings. ### Errors | Code | HTTP | |------|------| | `VALIDATION_FAILED` | 400 — bad code/domain | | `ORG_PENDING` | 422 | --- ## POST /v1/members/:id/dependants Add dependant. | | | |---|---| | **Auth** | Required | | **Roles** | SUPER_USER, HR_ADMIN | ### Request ```json { "full_name": "Kidus Hailu", "phone": "+251955667788", "relationship": "child", "start_date": "2026-04-01" } ``` --- ## UI routes | Route | Endpoint(s) | |-------|-------------| | `/members` | GET `/v1/members` (search + filters; modal when >3) | | `/members/new` | POST `/v1/members` | | `/members/import` | POST `/v1/members/import` | | `/members/[id]` | GET/PATCH + invite/offboard; **ID card** tab → GET `/v1/members/:id/id-card` | | `/invite/[token]` | GET/POST invite | | `/join` | POST `/v1/join` | ## Clinical withhold Member endpoints never return prescription images or medicine lines to HR_ADMIN/FINANCE. Use prescription endpoints with role checks for SUPER_USER/MEMBER clinical access.