API Reference (9 files updated): - Marketplace API: corrected offer endpoints (scoped under /purchase-requests/:id/offers), marked phantom /search /stats /seller/:sellerId /withdraw routes as NOT IMPLEMENTED, documented PUT→PATCH mismatches, removed invalid SellerOffer 'active' status - Dispute API: corrected resolve schema (action enum), categories (no 'fraud'), removed 'under_review' status, added security callouts (3 unguarded endpoints), route shadowing documented, all socket events marked as TODO stubs - Notification API: corrected mark-all-read method+path, fixed broken GET /:id, added unread-count-update event, 90-day TTL documented - Payment API: /create→/save, removed 10+ phantom endpoints, fixed release/refund paths (no /shkeeper/ segment), added 3 unauthenticated endpoint security warnings, stats undercounting documented, export privilege gap documented - Authentication API: 8-digit→6-digit code, no-complexity warning on reset-with-code, rate limiter counts all attempts, passkey stub claims removed, deleteAccount bug noted - Admin API: PUT→PATCH bug documented, wrong status values documented, hard vs soft delete clarified, scanner no-auth security bug, 3 NOT IMPLEMENTED endpoints - Chat API: file upload wrong endpoint bug, archive PUT→PATCH bug, rate limits added - Points API: corrected redeem schema, referral triggers on 'completed' only, leaderboard period ignored, removed 'refund' PointTransaction type - Socket Events: removed request-cancelled, notification-read; added unread-count-update; dispute events all stubs; referral-signup is auth-domain not points-domain Data Models (3 files updated): - SellerOffer: removed 'active' from status enum, withdrawOffer() is dead code - PurchaseRequest: added pending_payment/active statuses, added 'urgent' urgency, corrected description minimum (5 chars), removed finalized/archived - Dispute: corrected action enum, categories (no fraud), removed under_review, security callout on unguarded status/resolve endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
156 lines
6.1 KiB
Markdown
156 lines
6.1 KiB
Markdown
---
|
|
title: Points API
|
|
tags: [api, points, reference]
|
|
---
|
|
|
|
# Points API
|
|
|
|
> **Last updated:** 2026-05-29 — aligned with code (see [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md))
|
|
|
|
Endpoints live under `/api/points/*`. The router is [`backend/src/routes/pointsRoutes.ts`](../../backend/src/routes/pointsRoutes.ts), delegating to [`PointsController`](../../backend/src/controllers/pointsController.ts) and `PointsService` ([`backend/src/services/points/PointsService.ts`](../../backend/src/services/points/PointsService.ts)). The router applies `authenticateToken` globally — every endpoint requires `Bearer JWT`.
|
|
|
|
Models: [[PointTransaction]], [[LevelConfig]]. Points are minted automatically by the platform (referral signup, successful purchases, reviews) and can be redeemed for discounts or marketplace credits. Levels progress as the user's lifetime points cross configured thresholds.
|
|
|
|
> **Note on `PointTransaction.type`** — Valid values are `earn | spend | expire` only. There is **no** `refund` type; a financial refund does not create a points transaction.
|
|
|
|
## Balance and history
|
|
|
|
### GET /api/points/my-points
|
|
|
|
**Description:** Caller's current balance, lifetime totals, current level, referral code, and progress to next level.
|
|
**Auth required:** Bearer JWT
|
|
**Response 200:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"balance": 320,
|
|
"lifetimePoints": 1280,
|
|
"level": { "name": "silver", "tier": 2, "minPoints": 1000, "perks": [...] },
|
|
"nextLevel": { "name": "gold", "tier": 3, "minPoints": 2500, "pointsToGo": 1220 },
|
|
"referralCode": "ABCD1234",
|
|
"referralsCount": 4
|
|
}
|
|
}
|
|
```
|
|
|
|
### GET /api/points/transactions
|
|
|
|
**Description:** Paginated point ledger.
|
|
**Auth required:** Bearer JWT
|
|
**Query params:**
|
|
- `page` (default 1), `limit` (default 20)
|
|
- `type` (`earn` | `spend` | `expire` | `admin_grant` | `admin_deduct`) — note: `redeem`, `referral`, `purchase`, `review` are **not** valid filter values
|
|
- `from` / `to` (ISO dates)
|
|
**Response 200:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"transactions": [PointTransaction, ...],
|
|
"pagination": { "page": 1, "limit": 20, "total": 17, "hasMore": false }
|
|
}
|
|
}
|
|
```
|
|
|
|
> ⚠️ **Missing frontend pages** — `/dashboard/points/transactions`, `/dashboard/points/referrals`, and `/dashboard/points/levels` are referenced in documentation but **do not exist** in the frontend. Users cannot access these views through the UI.
|
|
|
|
### GET /api/points/referrals
|
|
|
|
**Description:** Users referred by the caller plus the points earned from each.
|
|
**Auth required:** Bearer JWT
|
|
**Response 200:** `{ success, data: { referrals: [{ userId, name, joinedAt, pointsEarned, status }] } }`
|
|
|
|
> ⚠️ **Missing frontend page** — `/dashboard/points/referrals` does not exist.
|
|
|
|
### GET /api/points/levels
|
|
|
|
**Description:** Public list of every configured level (from [[LevelConfig]]). Used by the marketing / levels page.
|
|
**Auth required:** Bearer JWT (but data is non-sensitive)
|
|
**Response 200:** `{ success, data: { levels: [LevelConfig, ...] } }`
|
|
|
|
> ⚠️ **Missing frontend page** — `/dashboard/points/levels` does not exist.
|
|
|
|
### GET /api/points/leaderboard
|
|
|
|
**Description:** Top referrers by referral count and points earned. Used for community displays.
|
|
**Auth required:** Bearer JWT
|
|
**Query params:** `limit` (default 10), `period` (`all` | `month` | `week`)
|
|
**Response 200:** `{ success, data: { entries: [{ userId, name, avatar, referrals, pointsEarned }] } }`
|
|
|
|
> ⚠️ **Known limitation** — The `period` query parameter (`all` | `month` | `week`) is **silently ignored** by the backend. The leaderboard always returns all-time results regardless of the value passed.
|
|
|
|
## Mutations
|
|
|
|
### POST /api/points/redeem
|
|
|
|
**Description:** Redeem points against an in-progress purchase. Server validates available balance and configured redemption rate.
|
|
**Auth required:** Bearer JWT
|
|
**Request body:**
|
|
```ts
|
|
{
|
|
pointsToUse: number; // points to redeem
|
|
purchaseRequestId: string; // the in-progress purchase to apply the discount to
|
|
}
|
|
```
|
|
**Response 200:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"transaction": { /* PointTransaction */ },
|
|
"discount": { "creditAmount": 3.20, "currency": "USD" },
|
|
"remainingPoints": 0
|
|
}
|
|
}
|
|
```
|
|
**Errors:** `400` insufficient balance, validation; `409` redemption already claimed.
|
|
|
|
### POST /api/points/generate-referral-code
|
|
|
|
**Description:** Generates (or rotates) the caller's unique referral code. Idempotent if the user already has one and `force` is not set.
|
|
**Auth required:** Bearer JWT
|
|
**Request body:** `{ force?: boolean }`
|
|
**Response 200:** `{ success, data: { referralCode: "ABCD1234", link: "https://amn.gg/r/ABCD1234" } }`
|
|
|
|
The short link redirect (`GET /r/:code`) is mounted at the app root in `app.ts` and forwards to `${FRONTEND_URL}/auth/jwt/sign-up?ref=<code>`.
|
|
|
|
## Admin
|
|
|
|
### POST /api/points/admin/add
|
|
|
|
**Description:** Manually grant (or deduct, with negative amount) points to a user. Logged as a `PointTransaction` with `type: "admin_grant"` / `"admin_deduct"`.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Request body:**
|
|
```ts
|
|
{
|
|
userId: string;
|
|
amount: number; // positive = grant; negative = deduct
|
|
reason: string; // mandatory free-text reason
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
```
|
|
**Response 200:** `{ success, data: { transaction, newBalance } }`
|
|
**Errors:** `403` non-admin, `404` target user not found, `400` would go below zero.
|
|
|
|
## Side effects and real-time
|
|
|
|
`PointsService` emits Socket.IO events on level-up and referral rewards:
|
|
|
|
- `level-up` on `user-<userId>` when a transaction crosses a level threshold.
|
|
- `referral-reward` on `user-<referrerId>` when a referred user triggers a reward. This fires only when the referred user's purchase reaches **`'completed'`** status — it does **not** fire on `'delivered'`.
|
|
|
|
`authController` (not `PointsService`) emits:
|
|
|
|
- `referral-signup` on `user-<referrerId>` when a referred user completes registration.
|
|
|
|
See [[Socket Events]] for payload shape.
|
|
|
|
## Related
|
|
|
|
- [[PointTransaction]]
|
|
- [[LevelConfig]]
|
|
- [[Points and Levels Flow]]
|
|
- [[Referral Flow]]
|
|
- `backend/POINTS_MIGRATION.md` (legacy migration notes)
|