BIO.RE
Themes

Get Active Theme

Public read of the platform's currently active client-web theme preset. Includes layout + assets (full theming surface). MUST pass ?target=CLIENT — default differs.

GET /api/v1/themes/active?target=CLIENT — 🌐 Public

Returns the currently active client-web theme preset — the one fan / creator bio pages render with right now. Includes the full theming surface (layout + assets) needed for live application — more fields than the list endpoint.

Always pass ?target=CLIENT explicitly. Omitting the query parameter does NOT default to client-web — pass it explicitly every time. The example URL above shows the canonical form.

preset: null is a normal response. When no theme is currently active for client-web (e.g. fresh install, admin temporarily disabled all presets), the response is { preset: null } — NOT a 404. Frontend should fall back to a built-in default theme bundled at build time when this happens.

Request

Query parameters

ParamTypeRequiredNotes
targetstringPass CLIENT literal (case-insensitive). Always send this — see callout above.

No headers required.

Response

200 OKApiResponseOf<ActiveThemeResponseDto>

{
  "success": true,
  "data": {
    "preset": {
      "id": "tp1a2b3c4-d5e6-7890-abcd-ef1234567890",
      "name": "Default Light",
      "slug": "default-light",
      "target": "CLIENT",
      "lightTokens": { "color": { "bg": "#FFFFFF", "fg": "#0F172A" } },
      "darkTokens": { "color": { "bg": "#0F172A", "fg": "#FFFFFF" } },
      "typography": { "fontFamily": "Inter, sans-serif" },
      "layout": { "maxWidth": "1280px" },
      "assets": { "logo": "https://cdn.bio.re/themes/default-light/logo.svg" },
      "publishedAt": "2026-04-29T20:00:00.000Z"
    }
  }
}

When no active client-web preset exists:

{
  "success": true,
  "data": {
    "preset": null
  }
}

preset fields

FieldTypeNotes
idstring (UUID)ThemePreset.id
namestringDisplay name
slugstringURL-friendly identifier
targetstringAlways "CLIENT" here (echoes the query)
lightTokens / darkTokensobjectJSON color/spacing/etc tokens
typographyobjectJSON typography settings
layoutobjectJSON layout settings (max-width, gutters, etc) — NOT in the list endpoint
assetsobjectJSON asset references (logo URLs, etc) — NOT in the list endpoint
publishedAtstring (ISO 8601) | nullWhen the preset was published

Stripped fields

status (always PUBLISHED+isActive here, filter excludes others), isActive (always true here), tokenSchema, description, thumbnail, createdBy, publishedBy, activatedBy, activatedAt, createdAt, updatedAt — internal-only.

Errors

This endpoint has no documented error responses. preset: null is the "no active preset" path; there's no 404.

Side effects

  1. prisma.themePreset.findFirst({ where: { target: 'CLIENT', isActive: true } }) (Prisma returns the first match — there's expected to be at most one active preset).
  2. Missing → return { preset: null }.
  3. Found → map to the 10-field sanitized projection (excludes internal metadata) and return { preset }.

Code samples

curl 'https://api.bio.re/api/v1/themes/active?target=CLIENT'
type ActiveThemePreset = {
  id: string;
  name: string;
  slug: string;
  target: 'CLIENT';
  lightTokens: object;
  darkTokens: object;
  typography: object;
  layout: object;
  assets: object;
  publishedAt: string | null;
};

async function getActiveTheme(): Promise<ActiveThemePreset | null> {
  const url = new URL('https://api.bio.re/api/v1/themes/active');
  url.searchParams.set('target', 'CLIENT');
  const res = await fetch(url);
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'Active theme fetch failed'), {
      code: json?.error?.code,
    });
  }
  return json.data.preset;
}
import { useQuery } from '@tanstack/react-query';

export const themeKeys = {
  active: () => ['themes', 'active'] as const,
};

export function useActiveTheme() {
  return useQuery({
    queryKey: themeKeys.active(),
    queryFn: async () => {
      const url = new URL('/api/v1/themes/active', window.location.origin);
      url.searchParams.set('target', 'CLIENT');
      const res = await fetch(url);
      const json = await res.json();
      if (!res.ok || !json.success) {
        throw Object.assign(new Error(json?.error?.message ?? 'Active theme fetch failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
      return json.data.preset as ActiveThemePreset | null;
    },
    // Active theme rarely flips during a session
    staleTime: 5 * 60_000,
  });
}

Try it

GET
/api/v1/themes/active

Query Parameters

target*string

Theme target (CLIENT or ADMIN)

Value in"CLIENT" | "ADMIN"

Response Body

application/json

curl -X GET "https://loading/api/v1/themes/active?target=CLIENT"
{
  "success": true,
  "data": {
    "preset": {
      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
      "name": "Default Light",
      "slug": "default-light",
      "target": "CLIENT",
      "lightTokens": {},
      "darkTokens": {},
      "typography": {},
      "layout": {},
      "assets": {},
      "publishedAt": "2019-08-24T14:15:22Z"
    }
  }
}

Source

SourcePathLines
Controllerapps/api-core/src/modules/theme-preset/theme-preset-public.controller.ts40–64 (getActive)
DTO (response)apps/api-core/src/modules/theme-preset/dto/theme-preset-response.dto.ts164–167 (ActiveThemeResponseDto), 127–157 (ActiveThemePresetDto)
Serviceapps/api-core/src/modules/theme-preset/theme-preset.service.ts139–143 (findActive(target))
Prisma modelpackages/prisma/prisma/schema.prismaThemePreset (filter target = CLIENT + isActive = true)

On this page