- Update data model enums to match backend models - Update API reference auth requirements - Add dispute module references and warning blocks - Add 2026-05-24 audit remediation callout to Overview - Generate task breakdowns and audit artifacts - Add doc alignment report (.taskmaster/reports/)
8.4 KiB
title, tags
| title | tags | |||
|---|---|---|---|---|
| API Overview |
|
API Overview
The AMN backend is an Express.js + TypeScript service that exposes a REST API plus a Socket.IO real-time channel. Every HTTP endpoint is mounted under /api/<service>/... in backend/src/app.ts and follows a consistent response envelope, authentication scheme, and error model.
This page is the entry point for the API. See the individual service pages for endpoint details:
- Authentication API - register/login/passkeys/Google OAuth
- User API - profile, wallet, admin user management
- Marketplace API - purchase requests, seller offers, templates, shop, reviews
- Payment API - SHKeeper, Web3, DePay, payouts
- Chat API - conversations and messages
- Notification API - in-app notifications
- Dispute API - dispute resolution (planned, not yet implemented)
- Blog API - blog posts (planned, not yet implemented)
- Admin API - user management, data cleanup (planned, not yet implemented)
- Points API - loyalty points, levels, referrals (planned, not yet implemented)
- AI API - OpenAI-backed text endpoints
- File API - upload, delete, serve
- Socket Events - real-time events
- Error Codes - status mapping and error shape
Base URLs
| Environment | Base URL |
|---|---|
| Local development | http://localhost:5001/api |
| Staging / dev | https://dev.amn.gg/api |
| Production | https://amn.gg/api |
The base port is set via PORT env var; in development it defaults to 5001. CORS is restricted to process.env.FRONTEND_URL and credentials are allowed (cors({ origin, credentials: true }) in app.ts).
Health check (not under /api): GET /health → { success, message, timestamp, environment, version }.
API discovery endpoint: GET /api → returns a map of available service prefixes.
Versioning
The API is currently un-versioned (there is no /v1 in paths). Breaking changes are communicated via release notes in the repository. The version string is exposed on /health and is sourced from package.json (process.env.npm_package_version). At the time of writing the deployed version is in the 4.x line.
Authentication
All protected endpoints use a stateless JWT in the standard HTTP Authorization header:
Authorization: Bearer <accessToken>
The token is verified by authenticateToken in backend/src/shared/middleware/auth.ts using config.jwtSecret. The decoded payload is normalised into req.user = { id, email, role } regardless of which key carried it (id, userId, _id, sub).
Tokens are issued by POST /api/auth/login, POST /api/auth/google/signin, POST /api/auth/google/signup, POST /api/auth/passkey/authenticate, and POST /api/auth/refresh-token. Refresh tokens are stored on the User document (refreshTokens array) so an admin password change wipes them and forces re-login.
Role-based access uses authorizeRoles('admin', ...) after authenticateToken. Three roles exist: buyer, seller, admin.
WebAuthn / Passkey flows live under /api/auth/passkey/* and exchange a challenge for an assertion; on success a regular JWT pair is returned (tokens.accessToken, tokens.refreshToken). See Authentication Flow for the full lifecycle.
Standard response envelope
The canonical helper is ResponseHandler in backend/src/shared/utils/response-handler.ts. Successful responses look like:
{
"success": true,
"message": "Success",
"data": { /* payload */ },
"statusCode": 200,
"timestamp": "2026-05-23T10:00:00.000Z",
"path": "/api/marketplace/purchase-requests",
"method": "GET",
"meta": { /* optional */ }
}
Paginated responses add a pagination block:
{
"success": true,
"data": [ /* items */ ],
"pagination": {
"page": 1,
"limit": 20,
"total": 137,
"totalPages": 7,
"hasMore": true
}
}
Error responses use the same envelope with success: false:
{
"success": false,
"message": "Validation failed",
"error": "Validation Error",
"statusCode": 400,
"timestamp": "2026-05-23T10:00:00.000Z",
"path": "/api/auth/register",
"method": "POST",
"data": [ /* validation details */ ]
}
Caveat: not every endpoint uses ResponseHandler. Legacy routes (mainly under /api/users, /api/marketplace legacy, /api/payment/decentralized, parts of /api/payment/shkeeper) return ad-hoc shapes such as { error: string } on failure or bare objects on success. When in doubt consult the per-endpoint response section in the service pages. The error middleware in shared/middleware/errorHandler.ts covers uncaught exceptions and emits { success: false, error, statusCode, stack? }.
Pagination conventions
Most list endpoints accept ?page=<n>&limit=<n> query params:
pagedefaults to1, 1-based.limitdefaults vary (20 for notifications/marketplace, 50 for user lists) and is capped (e.g. 100 for templates).- Server computes
total,totalPages, andhasMoreand returns them underpagination. - Some endpoints also accept
offset(e.g. payment lists) as a raw skip count.
Sort parameters: list endpoints commonly accept sortBy (default createdAt) and sortOrder (asc | desc, default desc).
Common query params
| Parameter | Used by | Meaning |
|---|---|---|
search |
users, templates, posts | Case-insensitive regex over title/name/email fields |
status |
payments, requests, disputes, notifications | Filter by entity state |
role |
users, contacts | Filter by buyer/seller/admin |
isActive |
users, templates | Boolean filter |
categoryId |
templates, requests | MongoId category filter |
unreadOnly |
notifications | Only unread items |
format |
payment export | json (default) or csv |
Rate limiting
Rate limiting is enabled as of the 2026-05-24 remediation. Four tiers are active in backend/src/app.ts:
| Tier | Scope | Limit | Window |
|---|---|---|---|
| Global | All /api/* routes (except /health and Request-Network webhooks) |
100 req | 15 min per IP |
| Auth | /api/auth/* |
10 req | 15 min per IP |
| Payment | /api/payment/* |
30 req | 15 min per IP |
| AI | /api/ai/* |
20 req | 15 min per IP |
The Express trust proxy setting is enabled in production so the real client IP is read from X-Forwarded-For (Nginx terminator).
CORS
CORS is configured globally in app.ts:
cors({
origin: process.env.FRONTEND_URL,
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
})
Only the configured FRONTEND_URL may make cross-origin requests with credentials. The SHKeeper configuration endpoint (GET /api/payment/shkeeper/config) overrides this with Access-Control-Allow-Origin: * because it is consumed by the SHKeeper payment widget hosted on another domain.
Uploaded files served from /uploads/* use helmet({ crossOriginResourcePolicy: { policy: "cross-origin" } }) so they can be embedded from the frontend domain.
Real-time channel
Socket.IO runs on the same HTTP server. All connections require a valid JWT passed in socket.auth.token (or socket.handshake.query.token). The server verifies the token with jwt.verify(config.jwtSecret) before allowing the connection. Room-join events enforce strict membership checks:
join-user-room— only the authenticated user may join their own room.join-request-room— buyer, preferred seller, or offer submitter only.join-seller-room/join-buyer-room— only the matching user id.join-chat-room— active participant only.
Clients join rooms via join-user-room, join-request-room, join-seller-room, join-buyer-room, join-chat-room. Full catalog: Socket Events.
Standard HTTP status codes
200 OK- success201 Created- resource created400 Bad Request- validation error401 Unauthorized- missing/invalid token403 Forbidden- role/ownership failure404 Not Found- resource or route missing409 Conflict- duplicate (email, review)423 Locked- account locked (auth flows)500 Internal Server Error- unhandled exception
See Error Codes for the app-specific codes returned in the error field.