# BizzCab Admin API

Base URL: `http://127.0.0.1:5001/api`

Auth: `Authorization: Bearer <admin JWT>` except login, OTP, forgot-password, and reset-password.

Envelope and seed login are in [api.md](api.md).

Postman: import [BizzCab Local](postman/BizzCab.postman_environment.json), then [Admin](postman/BizzCab-Admin.postman_collection.json). Run **Login** first. If the response has `requiresOtp`, run **Verify OTP**. Tests save `adminToken`, then the first id from each list (`userId`, `driverId`, `rideId`, and so on).

## Auth

| Method | Path | Body |
|---|---|---|
| POST | `/admin/auth/login` | `email`, `password` |
| POST | `/admin/auth/verify-otp` | `challengeToken`, `otp` |
| POST | `/admin/auth/resend-otp` | `challengeToken` |
| POST | `/admin/auth/forgot-password` | `email` |
| POST | `/admin/auth/reset-password` | `email`, `otp`, `newPassword`, `confirmPassword` |
| POST | `/admin/auth/logout` | — |
| GET | `/admin/auth/me` | — |
| PUT | `/admin/auth/profile` | `name`, `phone` |
| POST | `/admin/auth/change-password` | `currentPassword`, `newPassword`, `confirmPassword` |
| PUT | `/admin/auth/two-factor` | `enabled` |

Login returns `data.token` when 2FA is off. When 2FA is on it returns `data.challengeToken` and, in development, `data.devOtp`.

## Dashboard and settings

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/dashboard` | Counts for the home cards |
| GET | `/admin/app-config` | Branding, city, SOS numbers |
| PUT | `/admin/app-config` | JSON or multipart `mobileLogo`, `adminLogo` |

## Users

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/users` | Query: `q`, `status`, `deleteRequested`, `page`, `limit` |
| GET | `/admin/users/:id` | Profile, bank, rides |
| PATCH | `/admin/users/:id` | `status`: `active`, `blocked`, `inactive`, `deleted`. `deleteRequested: false` rejects a delete request |

## Drivers and vehicles

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/drivers` | Query: `q`, `status`, `page`, `limit` |
| GET | `/admin/drivers/:id` | Documents and bank accounts |
| PATCH | `/admin/drivers/:id` | `approvalStatus`, `kycStatus`, `accountStatus`, `documentId` + `documentStatus`, or `activeBankAccountId` |
| GET | `/admin/vehicles` | Categories and vehicles |
| POST | `/admin/vehicles` | multipart: `vehicleType`, `registrationNumber`, `model`, `color`, `driver`, files `rc`, `insurance`, `puc`, `photos` |
| GET | `/admin/vehicles/:id` | — |
| PATCH | `/admin/vehicles/:id` | `status` (`approved` / reject) plus the same files as create |
| PATCH | `/admin/vehicles/types/:id` | Fare: `baseFare`, `perKm`, `minFare`, `waitingPerMin`, `taxPercent` |
| GET | `/admin/commission` | — |
| PUT | `/admin/commission` | `defaultCommissionPercent`, `types: [{ id, commissionPercent }]` |

## Rides, SOS, reports

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/rides` | Query: `status`, `scope`, `q`, `paymentStatus`, `vehicleType` |
| GET | `/admin/rides/:id` | — |
| POST | `/admin/rides/:id/cancel` | `{ "reason": "Ops cancellation" }` |
| GET | `/admin/sos` | Query: `status=open` |
| PATCH | `/admin/sos/:id/resolve` | `{ "note": "Called rider" }` |
| GET | `/admin/reports` | JSON, or `?format=csv` |

## Wallets, coupons, payouts

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/wallets` | Query: `ownerType=user\|driver` |
| POST | `/admin/wallets/adjust` | `ownerType`, `ownerId`, `amount`, `type` (`credit`/`debit`), `note` |
| GET | `/admin/coupons` | — |
| POST | `/admin/coupons` | `code`, `discountType`, `discountValue`, limits, dates |
| PUT | `/admin/coupons/:id` | Same fields plus `active` |
| GET | `/admin/coupons/:id/report` | Usage |
| GET | `/admin/payouts` | — |
| PATCH | `/admin/payouts/:id` | `{ "status": "processed" }` |

## Content and locations

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/ratings` | — |
| PATCH | `/admin/ratings/:id` | `{ "hidden": true }` |
| GET | `/admin/tickets` | — |
| PATCH | `/admin/tickets/:id` | `status`, `resolution` |
| POST | `/admin/tickets/:id/messages` | `{ "text": "…" }` |
| GET | `/admin/notifications` | — |
| POST | `/admin/notifications` | `audience`, `title`, `body`, `type` |
| GET | `/admin/cms` | — |
| PUT | `/admin/cms` | `slug`, `title`, `content` |
| GET | `/admin/faqs` | — |
| POST | `/admin/faqs` | `question`, `answer`, `sort`, `audience`, `active` |
| PUT | `/admin/faqs/:id` | Same as create |
| GET | `/admin/support-categories` | — |
| POST | `/admin/support-categories` | `name`, `slug`, `sort`, `active` |
| PUT | `/admin/support-categories/:id` | Same as create |
| GET | `/admin/locations` | Cities and zones |
| POST | `/admin/cities` | `name`, `active` |
| PUT | `/admin/cities/:id` | Same |
| POST | `/admin/zones` | `name`, `city`, `operatingHours` |
| PUT | `/admin/zones/:id` | Same plus `active` |
