Record Profile View
Authenticated. Upserts a RecentlyViewed row for the (user, creator) pair — refreshes viewedAt on subsequent visits. Returns whether the row was recorded.
POST /api/v1/discover/history/:creatorId — 🔑 Bearer · Kill-switched
Records that the calling user viewed a creator's profile. Upsert semantics: first view creates the row, subsequent visits update the viewedAt timestamp (move-to-front behavior in the recently-viewed list). The body is empty — userId comes from the bearer token, creatorId from the path.
Move-to-front, not append. A repeat view of the same creator doesn't insert a duplicate row — it bumps the existing row's viewedAt so it surfaces at the top of GET /discover/history. The compound unique key (userId, creatorId) makes this safe.
Validates the creator exists. The server checks creatorProfile.findUnique for the supplied creatorId before upserting; missing → 404 creator_not_found. There's no inactive-creator filter here — even suspended / vacationing creators can be recorded as viewed (the active-only filter applies on the read side, see GET /discover/history).
Request
Path parameters
| Param | Type | Notes |
|---|---|---|
creatorId | string | The CreatorProfile.id being viewed (raw string, no UUID pipe) |
No body.
| Header | Required | Notes |
|---|---|---|
Authorization: Bearer <accessToken> | ✓ | JWT from POST /auth/login |
Response
200 OK — ApiResponseOf<RecordViewResultDto>
{
"success": true,
"data": {
"recorded": true
}
}| Field | Type | Notes |
|---|---|---|
recorded | boolean | Always true on 200 — both create and update paths return this |
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
401 | (guard) | Missing / invalid bearer token |
404 | discover.creator_not_found | No CreatorProfile with this id |
503 | features.discover_disabled | Admin kill switch DISCOVER is active |
Side effects
prisma.creatorProfile.findUnique({ where: { id: creatorId }, select: { id: true } }). Missing → throwcreator_not_found.prisma.recentlyViewed.upsert({ where: { userId_creatorId }, update: { viewedAt: new Date() }, create: { id, userId, creatorId } }).- Return
{ recorded: true }.
Code samples
curl -X POST https://api.bio.re/api/v1/discover/history/c1a2b3c4-d5e6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer $ACCESS_TOKEN"async function recordCreatorView(accessToken: string, creatorId: string): Promise<void> {
const res = await fetch(`https://api.bio.re/api/v1/discover/history/${creatorId}`, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
});
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Record view failed'), {
code: json?.error?.code,
});
}
}import { useMutation, useQueryClient } from '@tanstack/react-query';
export function useRecordCreatorView() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (creatorId: string) => {
const res = await fetch(`/api/v1/discover/history/${creatorId}`, { method: 'POST' });
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Record view failed'), {
code: json?.error?.code,
i18nKey: json?.error?.i18nKey,
});
}
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['discover', 'history'] });
},
});
}Try it
Authorization
bearer In: header
Path Parameters
Response Body
application/json
application/json
curl -X POST "https://loading/api/v1/discover/history/string"{
"success": true,
"data": {
"recorded": true
}
}{
"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
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/discover/discover.controller.ts | 80–88 (recordView) |
| DTO (response) | apps/api-core/src/modules/discover/dto/discover-response.dto.ts | 60–63 (RecordViewResultDto) |
| Service | apps/api-core/src/modules/discover/discover.service.ts | 364–373 (recordView) |
| Prisma models | packages/prisma/prisma/schema.prisma | RecentlyViewed (compound unique userId_creatorId), CreatorProfile (existence check) |
Browse by Category / Platform
Public creator browse by platform (Instagram / X / etc) AND optional content category. Three sort modes (recent / popular / rating). DM-type filter. Cursor pagination.
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.