BIO.RE
Creator

Get Creator Dashboard

Earnings + level + wallet + DM + response-rate summary in a single response. Computed from CreatorProfile, Wallet, PayoutRequest, Message, SocialAccount, and ConfigService thresholds.

GET /api/v1/creators/dashboard — 🔑 Bearer

Returns the full creator dashboard payload — level + commission rate, lifetime totals, wallet balance + frozen flag, pending payouts count, DM config, response rate (computed from message statuses), next-level progress + remaining requirements, and hasSocialAccounts flag for the onboarding nudge. Heavy aggregate read — call once on dashboard mount and cache.

commissionRate is admin-managed. Per-level commission rates are stored in ConfigService keys (creator.commission_bronze, creator.commission_silver, etc) with a 20% default. The response includes the rate that applies to this creator's current level — not a list of all rates.

Response rate semantics. responseRate = round((COMPLETED + REPLIED) / (COMPLETED + REPLIED + REJECTED + EXPIRED) * 100). Pending / in-flight messages are not counted because the creator hasn't yet had a chance to act. Returns 100 when there are zero resolvable messages (so a brand-new creator doesn't start at 0%).

Request

No body, no params.

HeaderRequiredNotes
Authorization: Bearer <accessToken>JWT from POST /auth/login

Response

200 OKApiResponseOf<DashboardResponseDto>

{
  "success": true,
  "data": {
    "level": "BRONZE",
    "commissionRate": 20,
    "totalMessages": 47,
    "totalEarnings": "1250.00",
    "walletBalance": "350.00",
    "walletFrozen": false,
    "pendingPayouts": 1,
    "dmActive": true,
    "dmType": "SINGLE_PAY",
    "dmPrice": "5.00",
    "responseRate": 95,
    "nextLevel": "SILVER",
    "nextLevelProgress": 47,
    "nextLevelRequirements": {
      "messages": { "current": 47, "required": 100 },
      "earnings": { "current": 1250, "required": 5000 }
    },
    "hasSocialAccounts": true,
    "avatarUrl": "https://cdn.bio.re/avatars/abc.webp"
  }
}

Fields

FieldTypeNotes
levelenumBRONZE / SILVER / GOLD / PLATINUM
commissionRatenumberPercentage (e.g. 20 = 20%). Pulled from creator.commission_<level> admin config; defaults to 20 if unset.
totalMessagesnumberLifetime message count (CreatorProfile.totalMessages)
totalEarningsstring (decimal)Lifetime earnings (decimal as string for precision)
walletBalancestring (decimal) | numberFrom Wallet.balance where type = CREATOR; falls back to 0 if no wallet row exists
walletFrozenbooleanWallet.frozentrue blocks payout requests
pendingPayoutsstring | numberCount of PayoutRequest rows with status = PENDING for this creator
dmActive / dmType / dmPriceboolean / enum | null / string | nullMirrors CreatorProfile.dm* fields
responseRatenumberInteger 0–100 (see Response rate callout above)
nextLevelenum | nullOne step above level; null when already PLATINUM
nextLevelProgressnumberInteger 0–100. Computed as min(messageProgress, earningsProgress) — both gates must be met.
nextLevelRequirementsobject | null{ messages: { current, required }, earnings: { current, required } }. null when nextLevel is null.
hasSocialAccountsbooleantrue if count(SocialAccount where userId) > 0
avatarUrlstring | nullMirror of User.avatarUrl

Errors

HTTPcode / i18nKeyReason
401(guard)Missing / invalid bearer token
404creator.dashboard.not_foundNo CreatorProfile for this user — call POST /creators/upgrade first

Side effects

  1. Lookup CreatorProfile by userId; throw not_found if missing.
  2. In parallel (Promise.all): read Wallet, count PayoutRequest PENDING, read User.avatarUrl, count SocialAccount, count messages with status IN (COMPLETED, REPLIED) ("responded"), count messages with status IN (COMPLETED, REPLIED, REJECTED, EXPIRED) ("resolvable").
  3. Read creator.commission_<level> from ConfigService (default 20).
  4. Compute responseRate = totalResolvable > 0 ? round(responded / totalResolvable * 100) : 100.
  5. Compute nextLevel + nextLevelProgress + nextLevelRequirements via calculateLevelProgress():
    • Reads creator.<nextLevel>_min_messages + creator.<nextLevel>_min_earnings from ConfigService (with built-in defaults per level).
    • Progress = min(messageProgress, earningsProgress) (both gates).
  6. Return assembled object. No mutations — pure read.

Code samples

curl https://api.bio.re/api/v1/creators/dashboard \
  -H "Authorization: Bearer $ACCESS_TOKEN"
type CreatorLevel = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINUM';

type LevelRequirementDetail = {
  current: number;
  required: number;
};

type Dashboard = {
  level: CreatorLevel;
  commissionRate: number;
  totalMessages: number;
  totalEarnings: string;
  walletBalance: string | number;
  walletFrozen: boolean;
  pendingPayouts: string | number;
  dmActive: boolean;
  dmType: 'FREE' | 'SINGLE_PAY' | 'PER_MESSAGE' | null;
  dmPrice: string | null;
  responseRate: number;
  nextLevel: CreatorLevel | null;
  nextLevelProgress: number;
  nextLevelRequirements: { messages: LevelRequirementDetail; earnings: LevelRequirementDetail } | null;
  hasSocialAccounts: boolean;
  avatarUrl: string | null;
};

async function getDashboard(accessToken: string): Promise<Dashboard> {
  const res = await fetch('https://api.bio.re/api/v1/creators/dashboard', {
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'Dashboard fetch failed'), {
      code: json?.error?.code,
    });
  }
  return json.data;
}
import { useQuery } from '@tanstack/react-query';

export const creatorKeys = {
  dashboard: () => ['creators', 'dashboard'] as const,
};

export function useDashboard() {
  return useQuery({
    queryKey: creatorKeys.dashboard(),
    queryFn: async () => {
      const res = await fetch('/api/v1/creators/dashboard');
      const json = await res.json();
      if (!res.ok || !json.success) {
        throw Object.assign(new Error(json?.error?.message ?? 'Dashboard fetch failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
      return json.data as Dashboard;
    },
    staleTime: 30_000, // 30s — dashboard is action-driven
  });
}

Try it

GET
/api/v1/creators/dashboard
AuthorizationBearer <token>

In: header

Response Body

application/json

application/json

application/json

curl -X GET "https://loading/api/v1/creators/dashboard"
{
  "success": true,
  "data": {
    "level": "BRONZE",
    "commissionRate": 0.2,
    "totalMessages": 47,
    "totalEarnings": "1250.00",
    "walletBalance": "0.00",
    "walletFrozen": true,
    "pendingPayouts": "0.00",
    "dmActive": true,
    "dmType": "FREE",
    "dmPrice": "5.00",
    "responseRate": 95.5,
    "nextLevel": "BRONZE",
    "nextLevelProgress": 0.47,
    "nextLevelRequirements": {
      "messages": {
        "current": 47,
        "required": 100
      },
      "earnings": {
        "current": 47,
        "required": 100
      }
    },
    "hasSocialAccounts": true,
    "avatarUrl": "string"
  }
}
{
  "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"
  }
}
{
  "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/creator/creator.controller.ts94–101 (getDashboard)
DTO (response)apps/api-core/src/modules/creator/dto/creator-client-response.dto.ts343–391 (DashboardResponseDto), 321–339 (nested LevelRequirementDetailDto, NextLevelRequirementsDto)
Serviceapps/api-core/src/modules/creator/creator.service.ts750–812 (getCreatorDashboard), 818–858 (calculateLevelProgress)
Config keysapps/api-core/src/modules/config/config.service.tscreator.commission_<level>, creator.<level>_min_messages, creator.<level>_min_earnings (admin-managed)
Prisma modelspackages/prisma/prisma/schema.prismaCreatorProfile, Wallet, PayoutRequest, Message (statuses COMPLETED/REPLIED/REJECTED/EXPIRED), SocialAccount, User.avatarUrl

On this page