Coding agent documentation index Fetch the complete documentation index at: https://docs.worklittle.com/docs-agent-manifest.json Use this file to discover all available pages before exploring further.
SDK
TypeScript and Python clients for api.worklittle.com. Same key, same resources. Language tabs below.
Install
Requires Node 18+.
npm install worklittle
export WORKLITTLE_API_KEY="sk-wl-api01-..."
The same package is also published as @worklittle/sdk.
Authentication
Send your key as a bearer token. Create one under API keys in Worklittle Business.
Authorization: Bearer sk-wl-api01-...
The SDKs and CLI read WORKLITTLE_API_KEY. Prefer the env var over --api-key, which is visible in process lists.
Public job board reads and public survey submit need no key.
Quickstart
import { createWorklittle } from "worklittle";
const wl = createWorklittle(); // reads WORKLITTLE_API_KEY
const page = await wl.jobs.search({ q: "software engineer", limit: 3 });
console.log(page.data);
Filters match GET /jobs. Prefix a value with - to exclude it:
await wl.jobs.search({
title: "software engineer, -senior",
company: "-lucid-motors,-tesla",
limit: 10,
});
Client options: apiKey, baseUrl (default https://api.worklittle.com), fetch, maxRetries (default 3). Your key is sent to baseUrl, so only point it at hosts you trust.
Search > detail
const page = await wl.jobs.search({ q: "software engineer", limit: 3 });
const [first] = page.data as Array<{ job_id: string }>;
const job = await wl.jobs.get(first.job_id);
GET /jobs returns:
{
"data": [
{
"job_id": "...",
"title": "Software Engineer",
"company_name": "Example Co",
"location": "Remote"
}
],
"meta": { "next_cursor": "..." }
}
List rows are snippets. jobs.get returns the full posting. Pass meta.next_cursor as cursor for the next page. See Search jobs.
Board > apply
YOUR_ORG_SLUG is the employer slug in your careers URLs.
import { createWorklittle, type BoardJob } from "worklittle";
const wl = createWorklittle();
const company = "YOUR_ORG_SLUG";
const board = (await wl.boards.get(company)) as { jobs: BoardJob[] };
const ref = board.jobs[0].slug || board.jobs[0].id;
// The response wraps the job: { company, job, features, meta }.
const { job } = (await wl.boards.getJob(company, ref)) as { job: BoardJob };
// Splits `values` into built-in fields and custom answers using job.application_fields.
await wl.boards.submitApplication(company, job, {
name: "Alex Rivera",
email: "alex@example.com",
});
wl.boards.apply(company, ref, body) posts a raw body instead. When the board has similar-job alerts on, the body must include similar_job_alerts as true or false. See Embedded job board.
Candidates > profile
Requires a key with the jobs:applications scope.
const list = await wl.candidates.list({ limit: 10 });
const candidate = await wl.candidates.get("CANDIDATE_ID");
See Manage candidates.
Resources
| Method | HTTP | Docs | | --- | --- | --- | | `wl.boards.get` / `listJobs` / `getJob` / `apply` / `submitApplication` | `/business/jobs/company/:company/*` | [Public job board](/business/api/public-job-board) | | `wl.jobs.search` / `get` / `map` / `salaryAverage` / `suggestions` / `stats` / `saved` | `GET /jobs`, `/jobs/:id`, `/jobs/map`, `/jobs?salary_average=1`, `/jobs/suggestions`, `/jobs/stats`, `/jobs/saved` | [Search jobs](/business/api/search-jobs) | | `wl.companies.search` | `GET /companies` | [Search companies](/business/api/search-companies) | | `wl.stats.get` | `GET /jobs/stats` | [Search jobs](/business/api/search-jobs) | | `wl.apply.submit` | `POST /jobs/:id/apply` | [Apply for jobs](/business/api/apply-for-jobs) | | `wl.apply.startWithAi` / `getWithAiSession` / `continueWithAi` / `approveWithAiSubmit` / `stopWithAi` (also `start` / `status` / `stop`) | `POST /jobs/apply`, `GET /jobs/apply/:id`, `POST /jobs/apply/:id/stop`, `POST /v1/apply-with-ai/:id/continue`, `/v1/apply-with-ai/:id/approve-submit` | [Apply for jobs](/business/api/apply-for-jobs) | | `wl.appliedJobs.*` | `/jobs/applied`, `/jobs/saved` (`counts`) | [Apply for jobs](/business/api/apply-for-jobs) | | `wl.resumes.*` / `wl.coverLetters.*` | `POST /jobs/resumes`, `/jobs/cover-letters`, `/v1/draft-resumes`, `/v1/draft-cover-letters` (`draft`) | [Create resumes](/business/api/create-resumes) | | `wl.agent.listTools` / `runTool` | `/v1/agent/tools`, `/v1/agent/tool` | [MCP](/business/mcp) | | `wl.candidates.*` | `/candidates`, `/pipeline-stages` | [Manage candidates](/business/api/manage-candidates) | | `wl.employees.*` / `wl.organization.*` | `/employees`, `/company-organizations` | [Manage organization](/business/api/manage-organization) | | `wl.jobListings.*` | `/business/jobs` | [Post a job](/business/api/post-a-job) | | `wl.employerJobs.*` | `/jobs/post` | [Post a job](/business/api/post-a-job) | | `wl.surveys.*` | `/platform/surveys` | [Surveys](/business/api/surveys) | | `wl.documents.*` | `/platform/documents` | [Documents](/business/api/documents) | | `wl.attendance.*` | `/attendance`, `/business/attendance` | [Attendance](/business/api/attendance) | | `wl.webhooks.*` | `/webhooks`, `/webhook-deliveries` | [Webhooks](/business/webhooks/integration) | | `wl.email.*` / `wl.offers.*` | `/email-messages`, `/email/send`, `/offers` | [Manage candidates](/business/api/manage-candidates) | | `wl.usage.list` / `wl.billing.*` / `wl.limits.*` | `/usage`, `/billing/*`, `/limits` | [API keys](/business/get-started/api-keys) |
Every method returns the parsed JSON body. Query filters match the REST parameters.
Webhooks
import { verifyWebhookSignature } from "worklittle";
const ok = verifyWebhookSignature({
signatureHeader: req.headers["worklittle-webhook-signature"] as string,
timestamp: req.headers["worklittle-webhook-timestamp"] as string,
rawBody, // the unparsed request body string
secret: process.env.WORKLITTLE_WEBHOOK_SECRET!,
});
Rejects timestamps more than 300 seconds old (toleranceSeconds to change). See Webhook integration.
Errors
import { WorklittleError, PaymentRequiredError } from "worklittle";
try {
await wl.jobs.get("JOB_ID");
} catch (err) {
if (err instanceof PaymentRequiredError) {
// 402: fix billing before retrying
} else if (err instanceof WorklittleError) {
console.error(err.status, err.code, err.message, err.requestId);
}
}
| Status | Error class | Behavior | | --- | --- | --- | | 429 | `WorklittleError` | Retried up to `maxRetries`, waiting `Retry-After` | | 429 + `QUOTA_EXCEEDED` | `QuotaExceededError` | Monthly free quota used. Retried like any 429, then raised | | 402 | `PaymentRequiredError` | Not retried. Do not retry until billing is fixed | | 401 / 403 | `WorklittleError` | Invalid key or missing scope |
QuotaExceededError and PaymentRequiredError extend WorklittleError. Errors also carry documentationUrl and body.