BIO.RE
Discover

Get Recently Viewed

Authenticated. Returns the calling user's recently viewed creators ordered by viewedAt DESC. Active-creator filter — inactive / suspended / vacationing creators are dropped from the read.

GET /api/v1/discover/history — 🔑 Bearer · Kill-switched

Returns the calling user's recently viewed creators, ordered by viewedAt DESC. Active-creator filter is applied on the read — even if the user previously viewed a creator who later went inactive / suspended / vacationing, that row is silently dropped from the response (the underlying RecentlyViewed row stays, but the join filters it out).

The list can be shorter than limit. If, say, you ask for 10 and 3 of them have gone inactive since you viewed them, you'll get 7 cards. There's no automatic top-up — the active filter runs on the join, not on the cursor pull.

Request

Query parameters

ParamTypeDefaultValidationNotes
limitnumberdiscover.recently_viewed_count (admin, default 10)Min(1), Max(50), @Type(Number)Server-additionally clamps to min(limit, 50)
HeaderRequiredNotes
Authorization: Bearer <accessToken>JWT from POST /auth/login

Response

200 OKApiResponseOf<CreatorListDto>

{
  "success": true,
  "data": {
    "creators": [
      {
        "id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
        "userId": "u1a2b3c4-d5e6-7890-abcd-ef1234567890",
        "username": "recent-creator",
        "displayName": "Recent Creator",
        "avatarUrl": "https://cdn.bio.re/avatars/abc.webp",
        "level": "BRONZE",
        "dmActive": true,
        "totalFollowers": 1500
      }
    ]
  }
}
FieldTypeNotes
creatorsCreatorCardDto[]Up to limit cards, ordered by recency. May be shorter than limit when previously-viewed creators have gone inactive.

See Search for the full CreatorCardDto field reference.

Errors

HTTPcode / i18nKeyReason
400(DTO validation)limit outside [1, 50]
401(guard)Missing / invalid bearer token
503features.discover_disabledAdmin kill switch DISCOVER is active

Side effects

  1. Resolve effectiveLimit = min(limit ?? config.discover.recently_viewed_count ?? 10, 50).
  2. recentlyViewed.findMany({ where: { userId }, orderBy: viewedAt desc, take: effectiveLimit }).
  3. Empty list → return { creators: [] }.
  4. creatorProfile.findMany({ where: { id IN recent.ids AND active filter }, include: user }) — note this drops inactive rows silently.
  5. Map to cards, return. No mutations.

Code samples

curl https://api.bio.re/api/v1/discover/history \
  -H "Authorization: Bearer $ACCESS_TOKEN"

curl 'https://api.bio.re/api/v1/discover/history?limit=20' \
  -H "Authorization: Bearer $ACCESS_TOKEN"
async function getRecentlyViewed(accessToken: string, limit?: number): Promise<CreatorCard[]> {
  const url = new URL('https://api.bio.re/api/v1/discover/history');
  if (limit) url.searchParams.set('limit', String(limit));
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'History fetch failed'), {
      code: json?.error?.code,
    });
  }
  return json.data.creators;
}
import { useQuery } from '@tanstack/react-query';

export const discoverKeys = {
  history: (limit?: number) => ['discover', 'history', limit ?? 'default'] as const,
};

export function useRecentlyViewed(limit?: number) {
  return useQuery({
    queryKey: discoverKeys.history(limit),
    queryFn: async () => {
      const url = new URL('/api/v1/discover/history', 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 ?? 'History fetch failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
      return json.data.creators as CreatorCard[];
    },
    staleTime: 30_000,
  });
}

Try it

GET
/api/v1/discover/history
AuthorizationBearer <token>

In: header

Query Parameters

limit?number

Number of recent views to return

Range1 <= value <= 50

Response Body

application/json

application/json

curl -X GET "https://loading/api/v1/discover/history"
{
  "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
      }
    ]
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Source

SourcePathLines
Controllerapps/api-core/src/modules/discover/discover.controller.ts90–96 (getHistory)
DTO (request)apps/api-core/src/modules/discover/dto/index.ts46–49 (HistoryQueryDto)
DTO (response)apps/api-core/src/modules/discover/dto/discover-response.dto.ts52–55 (CreatorListDto)
Serviceapps/api-core/src/modules/discover/discover.service.ts375–387 (getRecentlyViewed)
Configapps/api-core/src/modules/config/config.service.tsdiscover.recently_viewed_count (admin-managed default 10)
Prisma modelspackages/prisma/prisma/schema.prismaRecentlyViewed, CreatorProfile (active filter)

On this page