First-party app
Workable

Workable

Manage Workable jobs, candidates, pipeline stages, members and webhook subscriptions.

stable Human Resources

About

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.

App id
io.w6w.workable
Version
0.1.0
Author
w6w
Licence
MIT
Categories
Human Resources

Overview

Workable 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.

Build with Workable

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.

List Candidate Activity

candidate-activity-list

The activity stream for one candidate — stage moves, comments, ratings. Required scope: `r_candidates`.

Create Candidate

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.

Disqualify Candidate

candidate-disqualify

Disqualify a candidate. Required scope: `w_candidates`. `memberId` is required by Workable — the member performing the disqualification.

Get Candidate

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`.

List 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`.

Move Candidate to Stage

candidate-move

Move a candidate to another pipeline stage. Required scope: `w_candidates`. `memberId` is required by Workable — the member performing the move.

Update Candidate

candidate-update

Update a candidate's basic fields. Required scope: `w_candidates`.

List Disqualification Reasons

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.

Get Job

job-get

Get the full details of one job by its shortcode. Required scope: `r_jobs`.

List Jobs

job-list

List the account's jobs, oldest first. Required scope: `r_jobs`.

List Job Pipeline Stages

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`.

List Members

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`.

Create Webhook Subscription

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.

List Webhook Subscriptions

webhook-subscription-list

List this connection's registered webhook subscriptions. Required scope: `r_candidates` or `r_employees`.

Delete Webhook Subscription

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>"
      }
    }
  ]
}

Here are some of the things you can do

  • List Candidate Activity

    read
    candidate-activity-list
  • Create Candidate

    perform
    candidate-create
  • Disqualify Candidate

    perform
    candidate-disqualify
  • Get Candidate

    read
    candidate-get
  • List Candidates

    read
    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.

Install
npm install @w6w/sdk
yarn add @w6w/sdk
pnpm add @w6w/sdk
deno add npm:@w6w/sdk
Code
import { 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);
Install the CLI
npm install -g @w6w/cli
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.

What the agent gets

Credentials it can't read

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.

A tool surface scoped to the caller

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.

A durable workflow in one call

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.

Health-aware discovery

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).

Request MCP access

Health checks

Workable declares its own checks, so its health is a property of the app rather than something the host guesses at.

dependency

Account reachable

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.

quota

API rate-limit headroom

Per-10-second account-token allowance remaining, read off the documented X-Rate-Limit-* headers.

service

Workable platform status

Atlassian Statuspage rollup for workable.statuspage.io, anchored on the 'Recruiting and applicant tracking' component this app's endpoints actually touch. Unauthenticated.