Get Trending Creators
Public trending creator list. Multi-factor scoring (7-day window) cached in Redis 15min. Falls back to totalMessages sort if scoring fails. CDN-cached 5min.
GET /api/v1/discover/trending โ ๐ Public ยท Rate limit: 60 req / minute ยท Kill-switched
Returns the platform's trending creators. Cached in Redis (15min TTL) so reads are constant-time after the first warm. Underlying scoring is a multi-factor signal computed over a 7-day window; on scoring-engine failure, the endpoint falls back to a simple totalMessages DESC sort.
Cached ranking is preserved on read. When the cache hits, the server fetches the listed creatorProfile rows by id and re-sorts in-memory to match the cached ranking. This means even if a creator's stats changed since the cache was warmed, their position in trending reflects the snapshot at warm-time โ not the live state.
limit clamps to admin-managed default. When ?limit is absent, the server reads discover.trending_count (default 10). When supplied, the value still goes through Min(1) / Max(50) validation.
Request
Query parameters
| Param | Type | Default | Validation | Notes |
|---|---|---|---|---|
limit | number | discover.trending_count (admin, default 10) | Min(1), Max(50), @Type(Number) | Number of trending creators to return |
No headers required.
Response headers
| Header | Value |
|---|---|
Cache-Control | public, s-maxage=300, stale-while-revalidate=600 |
Response
200 OK โ ApiResponseOf<CreatorListDto>
{
"success": true,
"data": {
"creators": [
{
"id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
"userId": "u1a2b3c4-d5e6-7890-abcd-ef1234567890",
"username": "topcreator",
"displayName": "Top Creator",
"avatarUrl": "https://cdn.bio.re/avatars/abc.webp",
"level": "GOLD",
"dmActive": true,
"totalFollowers": 50000
}
]
}
}| Field | Type | Notes |
|---|---|---|
creators | CreatorCardDto[] | Up to limit cards, ordered by trending rank (cached snapshot or live scoring) |
See Search for the full CreatorCardDto field reference.
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
400 | (DTO validation) | limit outside [1, 50] |
429 | (throttle) | Rate limit exceeded (60 req/min) |
503 | features.discover_disabled | Admin kill switch DISCOVER is active |
Side effects
- Resolve
count = limit ?? config.discover.trending_count ?? 10. - Cache lookup โ
redis.cacheGet('discover:trending:<count>'). Hit:- Fetch
creatorProfile.findMany({ where: id IN cached.ids AND active filter }). - In-memory re-sort to match cached id order.
- Return.
- Fetch
- Cache miss: try multi-factor scoring (
computeTrending). On failure: log warn + fallback tototalMessages DESC. - Map rows โ
toCard()and return.
Code samples
curl https://api.bio.re/api/v1/discover/trending
curl 'https://api.bio.re/api/v1/discover/trending?limit=20'async function getTrendingCreators(limit?: number): Promise<CreatorCard[]> {
const url = new URL('https://api.bio.re/api/v1/discover/trending');
if (limit) url.searchParams.set('limit', String(limit));
const res = await fetch(url);
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Trending fetch failed'), {
code: json?.error?.code,
});
}
return json.data.creators;
}import { useQuery } from '@tanstack/react-query';
export const discoverKeys = {
trending: (limit?: number) => ['discover', 'trending', limit ?? 'default'] as const,
};
export function useTrending(limit?: number) {
return useQuery({
queryKey: discoverKeys.trending(limit),
queryFn: async () => {
const url = new URL('/api/v1/discover/trending', window.location.origin);
if (limit) url.searchParams.set('limit', String(limit));
const res = await fetch(url);
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Trending fetch failed'), {
code: json?.error?.code,
i18nKey: json?.error?.i18nKey,
});
}
return json.data.creators as CreatorCard[];
},
staleTime: 5 * 60_000, // match the CDN s-maxage
});
}Try it
Query Parameters
Number of trending creators to return
1 <= value <= 50Response Body
application/json
curl -X GET "https://loading/api/v1/discover/trending"{
"success": true,
"data": {
"creators": [
{
"id": "cuid_creator_123",
"userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b",
"username": "johndoe",
"displayName": "John Doe",
"avatarUrl": "https://cdn.bio.re/avatars/abc.jpg",
"level": "BRONZE",
"dmActive": false,
"totalFollowers": 0
}
]
}
}Source
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/discover/discover.controller.ts | 43โ49 (trending) |
| DTO (request) | apps/api-core/src/modules/discover/dto/index.ts | 41โ44 (TrendingQueryDto) |
| DTO (response) | apps/api-core/src/modules/discover/dto/discover-response.dto.ts | 52โ55 (CreatorListDto) |
| Service | apps/api-core/src/modules/discover/discover.service.ts | 98โ124 (getTrending), computeTrending (scoring), getTrendingFallback (totalMessages sort) |
| Config | apps/api-core/src/modules/config/config.service.ts | discover.trending_count (admin-managed default 10) |
| Cache | Redis | discover:trending:<count> key, 15min TTL |
| Prisma model | packages/prisma/prisma/schema.prisma | CreatorProfile (active filter) |
Search Creators
Public creator search across username, displayName, and bio. PostgreSQL full-text search with ILIKE fallback. Cursor-based pagination, CDN-cached 5min/10min SWR.
Get Featured Creators
Public admin-curated featured creator list. Filtered by current time window (startsAt/endsAt) + creator active status. Ordered by admin-set position. CDN-cached 5min.