API Reference
Base URL: http://localhost:8000
Interactive docs: /docs (Swagger UI) | /redoc
Authentication
All protected routes require the Authorization: Bearer <access_token> header.
Auth Endpoints
| Method | Path | Auth | Role | Description |
|---|---|---|---|---|
| POST | /auth/register |
No | — | Register new user, returns token pair |
| POST | /auth/login |
No | — | Login with email + password |
| POST | /auth/refresh |
No | — | Exchange refresh token for new access token |
| POST | /auth/logout |
Yes | any | Logout current user |
| GET | /auth/me |
Yes | any | Get current user profile |
POST /auth/register
Request body:
Response 201:
Errors: 409 email already registered | 422 validation error
POST /auth/login
Request body:
Response 200: Same as register.
Errors: 401 invalid credentials | 403 account deactivated
POST /auth/refresh
Request body:
Response 200: Same token pair shape.
Errors: 401 invalid or expired refresh token
User Endpoints
| Method | Path | Auth | Role | Description |
|---|---|---|---|---|
| GET | /users/me |
Yes | any | Get own profile |
| PATCH | /users/me |
Yes | any | Update own profile (full_name) |
| GET | /users |
Yes | admin | List all users (paginated) |
| GET | /users/{user_id} |
Yes | admin or self | Get user by ID |
| DELETE | /users/{user_id} |
Yes | admin | Soft-delete user (sets is_active=false) |
GET /users/me
Response 200:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"full_name": "John Doe",
"role": "user",
"is_active": true,
"is_verified": false,
"last_login": "2024-01-15T10:30:00Z",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
PATCH /users/me
Request body:
GET /users?skip=0&limit=20
Query params: skip (default 0), limit (default 20, max 100)
Response 200: Array of UserResponse objects.
Health Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health |
No | Liveness probe |
| GET | /health/ready |
No | Readiness probe (checks DB + Redis) |
GET /health
Response 200:
GET /health/ready
Response 200:
Response 503 (if any dependency is down):
Error Format
All errors return consistent JSON:
| Error Code | Status | Meaning |
|---|---|---|
UNAUTHORIZED |
401 | Missing or invalid token |
FORBIDDEN |
403 | Insufficient role / inactive account |
NOT_FOUND |
404 | Resource does not exist |
CONFLICT |
409 | Duplicate resource (e.g. email) |
ERROR |
500 | Unexpected server error |