Manage Workable jobs, candidates, pipeline stages, members and webhook subscriptions.
Workable ships in the w6w first-party pack. It declares 15 actions, 3 health checks, and the host runs its code in a sandbox that never sees the credential.
io.w6w.workableWorkable is an applicant tracking system, and this app covers the recruiting loop over its own SPI v3 API: listing and reading jobs and the pipeline stages configured on them, listing, reading, creating and updating candidates, moving a candidate to another stage or disqualifying them, reading a candidate’s activity stream, listing account members and disqualification reasons, and managing webhook subscriptions.
Workable has no single API host — every account gets its own subdomain (https://<subdomain>.workable.com/spi/v3/...) — so the subdomain is collected once at connect time as a Connection field, the same posture this pack already uses for Zendesk and Gorgias, rather than a fixed hostname in the manifest.
Good for routing an external event — a careers-page submission, a referral, an assessment result — into a new Workable candidate, moving candidates between pipeline stages based on a signal from another system, syncing pipeline state elsewhere, or reacting to a candidate or employee event via a registered webhook instead of polling.
Out of scope for this first version: the HR/Employee endpoints (employees, time off, time tracking, performance reviews, onboarding), requisitions and offers, and the Job Board/Assessment/Video-Interview/Background-Check partner surfaces — each is its own API area this app does not touch.
Three routes to the same 15 actions. The Workflow tab is generated from Workable's own manifest and carries its real ids, so it is copy-pasteable; the Code and CLI examples are the same call for any action on any app, so every app-specific value in them is a blank you fill in.
candidate-activity-list The activity stream for one candidate — stage moves, comments, ratings. Required scope: `r_candidates`.
candidate-create Create a candidate on a job. Required scope: `w_candidates`. See the description for what `sourced` controls — it decides whether the candidate is emailed.
candidate-disqualify Disqualify a candidate. Required scope: `w_candidates`. `memberId` is required by Workable — the member performing the disqualification.
candidate-get Get the full details of one candidate, including education, experience and answers (trimmed from the list response in v3). Required scope: `r_candidates`.
candidate-list List candidates across the account, or narrow to one job/stage/email. With no filter set this returns every candidate in the account. Required scope: `r_candidates`.
candidate-move Move a candidate to another pipeline stage. Required scope: `w_candidates`. `memberId` is required by Workable — the member performing the move.
candidate-update Update a candidate's basic fields. Required scope: `w_candidates`.
disqualification-reason-list List the account's disqualification reasons, for `candidate-disqualify`'s Reason ID field. Required scope: `r_jobs`. The vendor's own API reference gives no example response for this endpoint, so the raw body is returned as-is.
job-stage-list List the pipeline stages configured on one job — the values `candidate-move`'s Target Stage and `candidate-create`'s Stage accept. Required scope: `r_jobs`.
member-list List the account's hiring members — the ids `candidate-move` and `candidate-disqualify` need for their Acting Member field. Required scope: `r_jobs`.
webhook-subscribe Register a URL to receive a Workable event. Required scope: `r_candidates` or `r_employees`. Target URLs must be unique — a duplicate answers 409.
webhook-subscription-list List this connection's registered webhook subscriptions. Required scope: `r_candidates` or `r_employees`.
webhook-unsubscribe Unsubscribe from an event. Required scope: `r_candidates` or `r_employees`.
A workflow step names the app and the action, and the editor fills in the
connection when you pick one. This is the Step shape from the
workflow spec, carrying Workable's real ids.
{
"manifestVersion": "2",
"name": "workable-example",
"steps": [
{
"id": "candidate-activity-list",
"uses": {
"app": "io.w6w.workable",
"action": "candidate-activity-list",
"connection": "conn_YOUR_CONNECTION_ID"
},
"with": {
"id": "<id>"
}
}
]
}candidate-activity-list candidate-create candidate-disqualify candidate-get candidate-list +10 more actions available
Every app-specific value here is a blank you have to fill in. An
app action is reached through the connection that authenticates it, so the
address is a connection id, not the app id — and connections belong to your account,
so a public page cannot know yours. Create one for Workable, then fill in
the three blanks: conn_YOUR_CONNECTION_ID, the action key, and the
parameters that action declares. The call itself is real — the shape is transcribed
from the studio's own snippet builder, which prints the same kind of blanks — but
nothing in it is specific to Workable. The Workflow tab is where this app's
real ids are.
npm install @w6w/sdkyarn add @w6w/sdkpnpm add @w6w/sdkdeno add npm:@w6w/sdkimport { W6wClient, isActionRun } from "@w6w/sdk";
// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
const client = new W6wClient();
const envelope = await client.run({
urn: "conn_YOUR_CONNECTION_ID",
action: "candidate-activity-list",
payload: {
id: "<value>",
// actions: "<value>",
// updatedAfter: "<value>",
// limit: "<value>",
// sinceId: "<value>",
// maxId: "<value>",
// pageUrl: "<value>",
},
});
if (isActionRun(envelope)) console.log(envelope.value); npm install -g @w6w/cli w6w run conn_YOUR_CONNECTION_ID --action candidate-activity-list --payload '{"id":"<value>"}' Give an AI agent Workable — without giving it Workable's credentials. One MCP endpoint exposes every app, function and workflow the caller is entitled to, as tools it can discover and run. Access is granted per team while we onboard.
One tool call{
"name": "w6w_invoke",
"arguments": {
"ref": "app:io.w6w.workable#candidate-activity-list",
"input": {
"id": "<id>"
}
}
}
Every tool names its target with a single ref. The
app: form above doesn't name a connection at all — the
host resolves which of the caller's Workable connections to sign
with, and refuses rather than guesses when the answer is ambiguous.
The token is attached host-side, at the moment of the call. It is never a tool argument, never in the model's context, and never in a transcript — so a prompt injection has nothing to exfiltrate.
Tools are derived per end user from what that person has actually connected and is entitled to — not one shared bot identity carrying the union of everyone's access.
Multi-step work runs on the workflow engine and returns a run handle the agent can poll — retries, branching and state survive the conversation that started them.
Workable's declared health checks are on the surface too, so an agent can tell "the vendor is down" from "your credential expired" before it burns a retry on either.
The MCP surface is part of the hosted platform. Workable itself is MIT, and the runtime that executes it is source-available (FSL).
Workable declares its own checks, so its health is a property of the app rather than something the host guesses at.
Signed request to this connection's own subdomain. Workable offers no unauthenticated signal that distinguishes a real subdomain from a made-up one, so this probe is necessarily signed — see the file header.
Per-10-second account-token allowance remaining, read off the documented X-Rate-Limit-* headers.
Atlassian Statuspage rollup for workable.statuspage.io, anchored on the 'Recruiting and applicant tracking' component this app's endpoints actually touch. Unauthenticated.