Files
nick-doc/03 - API Reference/User API.md
2026-05-23 20:35:34 +03:30

263 lines
8.6 KiB
Markdown

---
title: User API
tags: [api, user, reference]
---
# User API
Two routers are mounted for users:
- `/api/user/*` - the new controller pattern in [`backend/src/services/user/userControllerRoutes.ts`](../../backend/src/services/user/userControllerRoutes.ts) wired to `userController`.
- `/api/users/*` - the legacy router in [`backend/src/services/user/userRoutes.ts`](../../backend/src/services/user/userRoutes.ts) (kept for backward compatibility, primarily used by the admin console).
Address-book CRUD lives on its own service: [`/api/addresses/*`](../../backend/src/services/address/addressRoutes.ts). All endpoints require `Bearer JWT` unless noted. Source of truth model: [[User]].
## Profile (current user)
### GET /api/user/profile
**Description:** Returns the caller's profile.
**Auth required:** Bearer JWT
**Response 200:**
```json
{ "success": true, "data": { /* User without password / verification tokens */ } }
```
**Source:** `userController.getCurrentUserProfile`
### PUT /api/user/profile
**Description:** Updates the caller's profile.
**Auth required:** Bearer JWT
**Request body (whitelisted fields):**
```ts
{
firstName?: string;
lastName?: string;
name?: string; // alias for profile.name
phone?: string;
bio?: string;
website?: string;
photoURL?: string; // also mirrored to profile.avatar
isPublic?: boolean;
address?: {
street?: string;
city?: string;
state?: string;
country?: string;
postalCode?: string;
};
preferences?: {
language?: "en" | "fa" | "ar";
currency?: "USD" | "EUR" | "IRR" | "AED";
notifications?: { email?: boolean; sms?: boolean; push?: boolean };
};
}
```
**Response 200:** Updated user.
### GET /api/users/profile
**Description:** Legacy equivalent of the above. Returns the full sanitized user document.
**Auth required:** Bearer JWT
### GET /api/users/profile/:userId
**Description:** Public profile by id. If `profile.isPublic === false` and caller is not the owner or admin, only `firstName`, `lastName`, `avatar`, `role` are returned.
**Auth required:** Bearer JWT
## Avatar upload
Avatar upload is handled by the [[File API]]:
`POST /api/files/upload/avatar` (multipart `avatar`) returns a URL that the caller then writes to `profile.avatar` via `PUT /api/user/profile`.
## Wallet address
### GET /api/user/wallet-address
**Description:** Returns the caller's stored EVM wallet address (or `null`).
**Auth required:** Bearer JWT
**Response 200:** `{ "success": true, "data": { "walletAddress": "0x..." | null } }`
### PATCH /api/user/wallet-address
**Description:** Verifies an EIP-191 signed message and stores `profile.walletAddress`. The server uses `ethers.verifyMessage(message, signature)` and rejects if the recovered address does not match.
**Auth required:** Bearer JWT
**Request body:**
```ts
{
walletAddress: string; // 0x-prefixed 40-hex
signature: string; // signed `message`
message: string; // human-readable challenge text
}
```
**Response 200:** `{ "success": true, "data": { "walletAddress": "0x..." } }`
**Errors:**
- `400` missing fields, malformed address, signature mismatch
- `404` user not found
The legacy alias `PATCH /api/users/wallet-address` performs the same logic.
## Contacts and search
### GET /api/users/contacts
**Description:** Returns the users the caller is allowed to chat with based on role:
- `buyer` → sees `seller` + `admin`
- `seller` → sees `buyer` + `admin`
- `admin` → sees everyone
**Auth required:** Bearer JWT
**Response 200:** `{ "success": true, "data": { "contacts": [...], "count": N } }`
### GET /api/users/search?q=<term>&role=<role>
**Description:** Case-insensitive search across `firstName`/`lastName`/`email`. Returns up to 20 active users.
**Auth required:** Bearer JWT
**Errors:** `400` if `q.length < 2`.
### GET /api/users?role=...&isActive=true&search=...&page=1&limit=50
**Description:** Paginated user directory (legacy, no admin gate). See pagination conventions in [[API Overview]].
**Auth required:** Bearer JWT
## Admin: user management
These are duplicated across the two routers. The newer controller variants live under `/api/user/admin/*`; the legacy bodies live under `/api/users/admin/*`. All require `req.user.role === 'admin'` (the legacy routes check inline; the controller routes only check `authenticateToken` and the controller enforces the role).
### POST /api/user/admin/create
**Description:** Admin creates a user with a chosen role and verification state.
**Auth required:** Bearer JWT (admin)
**Request body:**
```ts
{
email: string;
password: string;
firstName: string;
lastName: string;
role?: "buyer" | "seller" | "admin"; // default "buyer"
isActive?: boolean; // default true
isVerified?: boolean; // default false
profile?: { /* free-form */ };
}
```
**Response 201:** `{ success, data: { user } }`
**Errors:** `400` missing fields, `403` non-admin, `409` email exists.
### DELETE /api/user/admin/:userId
**Description:** Hard-delete a user. Prevents self-deletion and deleting other admins.
**Auth required:** Bearer JWT (admin)
**Response 200:** `{ success, data: { deletedUserId } }`
**Errors:** `400` self-delete, `403` admin-on-admin, `404` not found.
### PATCH /api/user/admin/:userId/status
**Description:** Activate / suspend a user.
**Auth required:** Bearer JWT (admin)
**Request body:** `{ isActive: boolean; reason?: string }`
**Response 200:** `{ success, data: { user: { _id, isActive, statusUpdatedAt } } }`
### PATCH /api/user/admin/:userId/toggle-status
**Description:** Flip active/suspended without explicit body.
**Auth required:** Bearer JWT (admin)
### PATCH /api/user/admin/:userId/role
**Description:** Change a user's role.
**Auth required:** Bearer JWT (admin)
**Request body:** `{ role: "buyer" | "seller" | "admin"; reason?: string }`
**Errors:** `400` invalid role.
### GET /api/user/admin/list
**Description:** Paginated admin user list with filters.
**Auth required:** Bearer JWT (admin)
**Query params:** `role`, `isActive`, `isVerified`, `search`, `page`, `limit`, `sortBy`, `sortOrder`
**Response 200:** `{ success, data: { users, pagination, stats: { totalUsers, activeUsers, verifiedUsers, buyers, sellers, admins } } }`
### GET /api/user/admin/:userId/dependencies
**Description:** Returns a count of related entities (purchase requests, offers, payments) before a destructive admin operation.
**Auth required:** Bearer JWT (admin)
### GET /api/users/admin/stats
**Description:** Aggregated user stats — total/active/verified counts, role distribution, activity buckets (24h / 7d / 30d).
**Auth required:** Bearer JWT (admin)
### GET /api/users/admin/:userId
**Description:** Fetch a single user by id (admin view, includes preferences and last-login).
**Auth required:** Bearer JWT (admin)
### PUT /api/users/admin/:userId
**Description:** Mass update a user document (admin override).
**Auth required:** Bearer JWT (admin)
### PUT /api/users/admin/update/:email
**Description:** Same as above but keyed on email.
**Auth required:** Bearer JWT (admin)
### PATCH /api/users/admin/:userId/password
**Description:** Admin forces a new password. Wipes `refreshTokens` so all sessions are invalidated.
**Auth required:** Bearer JWT (admin)
**Request body:** `{ newPassword: string; reason?: string }`
### POST /api/users/admin/:userId/resend-verification
**Description:** Regenerate the 8-digit email verification code and re-send the verification email.
**Auth required:** Bearer JWT (admin)
**Errors:** `400` user already verified.
## Address book
Source: [`backend/src/services/address/addressRoutes.ts`](../../backend/src/services/address/addressRoutes.ts), model: [[Address]].
### GET /api/addresses
**Description:** List the caller's addresses.
**Auth required:** Bearer JWT
**Response 200:** `{ success: true, data: [Address, ...] }`
### POST /api/addresses
**Description:** Create a new address. First address auto-becomes primary.
**Auth required:** Bearer JWT
**Request body:**
```ts
{
fullName: string;
phone: string;
street: string;
city: string;
state?: string;
country: string;
postalCode?: string;
isPrimary?: boolean;
notes?: string;
}
```
### PUT /api/addresses/:addressId
**Description:** Update an address.
**Auth required:** Bearer JWT
**Errors:** `404` not owned by user.
### DELETE /api/addresses/:addressId
**Description:** Delete an address. If it was the primary, another address is promoted.
**Auth required:** Bearer JWT
### PATCH /api/addresses/:addressId/primary
**Description:** Promote an address to primary; demotes the previous primary.
**Auth required:** Bearer JWT
See [[Address]] for the schema, and [[Marketplace API]] for how purchase requests reference an address.