Complete REST API reference — Fastify 5 · Drizzle ORM · Lucia Auth · Zod validation
v7.0 · April 2026
@teezu/types package; auto-compiled to JSON Schema for Fastifycurl -X GET https://api.teezu.online/api/v1/users/usr_abc123 \ -H "Authorization: Bearer <session_token>"
Session managed by Lucia Auth · cookies + Bearer fallback · Zod-validated bodies
Register a new user account. Validates with RegisterSchema from @teezu/types.
// Request body
{
"email": "user@example.com",
"username": "john_doe",
"password": "secureT33zu!123",
"role": "viewer" // "viewer" | "creator" | "provider"
}
// 201 Created
{
"userId": "usr_abc123",
"sessionToken": "sess_xyz...",
"user": { "id": "usr_abc123", "email": "user@example.com", "username": "john_doe", "role": "viewer" }
}
Authenticate and create a new Lucia session. Returns opaque session token + sets teezu_session cookie.
// Request body
{
"email": "user@example.com",
"password": "secureT33zu!123"
}
// 200 OK
{
"sessionToken": "sess_xyz...",
"expiresAt": "2026-05-01T12:00:00Z",
"user": { "id": "usr_abc123", "username": "john_doe", "role": "viewer" }
}
Invalidate the current session. Clears the session cookie server-side.
// No request body required // 204 No Content
Extend the current Lucia session. Returns a new expiresAt timestamp.
// 200 OK
{
"sessionToken": "sess_new...",
"expiresAt": "2026-05-15T12:00:00Z"
}
User records stored in users table via Drizzle ORM · PATCH uses partial Zod schema
Fetch a user by ID. Public fields only unless the requester is the owner or admin.
// 200 OK
{
"id": "usr_abc123",
"username": "john_doe",
"displayName": "John Doe",
"avatarUrl": "https://cdn.teezu.online/avatars/...",
"role": "viewer",
"createdAt": "2026-01-10T08:00:00Z"
}
Partial update of user fields. Validated with UpdateUserSchema.
// Request body (all fields optional)
{
"displayName": "Johnny",
"bio": "Content creator 🔥",
"avatarUrl": "https://..."
}
// 200 OK — returns updated user object
Extended public profile: stats, recent content, subscription tiers and social links.
Media stored in S3/Cloudinary · metadata in content table · AI moderation on upload
Personalized content feed. Supports cursor-based pagination.
// Query params
?limit=20&cursor=crs_abc&filter=all|premium|free
// 200 OK
{
"items": [ { "id": "cnt_001", "type": "image", "url": "...", "isPremium": false, ... } ],
"nextCursor": "crs_xyz",
"hasMore": true
}
Create new content entry. Accepts multipart/form-data for file uploads via Multer pipeline (S3 → thumbnail → AI check → DB).
// multipart/form-data fields
caption string
type "image" | "video" | "audio"
isPremium boolean
tierRequired "free" | "fan" | "superfan"
file File (binary)
// 201 Created
{
"contentId": "cnt_abc123",
"url": "https://cdn.teezu.online/...",
"thumbnailUrl": "https://cdn.teezu.online/thumbs/...",
"moderationStatus": "approved"
}
Fetch a single content item with metadata, stats, and presigned CDN URL.
Soft-delete content. Removes from feed; CDN asset scheduled for purge.
WebRTC-based streams · Socket.IO signalling · state machine: idle → live → ended
Create a new stream session. Returns stream credentials for WebRTC.
// Request body
{
"title": "Evening show 🔥",
"isPremium": true,
"tokenPrice": 10
}
// 201 Created
{
"streamId": "str_abc123",
"state": "idle",
"iceServers": [ { "urls": "stun:stun.teezu.online:3478" } ],
"socketRoom": "stream:str_abc123"
}
Get current stream metadata, state, viewer count and host info.
Transition stream state. Valid transitions: idle→live, live→frozen, live→ended, frozen→live.
// Request body
{
"state": "live" // "idle" | "live" | "frozen" | "ended"
}
// 200 OK
{
"streamId": "str_abc123",
"state": "live",
"startedAt": "2026-04-15T20:00:00Z"
}
REST for history · Socket.IO for realtime delivery · messages stored in messages table
List all conversations for the authenticated user, ordered by last message time.
// 200 OK
{
"conversations": [
{
"id": "conv_abc",
"participant": { "id": "usr_xyz", "username": "jane", "avatarUrl": "..." },
"lastMessage": { "content": "Hey!", "sentAt": "2026-04-14T18:30:00Z" },
"unreadCount": 2
}
]
}
Send a message. Persisted to DB and broadcast via Socket.IO send_message event.
// Request body
{
"content": "Hello! 👋",
"type": "text" // "text" | "image" | "tip" | "unlock"
}
// 201 Created
{
"messageId": "msg_001",
"conversationId": "conv_abc",
"content": "Hello! 👋",
"type": "text",
"sentAt": "2026-04-15T09:10:00Z"
}
In-app token economy · wallet balances in wallets table · escrow via WalletService
Get the authenticated user's current token balance.
// 200 OK
{
"balance": 4250,
"held": 200, // tokens in escrow (pending bookings)
"available": 4050,
"currency": "TZT"
}
Send tokens as a tip to a creator or during a stream. Triggers Socket.IO tip event.
// Request body
{
"recipientId": "usr_creator42",
"amount": 100,
"context": "stream", // "stream" | "chat" | "content"
"contextId": "str_abc123" // optional reference ID
}
// 200 OK
{
"transactionId": "txn_tip_001",
"newBalance": 4150,
"recipient": { "id": "usr_creator42", "username": "creator42" }
}
Initiate a token purchase via payment gateway. Returns a checkout URL.
// Request body
{
"packageId": "pkg_500", // predefined token package
"paymentMethod": "card" // "card" | "crypto" | "ideal"
}
// 200 OK
{
"checkoutUrl": "https://checkout.teezu.online/pay/sess_xyz",
"expiresAt": "2026-04-15T10:00:00Z"
}
AI module routes — mood detection, matching engine, generative responses
Detect mood / sentiment from a text or media input. Used to personalise feed and recommendations.
// Request body
{
"input": "Feeling adventurous tonight 🔥",
"type": "text" // "text" | "image_url"
}
// 200 OK
{
"mood": "adventurous",
"confidence": 0.91,
"tags": ["energetic", "social", "bold"]
}
Run the matching engine for the current user. Returns ranked creator / provider suggestions.
// Request body (all optional)
{
"limit": 10,
"filters": { "role": "provider", "tags": ["fitness"] }
}
// 200 OK
{
"matches": [
{ "userId": "usr_xyz", "score": 0.97, "reasons": ["shared interests", "high rating"] }
]
}
Generate AI-assisted content: captions, bio suggestions, chat openers.
// Request body
{
"type": "caption", // "caption" | "bio" | "opener"
"context": "sunset photo on the beach",
"tone": "playful"
}
// 200 OK
{
"generated": "Golden hour hits different when you're living your best life 🌅🔥",
"alternatives": ["Sun, sea, and good vibes only ✨", "The beach called — I answered 🐚"]
}
Provider profiles + booking flow · availability check → escrow → confirmation
List available providers. Supports filters and sorting.
// Query params
?category=fitness&minRating=4&sort=popularity&limit=20
// 200 OK
{
"providers": [
{ "id": "usr_prov1", "username": "pro_jane", "category": "fitness", "rating": 4.8, "tokenRate": 50 }
],
"total": 142
}
Full provider profile: bio, services, availability slots, reviews, token rate.
Book a provider session. Pipeline: availability check → wallet balance check → escrow (WalletService.holdFunds()) → booking record (pending).
// Request body
{
"slotId": "slot_2026041520", // from provider availability
"durationMinutes": 30,
"note": "Looking forward to it!"
}
// 201 Created
{
"bookingId": "bkg_abc123",
"status": "pending",
"provider": { "id": "usr_prov1", "username": "pro_jane" },
"slot": { "start": "2026-04-15T20:00:00Z", "end": "2026-04-15T20:30:00Z" },
"tokensHeld": 1500,
"confirmBy": "2026-04-15T18:00:00Z"
}
All errors follow the Fastify error shape with a code field for programmatic handling.
// Standard error body
{
"statusCode": 422,
"error": "Unprocessable Entity",
"code": "VALIDATION_ERROR",
"message": "email: Invalid email address",
"details": [ { "field": "email", "message": "Invalid email address" } ]
}
details[]Retry-After headerX-Request-Id headerImplemented via @fastify/rate-limit with a Redis store in production. Limits are per authenticated user (by session) or per IP for public routes.
// Rate limit response headers X-RateLimit-Limit: 100 X-RateLimit-Remaining: 42 X-RateLimit-Reset: 1744900800 Retry-After: 38 // only on 429