Top-level methods

Reference for board context, SEO infrastructure, the raw client, and shared response conventions.

The SDK has two top-level reads and one raw request escape hatch. Namespace methods use the same underlying BoardClient pipeline.

board.context()

ts
context(options?: FetchOptions): Promise<PublicBoard>

Returns the public configuration needed to build the board shell:

FieldUse
id, slug, nameBoard identity. id is immutable; slug can change.
languageRequired input for SDK display-formatting helpers.
logoUrl, primaryDomain, showCavunoBrandingPublic brand and domain state.
featuresBoolean gates for alerts, candidates, employers, blog, talent, registration wall, password protection, public submission, paywall, and impressum.
talentDirectoryVisibilityoff, public, or employers_only. Use this instead of the public-only talent boolean when constructing navigation.
analyticsPublic analytics IDs and the cookie-consent requirement.
theme, themeSnapshotHashRuntime theme data and doctor’s migrated-theme freshness hash.
customFields, labels, footerJob-field definitions, operator copy overrides, and public footer configuration.
sandboxPlatform sandbox marker. Only doctor’s opted-in write probes should use it.
ts
const context = await board.context({ cache: 'force-cache' });
if (context.features.blog) {
// Register or render the public blog route.
}

Context is public and can normally use a shared cache. Feature flags guide presentation; they do not replace API authorization or entitlement enforcement.

board.seo()

ts
seo(options?: FetchOptions): Promise<BoardSeo>

Returns public infrastructure configuration:

  • canonicalBase for canonical links and the robots.txt sitemap line.
  • adsTxt and indexNowKey, each nullable.
  • googleSiteVerification, nullable.
  • Absolute icon URLs for ICO, SVG, Apple Touch, 192, 512, and maskable 512 variants.
  • Manifest name and themeColor.
ts
const seo = await board.seo({ cache: 'force-cache' });
export function adsTxtResponse() {
if (seo.adsTxt === null) return new Response('Not found', { status: 404 });
return new Response(seo.adsTxt, {
headers: { 'content-type': 'text/plain; charset=utf-8' },
});
}

board.seo() does not create page metadata or JSON-LD. Those pure builders live in @cavuno/board/seo.

board.client.fetch()

ts
fetch<T>(path: string, options?: FetchOptions): Promise<T>

Use the raw client for a live board-relative endpoint that does not yet have a namespace method. Prefer namespace methods when available because their bodies, queries, and responses are generated from the API contract.

ts
interface BoardStats {
object: 'board_stats';
activeJobs: number;
}
const stats = await board.client.fetch<BoardStats>('/custom/stats', {
query: { period: '30d' },
signal: AbortSignal.timeout(5_000),
});

The path is appended below /v1/boards/{identifier}. It must begin with / to produce the intended route. The generic type is an application assertion—the raw client does not validate the response at runtime.

Query behavior

Queries must be flat objects. Arrays serialize as repeated keys, preserving order:

ts
await board.client.fetch('/custom/jobs', {
query: {
remoteOption: ['remote', 'hybrid'],
cursor: null,
limit: 20,
},
});
// ?remoteOption=remote&remoteOption=hybrid&limit=20

null and undefined are omitted. Other values are converted with String(value). Nested objects are not recursively encoded.

Body and response behavior

  • Ordinary bodies are JSON-stringified and receive content-type: application/json.
  • Strings, URLSearchParams, FormData, Blob, ArrayBuffer, and ReadableStream are sent unchanged.
  • A successful HTTP 204 resolves to undefined without parsing.
  • Other successful responses are parsed as JSON.
  • Every non-2xx response throws BoardApiError; an invalid or non-JSON error body becomes unknown_error.
  • There is no automatic retry, response validation, or 401 refresh.

Shared list envelopes

List methods return ListEnvelope<T> and searches return SearchEnvelope<T>:

ts
const page = await board.jobs.list({ limit: 20 });
page.object; // "list"
page.data; // PublicJobCard[]
page.hasMore; // boolean
page.nextCursor; // string | null

Jobs catalog envelopes can also contain count, limit, offset, and gatedCount. Consumers must ignore unknown additive response fields. Echo nextCursor instead of inspecting it; it is opaque.

Verify the behavior

Use a deliberate 204 endpoint and a deliberate missing path in development. Confirm that the first resolves undefined, while the second throws BoardApiError and retains its status, code, raw envelope, and request ID.