Jobs namespace

Reference for job discovery, details, similar jobs, applications, and resume uploads.

Use board.jobs to read published jobs and to run the native application flow. Job discovery and detail reads are public. apply accepts either a candidate session or an allowed guest application, while myApplication requires a candidate session.

Shared behavior

Every method returns the Board API wire body without reshaping it. A non-2xx response throws BoardApiError; inspect status, code, details, and requestId instead of matching the message.

The final FetchOptions argument passes signal, headers, cache, next, cf, and other fetch options through to fetch. List and search results include object, url, hasMore, nextCursor, and data. Job catalog responses can also include count, limit, offset, and gatedCount.

board.jobs.list

List published jobs. The default relevance sort uses the board’s featured ranking.

ts
board.jobs.list(
query?: JobsListQuery,
options?: FetchOptions,
): Promise<JobCardListEnvelope>

JobsListQuery accepts:

FieldTypeBehavior
cursorstringOpaque nextCursor from the previous response.
limitnumberPage size from 1 to 100.
offsetnumberJobs to skip. It takes precedence over cursor; offset + limit cannot exceed 10,000.
companyIdstring[]Up to 10 company IDs, matched with OR.
remoteOptionRemoteOption[]on_site, hybrid, or remote.
employmentTypeEmploymentType[]Employment types, matched with OR.
senioritySeniority[]Seniority levels, matched with OR.
sortJobSortrelevance, newest, or salary_high. An explicit sort unpins featured jobs.
locationstringPlace slug for a radius search. An unresolvable place is ignored.
radiusnumber10–250 km; defaults to 50 and is ignored without location.
categorystringCategory slug for a programmatic jobs page. An unresolvable category returns 404.
skillstringSkill slug for a programmatic jobs page. An unresolvable skill returns 404.
fieldsstringOnly +description is supported. It adds HTML description to each otherwise-slim card.

The response is JobCardListEnvelope: data contains PublicJobCard values and relatedSearches can suggest category or skill pages.

ts
const controller = new AbortController();
const page = await board.jobs.list(
{
limit: 20,
offset: 0,
remoteOption: ['remote', 'hybrid'],
location: 'london',
radius: 25,
sort: 'newest',
},
{ signal: controller.signal },
);
for (const job of page.data) {
console.log(job.title, job.links.public);
}
if (page.hasMore) {
console.log('Next cursor:', page.nextCursor);
}

Handle pagination_invalid_cursor, pagination_offset_too_large, taxonomy not-found errors, and search_unavailable. gatedCount reports jobs hidden from the current viewer; do not present it as another page of accessible results.

Related methods: board.jobs.search, board.companies.listJobs, and paginate.

board.jobs.retrieve

Retrieve one published job by slug.

ts
board.jobs.retrieve(
jobSlug: string,
query?: Record<string, never>,
options?: FetchOptions,
): Promise<PublicJob>

PublicJob includes job and company identity, description, application URL, employment and salary fields, resolved categories and skills, office locations, place hierarchy, remote-work requirements, custom-field values, and canonical public links. The SDK URL-encodes jobSlug and does not resolve custom-field labels; match customFieldValues keys to board.context().customFields.

ts
const job = await board.jobs.retrieve('senior-engineer');
console.log(job.title);
console.log(job.company?.name);
console.log(job.customFieldValues);

The method returns 404 when the board is unavailable or the slug does not identify a published job. Draft, expired, and archived jobs are not returned by this public read.

Related methods: board.jobs.similar, board.jobs.apply, and board.context for custom-field definitions.

board.jobs.search

Search published jobs with free text, facets, date bounds, and geo filters.

ts
board.jobs.search(
body: JobsSearchBody,
query?: Record<string, never>,
options?: FetchOptions,
): Promise<JobCardSearchEnvelope>

JobsSearchBody accepts optional query text up to 200 characters, sort, cursor, limit, offset, and filters. Filter arrays accept up to 10 values. filters.publishedAt accepts ISO 8601 gte and lte bounds; filters.location and filters.radius follow the list method’s geo rules.

ts
const controller = new AbortController();
const results = await board.jobs.search(
{
query: 'platform engineer',
sort: 'salary_high',
filters: {
employmentType: ['full_time'],
seniority: ['senior', 'lead'],
publishedAt: { gte: '2026-07-01T00:00:00.000Z' },
},
limit: 20,
},
undefined,
{ signal: controller.signal },
);
console.log(results.data, results.count, results.gatedCount);

This is a POST request, but it is a read operation. Invalid filters or pagination return 400; an unavailable search core returns search_unavailable with status 503.

Related methods: board.jobs.list and board.taxonomy.places.list.

board.jobs.similar

Return jobs related to a published job. The result excludes the source job and jobs at the same company.

ts
board.jobs.similar(
jobSlug: string,
query?: JobsSimilarQuery,
options?: FetchOptions,
): Promise<ListEnvelope<PublicJobCard>>

query.limit accepts 1–20 and defaults to 5.

ts
const { data } = await board.jobs.similar('senior-engineer', { limit: 5 });
for (const job of data) {
console.log(job.title);
}

An empty data array is a valid result. A missing source job returns 404; similarity infrastructure failure returns search_unavailable with status 503.

Related methods: board.jobs.retrieve and board.companies.similar.

board.jobs.apply

Submit a native application. Signed-in candidates can omit name and email; guests must supply them and can apply only when the board permits guest applications. Repeating the same application is idempotent and returns the existing Application.

ts
board.jobs.apply(
jobSlug: string,
body?: ApplyBody,
options?: FetchOptions,
): Promise<Application>

ApplyBody contains optional name, email, and coverNote fields.

ts
const application = await board.jobs.apply('senior-engineer', {
name: 'Avery Chen',
email: 'avery@example.com',
coverNote: 'I build reliable developer platforms.',
});
console.log(application.id, application.status);

The returned Application includes its ID, candidate-facing status, timestamps, candidate facts, optional resume filename, and a job summary. Handle applications_guest_not_allowed (403), applications_job_not_found (404), and applications_external_apply_only (422). Use the job’s applicationUrl or the resolveApplyAction helper to branch between native and external apply before submitting.

Related methods: board.jobs.uploadApplicationResume and board.jobs.myApplication.

board.jobs.uploadApplicationResume

Attach a resume to an existing native application. The SDK creates the multipart FormData body.

ts
board.jobs.uploadApplicationResume(
jobSlug: string,
file: Blob,
opts?: { applicationId?: string },
options?: FetchOptions,
): Promise<Application>

Signed-in candidates target their own application and omit applicationId. A guest passes the ID returned by board.jobs.apply.

ts
const application = await board.jobs.apply('senior-engineer', {
name: 'Avery Chen',
email: 'avery@example.com',
});
const updated = await board.jobs.uploadApplicationResume(
'senior-engineer',
resumeFile,
{ applicationId: application.id },
);
console.log(updated.resumeFilename);

Empty or malformed files return applications_resume_invalid_file with status 400. Files over 10 MB return 413. Unsupported types or a magic-byte mismatch return 415. A missing or inaccessible application returns applications_not_found with status 404. Do not set content-type yourself; the runtime must add the multipart boundary.

Related method: board.jobs.apply.

board.jobs.myApplication

Retrieve the authenticated candidate’s application for one job.

ts
board.jobs.myApplication(
jobSlug: string,
options?: FetchOptions,
): Promise<Application>
ts
import { isNotFound } from '@cavuno/board';
try {
const application = await board.jobs.myApplication('senior-engineer');
console.log(application.status);
} catch (error) {
if (isNotFound(error)) {
console.log('The candidate has not applied to this job.');
} else {
throw error;
}
}

This method requires a board-user access token. It returns 401 for a missing, invalid, or expired token; 403 when the token belongs to another board; 404 for a missing board, job, or application; and 429 when the per-user rate limit is exceeded. A 404 application is an expected “not applied” state, not necessarily a broken job page.

Related methods: board.jobs.apply and board.me.applications for the candidate’s full application history.