BIO.RE
Content

Get Help Article (by slug)

Public read of a single help article by slug. PUBLISHED-only. HTML body server-side sanitized. Embedded category. 404 on missing/draft.

GET /api/v1/public/help/articles/:slug โ€” ๐ŸŒ Public ยท Rate limit: 60 req / minute

Returns a single published help article by slug. PUBLISHED-only โ€” DRAFT slugs return 404. The HTML content is server-side sanitized (same sanitizeHtml() helper as CMS pages โ€” strips <script>, <style>, <iframe>, inline on* event handlers).

Sanitization is defensive, not exhaustive. Same caveat as GET /public/pages/:slug and GET /public/blog/:slug โ€” strips obvious XSS but admin authors are still ultimately trusted. Use client-side sanitization (DOMPurify) for additional defense.

Request

Path parameters

ParamTypeNotes
slugstringHelp article slug (e.g. how-to-withdraw)

No body, no query params, no headers required.

Response headers

HeaderValue
Cache-Controlpublic, s-maxage=300, stale-while-revalidate=600

Response

200 OK โ€” ApiResponseOf<PublicHelpArticleDto>

{
  "success": true,
  "data": {
    "slug": "how-to-withdraw",
    "title": "How to Withdraw Funds",
    "content": "<p>Sanitized HTML content...</p>",
    "excerpt": "Step-by-step guide to withdrawing earnings.",
    "icon": "wallet",
    "readTimeMinutes": 5,
    "publishedAt": "2026-04-29T20:00:00.000Z",
    "category": { "name": "Payments & Billing", "slug": "payments" }
  }
}
FieldTypeNotes
slugstringEchoes the path param
titlestringArticle title
contentstringServer-side sanitized HTML body
excerptstring | nullShort summary
iconstring | nullIcon identifier
readTimeMinutesnumber | nullEstimated read time
publishedAtstring (ISO 8601) | nullWhen published
categoryobject{ name, slug } of the parent HelpCategory

Notable absence

The list endpoint returns isFeatured but the single-article endpoint does not โ€” the featured flag is a list-discovery concern, not relevant when you're already viewing the article.

Errors

HTTPcode / i18nKeyReason
404error.content.help_article_not_foundNo HelpArticle matches slug AND status = PUBLISHED
429(throttle)Rate limit exceeded (60 req/min)

Side effects

  1. prisma.helpArticle.findFirst({ where: { slug, status: PUBLISHED }, include: { category: true } }).
  2. Missing โ†’ throw help_article_not_found (404).
  3. HTML sanitization โ€” sanitizeHtml(article.content) (same helper as CMS pages and blog posts).
  4. Project category to { name, slug }.
  5. Return assembled object. No mutations.

Code samples

curl https://api.bio.re/api/v1/public/help/articles/how-to-withdraw
type HelpArticle = {
  slug: string;
  title: string;
  content: string;
  excerpt: string | null;
  icon: string | null;
  readTimeMinutes: number | null;
  publishedAt: string | null;
  category: { name: string; slug: string };
};

async function getHelpArticle(slug: string): Promise<HelpArticle> {
  const res = await fetch(`https://api.bio.re/api/v1/public/help/articles/${encodeURIComponent(slug)}`);
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'Help article fetch failed'), {
      code: json?.error?.code,
    });
  }
  return json.data;
}
import { useQuery } from '@tanstack/react-query';

export const contentKeys = {
  helpArticle: (slug: string) => ['content', 'help', 'article', slug] as const,
};

export function useHelpArticle(slug: string) {
  return useQuery({
    queryKey: contentKeys.helpArticle(slug),
    queryFn: async () => {
      const res = await fetch(`/api/v1/public/help/articles/${encodeURIComponent(slug)}`);
      const json = await res.json();
      if (!res.ok || !json.success) {
        throw Object.assign(new Error(json?.error?.message ?? 'Help article fetch failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
      return json.data as HelpArticle;
    },
    enabled: Boolean(slug),
    staleTime: 5 * 60_000,
  });
}

Try it

GET
/api/v1/public/help/articles/{slug}

Path Parameters

slug*string

Response Body

application/json

application/json

curl -X GET "https://loading/api/v1/public/help/articles/string"
{
  "success": true,
  "data": {
    "slug": "how-to-withdraw",
    "title": "How to Withdraw Funds",
    "content": "<p>Sanitized HTML content</p>",
    "excerpt": "string",
    "icon": "string",
    "readTimeMinutes": 0,
    "publishedAt": "2019-08-24T14:15:22Z",
    "category": {
      "slug": "payments",
      "name": "Payments & Billing"
    }
  }
}
{
  "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/content/public-content.controller.ts352โ€“373 (getHelpArticle), 29โ€“36 (sanitizeHtml)
DTO (response)apps/api-core/src/modules/content/dto/content-public-response.dto.ts260โ€“284 (PublicHelpArticleDto), 202โ€“208 (PublicHelpCategoryEmbedDto)
Serviceapps/api-core/src/modules/content/content.service.ts778โ€“783 (getPublishedHelpArticle)
Prisma modelspackages/prisma/prisma/schema.prismaHelpArticle (status = PUBLISHED), HelpCategory (joined)

On this page