# API Endpoints Every backend endpoint the frontend calls. Paths are shown **after** the API base (today `SARLINK_API_BASE_URL`; in the target architecture the base becomes `API_URL` → nginx `/api`). Auth = requires `Authorization: Token `. Third-party integrations use different bases (`PERSON_VERIFY_BASE_URL`, `OMADA_BASE_URL`, hardcoded Invoice Ninja) — flagged inline. ## Summary | Method | Path | Purpose | Auth | |---|---|---|:--:| | **Auth & onboarding** |||| | GET | `/api/auth/users/filter/?mobile=&id_card=` | Does a permanent user exist / is verified | No | | GET | `/api/auth/users/temp/filter/?mobile=&id_card=` | Does a pending (temp) user exist | No | | POST | `/auth/mobile/` | Send login OTP to a mobile | No | | POST | `/api/auth/register/` | Register a new (temp) user | No | | POST | `/api/auth/register/verify/` | Verify registration OTP | No | | POST | `/callback/auth/` | Exchange OTP PIN → API token + user | No | | POST | `/auth/logout/` | Invalidate token on sign-out | Yes | | POST | `/auth/login/` | Username/password login — **DEAD** | No | | **Billing** |||| | POST | `/api/billing/payment/` | Create a device payment | Yes | | GET | `/api/billing/payment/?…&all_payments=` | List payments | Yes | | GET | `/api/billing/payment/{id}` | Get one payment | Yes | | PATCH | `/api/billing/payment/{id}/cancel/` | Cancel a payment | Yes | | PUT | `/api/billing/payment/{id}/verify/` | Verify/complete payment (TRANSFER/WALLET) | Yes | | POST | `/api/billing/topup/` | Create a wallet top-up | Yes | | GET | `/api/billing/topup/?…&all_topups=` | List top-ups | Yes | | GET | `/api/billing/topup/{id}` | Get one top-up | Yes | | PATCH | `/api/billing/topup/{id}/cancel/` | Cancel a top-up | Yes | | PUT | `/api/billing/topup/{id}/verify/` | Verify a top-up payment | Yes | | POST | `/api/billing/admin-topup/` | Admin credits a user's wallet | Yes | | GET | `/api/billing/wallet-transactions/?…&all_transactions=` | List wallet transactions | Yes | | **Devices** |||| | GET | `/api/devices/?…&all_devices=` | List devices | Yes | | GET | `/api/devices/{id}/` | Get one device | Yes | | POST | `/api/devices/` | Register/add a device | Yes | | PUT | `/api/devices/{id}/block/` | Block/unblock a device | Yes | | **Users / profile / geo** |||| | GET | `/api/auth/atolls/` | List atolls (+ nested islands) | No | | GET | `/api/auth/users/?…` | List users (admin) | Yes | | GET | `/api/auth/users/{id}/` | Get a user profile by id | Yes | | GET | `/api/auth/profile/` | Logged-in user's own profile | Yes | | PUT | `/api/auth/users/{id}/verify/` | Admin verify a user | Yes | | DELETE | `/api/auth/users/{id}/reject/` | Admin reject a user | Yes | | PUT | `/api/auth/users/{id}/update/` | Update a user's details | Yes | | PUT | `/api/auth/users/{id}/agreement/` | Upload/update agreement (multipart) | Yes | | **Third-party** |||| | GET | `{PERSON_VERIFY}/api/person/{idCard}` | National identity lookup | No | | — | Omada group/block endpoints | **DEAD** (moving to RADIUS) | X-API-key | | POST | `{ninja}/api/v1/clients` | Invoice Ninja client — **DEAD** | x-api-token | ## Auth & onboarding - **GET `/api/auth/users/filter/`** — `signin()` (auth-actions) + `checkIdOrPhone()`. Checks a phone/ID exists & is verified before OTP; signup dupe-check. → `{ ok, verified }`. - **GET `/api/auth/users/temp/filter/`** — `checkTempIdOrPhone()`. Pending-registration lookup. → `{ ok, otp_verified, t_verified }`. - **POST `/auth/mobile/`** — `signin()`. Sends login OTP. Body `{ mobile }`. → `{ detail }`. - **POST `/api/auth/register/`** — `backendRegister()` from `signup()`. Body `{ firstname, lastname, username, address, id_card, dob, mobile, island, atoll, acc_no, terms_accepted, policy_accepted }`. → `{ t_username }`. - **POST `/api/auth/register/verify/`** — `VerifyRegistrationOTP()`. Body `{ mobile, otp }`. → `{ message, verified }`. - **POST `/callback/auth/`** — the login token exchange (was NextAuth `authorize`, now `verify-otp-form`). Body `{ token: pin }`. → `{ user, token, expiry }`. 400/403/429 return error payloads (`token[0]` / `message`). - **POST `/auth/logout/`** — `logout()`. Expects `204`. - **POST `/auth/login/`** — DEAD (`login()` via `axiosInstance`, unused; login goes through `/callback/auth/`). ## Billing `actions/payment.ts`, `queries/wallet.ts`, `actions/user-actions.ts`. - **POST `/api/billing/payment/`** `createPayment()` — pay for cart devices. Body `{ device_ids[], number_of_months }` → `Payment`. - **GET `/api/billing/payment/`** `getPayments()` — list; `all_payments=true` for admin. → `ApiResponse`. - **GET `/api/billing/payment/{id}`** `getPayment()` → `Payment`. - **PATCH `…/payment/{id}/cancel/`** `cancelPayment()` → `Payment`. - **PUT `…/payment/{id}/verify/`** `verifyPayment()` / `verifyDevicePayment()` — Body `{ method: "TRANSFER" | "WALLET" }`. MIB verification is **server-side**; the frontend just sends the method. → `Payment`. - **POST `/api/billing/topup/`** `createTopup()` — Body `{ amount }` → `Topup`. - **GET `/api/billing/topup/`** `getTopups()` — `all_topups=true` for admin. → `ApiResponse`. - **GET `/api/billing/topup/{id}`** `getTopup()` → `Topup`. - **PATCH `…/topup/{id}/cancel/`** `cancelTopup()` → `Topup`. - **PUT `…/topup/{id}/verify/`** `verifyTopupPayment()` → `{ status, message, transaction? { ref, sourceBank, trxDate } }`. - **POST `/api/billing/admin-topup/`** `adminUserTopup()` — Body `{ amount, user_id, description }`. - **GET `/api/billing/wallet-transactions/`** `getWaleltTransactions()` → `ApiResponse` (`transaction_type: "DEBIT" | "TOPUP"`). ## Devices `queries/devices.ts` (`checkSession()` for token). - **GET `/api/devices/`** `getDevices()` — params `name, offset, limit, page, sortBy, status`, `all_devices=true` for admin. → `ApiResponse`. - **GET `/api/devices/{id}/`** `getDevice()` → `Device`. - **POST `/api/devices/`** `addDeviceAction()` — Body `{ name, mac, registered: true }` → `Device`. - **PUT `/api/devices/{id}/block/`** `blockDeviceAction()` — Body `{ blocked, reason_for_blocking, blocked_by: "ADMIN" | "PARENT" }`. Parents forced to `PARENT`. → `Device`. ## Users / profile / geo `queries/users.ts`, `queries/islands.ts`, `actions/user-actions.ts`. - **GET `/api/auth/atolls/`** `getAtolls()` — atoll+island dropdowns on signup. → `Atoll[]` (each with nested `islands`). - **GET `/api/auth/users/`** `getUsers()` — admin user list. → `ApiResponse`. - **GET `/api/auth/users/{id}/`** `getProfileById()` — profile & admin user pages. → `UserProfile`. - **GET `/api/auth/profile/`** `getProfile()` — own profile (agreements, payment detail). → `User`. - **PUT `/api/auth/users/{id}/verify/`** `verifyUser()` — → `{ ok, mismatch_fields, … }`; surfaces field mismatches. - **DELETE `/api/auth/users/{id}/reject/`** `rejectUser()` — Body `{ rejection_details }`; `204` → revalidate/redirect. - **PUT `/api/auth/users/{id}/update/`** `updateUser()` — Body = non-empty form fields. → `User` or per-field errors. - **PUT `/api/auth/users/{id}/agreement/`** `updateUserAgreement()` — multipart FormData (PDF). → `{ agreement }`. ## Third-party - **GET `{PERSON_VERIFY_BASE_URL}/api/person/{idCard}`** `getNationalPerson()` (`lib/person.ts`) — **LIVE**. National identity lookup to cross-check user data during admin verification. ISR `revalidate: 60`. → `TNationalPerson { nic, name(_en), dob, gender, house_name(_en), island_name(_en), atoll(_en), constituency, … }`. *Memory note: planned to route through the backend instead of calling directly.* - **Omada** (`actions/omada-actions.ts`) — group profiles / add-to-group / block — **DEAD**, none imported by UI. Device blocking now uses backend `/api/devices/{id}/block/`. Consistent with the Omada→RADIUS migration. - **Invoice Ninja** (`actions/ninja/client.ts`) — hardcoded staging URL, create client — **DEAD**. ## Frontend's own API routes (`app/api/`) — not backend - **`app/api/auth/[...nextauth]/route.ts`** — NextAuth handler. **To be removed** in the static migration. - **`app/api/check-devices/route.ts`** — stub returning `{ message: "Request received" }`; no backend call. Dead/placeholder. ## Response envelope List endpoints return `ApiResponse = { meta, links, data: T[] }` (pagination). Errors surface as `{ message }` / `{ detail }` (see `handleApiResponse` in `utils/tryCatch.ts`, which is hardened against non-JSON error bodies). ## Dead code to drop during the port `/auth/login/` (#8), `/islands/`, `/inventory/`, all Omada, Invoice Ninja, `backendMobileLogin`, `app/api/check-devices`, and the two axios helpers `utils/axios-client.ts` / `utils/axiosInstance.ts` (only used by dead calls).