The WorkerKit API.

Everything the MCP server does, over plain HTTPS: two OpenAPI specs, an API key or an OAuth2 client, and the operating rules an agent needs before its first call. For the platforms that connect to a REST API rather than an MCP server.

Get started

Signup, approval and funding.

A new user can sign up during approval. An existing user signs in with Google, Microsoft or an email OTP in the WorkerKit browser page. Signing in is separate from granting access: the account admin chooses the account, permissions and expiry, then approves. Never request an OTP, provider key, fleet credential or payment details in conversation.

For an API client with secure credential storage, POST https://api.workerkit.ai/api/auth/agent/requests with name, clientLabel and a scopes array. This bootstrap route needs no fleet key. Keep pollSecret private; display only approvalUrl, userCode and expiresAt. Requests expire after ten minutes.

Optionally POST /api/auth/agent/requests/{requestId}/email with { "email": "user@example.com" } and X-Poll-Secret. Email binds the request to that signed-in address; the code stays with the initiating client. Email delivery does not reveal whether an account exists.

GET /api/auth/agent/requests/{requestId} with X-Poll-Secret at most once every five seconds. When status is approved, POST the same path plus /redeem with that header. Only this response contains managerKey; put it directly in credential storage, never a transcript. /cancel cancels pending access or revokes this request's redeemed key after a lost response. A leaked approval URL cannot collect a key. Honor Retry-After on 429.

Do not import bootstrap operations into a hosted assistant that cannot keep the polling secret and redeemed key outside model-visible results. Use its standard OAuth integration instead.

After connection, call key_info, then onboarding_get (optionally with the intended model provider). Readiness here checks account model funding; check the selected worker's permissions, deployment and budgets before running. Empty fleets are valid. Consent defaults to read-only scopes and 30 days; install, deploy, run, connections and purchases need their explicit scopes. An expired or revoked grant needs fresh approval. Revoking access does not stop already scheduled workers: pause those separately.

Runtime permissions require the human to review a shared account ceiling per UTC day and month. onboarding_get.spendPolicy reports its limits and reserved allowance. Each hosted run, including schedules, reserves its model ceiling plus possible BYOK fees. Reservations remain until the window resets even after a cheaper or failed run. Agents cannot raise this ceiling through budget, clone or deployment operations. A human_spend_ceiling refusal requires waiting or fresh human approval. Metered app charges and wallet purchases are separate.

BYOK: send the person byokSetupUrl from onboarding_get and ask them to select the returned account in Settings. Provider keys go directly into that trusted page. A client that already has a provider secret in protected storage can use model_key_set with manageConnections; never echo the secret. BYOK can still incur platform fees, metered app charges and decision costs.

Wallet: wallet_get requires readWallet. With explicit permission for the amount and requestWalletTopUp, call wallet_checkout_create with amountUsd and a unique idempotencyKey (HTTP: POST /api/manage/wallet/checkouts, Idempotency-Key header). Reuse the same key and amount on retries. Show amountUsd, feeUsd, totalUsd and the returned checkoutUrl; the person reviews and pays in Stripe Checkout. This grants no unattended charging authority.

wallet_checkout_get (GET /api/manage/wallet/checkouts/{sessionId}) reports pending, expired, paid_pending_credit or credited. A checkout URL, redirect or paid session is not wallet credit. Poll no faster than every five seconds and proceed only on credited; check worker readiness again. requestWalletTopUp alone can inspect only checkouts created by that key. readWallet can inspect the account's checkouts.

Two surfaces

Your fleet, and the public catalog.

The fleet is yours, so it is never anonymous; the catalog is public, so it is never walled behind a sign-in. Each surface has an OpenAPI 3 document of its own.

Base URLWhat it isAuth
https://api.workerkit.ai/api/manage/workersYour fleet: read, run and configure workers, set their budgets, clone them, install kits as new ones, author kits of your own, connect apps by credential, and register your own MCP servers (kits live beside it under /api/manage/kits; apps, model keys and MCP servers under /api/manage/apps, /api/manage/model-keys and /api/manage/mcp-servers).Manager key or OAuth2
https://api.workerkit.ai/api/directory/mcpThe public kits catalog: search kits, read one in full, read a publisher, and read what WorkerKit is and when to use it, written for an agent (/about).None at all
SurfaceOpenAPI 3 document
Workershttps://api.workerkit.ai/openapi/workers.json
Directoryhttps://api.workerkit.ai/openapi/directory.json

If your platform speaks MCP, use the WorkerKit MCP server instead: the same operations, with the sign-in discovered from the server.

Meta Muse connects this way, holding a manager key and calling the fleet directly. Its walkthrough, written for the Muse agent, is Set up WorkerKit in Meta Muse.

Connect with an API key

One key, the scopes you choose.

An account admin creates a key under Fleet access, picks its scopes, and reads it once: it is never shown again. Send it on every fleet request as Authorization: Bearer pe_mgr_.... The key reaches the fleet only; it grants no access to any connected app.

ScopeWhat it grants
readWorkersThe fleet list, worker detail, and reads of memory, schedules and the instruction.
readRunsRun history, run detail, run events and a run's stored transcript. A receipt returned by a waiting run request is run content too: without this scope the run still starts and the receipt comes back with contentWithheld.
runWorkersRun now, one worker or up to 20 in one call, and cancel.
manageMemoryAdd, edit, retire and delete rules and facts; clear a run's report; grade a run.
manageSchedulesCreate, edit and delete schedules.
manageInstructionsCreate or replace a language worker's instruction, and answer a decision worker's install questions.
manageStateStart and stop a worker.
installKitsPreview and install a directory kit as a new worker.
manageDeliveriesCreate, edit and delete run-result delivery destinations: where the platform sends a run report when the worker finishes. Reading them rides on readWorkers. Availability is judged per account, so ask the channels operation rather than inferring it from the worker apps.
manageBudgetsRead and change a worker's spend and run ceilings, and the account-wide fleet ceiling. Its own scope because raising a dollar cap is the one management action that can cost money without starting anything.
createWorkersClone a worker into a new one, singly or in bulk, with a dry-run preview. The only non-kit creation path: a clone carries permissions a person already approved on the source.
publishKitsAuthor kits: validate (a dry run that reports every gate at once), publish from content or from an owned worker, edit, replace, unlist, relist, make private, delete, and edit the publisher profile. A private kit installed with installKits is how a worker is built from scratch through the reviewed manifest pipeline. The anonymous Directory API serves the authoring guide, the live permission vocabulary and the per-app tool explorer; reads of your own kits ride on readWorkers.
manageConnectionsConnect and disconnect apps for your operators by credential: every family the Apps page accepts by paste (bot tokens, API keys, private-app tokens), validated live against the provider, stored encrypted, never returned; register your account's own MCP servers as custom MCP apps (with their credentials) and enable their tools; and set or remove your account's own model-provider keys. Reading which apps are connected, with a recipe for connecting each, rides on readWorkers. Google, Microsoft, GitHub and Reddit are browser sign-ins and stay on the Apps page.
manageDeploymentsDeploy a worker onto the hosted runtime and manage that deployment: its model and reasoning, its transcript setting, its spend ceilings, pause and resume, and undeploy. This is the step that makes an installed worker run at all: without a deployment it fires no schedule and a run request is refused with not_deployed. Reading the deployment and the model catalog rides on readWorkers.
deleteWorkersDelete a worker permanently: its key stops working, its schedules stop firing, and its instruction, memory, deployment and delivery destinations go with it — as do its sub-workers, because a dead orchestrator must never leave live workers behind. Not reversible by any call, which is why it is its own scope rather than part of start/stop: stopping a worker is reversible and this is not. Run receipts survive, and the freed worker slot is what clears a 402 limit_exceeded on install.
readWalletRead spendable wallet balance, fees and account checkout status.
requestWalletTopUpCreate a human-confirmed Stripe Checkout link and inspect purchases requested by this key. Does not authorize charging a saved card.

Call GET /api/manage/workers/key-info first to learn what your key can do: it returns the account name, the key's scopes and expiry, and serverTimeUtc. Any valid key may ask.

Connect with OAuth2

Authorization code with PKCE.

Platforms that register themselves connect with no key to paste: the authorization-code flow with PKCE (S256), dynamic client registration, and the same scope names as above. At consent an account admin picks or creates a manager key at https://workerkit.ai/mcpauth, and that key's scopes are the token's reach.

EndpointURL
Authorizationhttps://api.workerkit.ai/api/oauth/authorize
Tokenhttps://api.workerkit.ai/api/oauth/token
Dynamic client registrationhttps://api.workerkit.ai/api/oauth/register
Revocationhttps://api.workerkit.ai/api/oauth/revoke
Discoveryhttps://api.workerkit.ai/.well-known/oauth-authorization-server

A platform that cannot do PKCE or dynamic client registration should use the API key path today.

Quick start

Five requests.

The three directory calls need nothing. The two fleet calls need a key; replace the placeholders with the ids the responses return.

  • The directory, no auth: what WorkerKit is and when to use it, written for an agent curl https://api.workerkit.ai/api/directory/mcp/about
  • The directory, no auth: the filter vocabulary curl https://api.workerkit.ai/api/directory/mcp/overview
  • The directory, no auth: search kits curl "https://api.workerkit.ai/api/directory/mcp/kits?q=inbound+leads&page=1&pageSize=20"
  • Your fleet: list every worker curl https://api.workerkit.ai/api/manage/workers \ -H "Authorization: Bearer pe_mgr_..."
  • Your fleet: run a worker, then poll its events every 3 to 5 seconds curl -X POST https://api.workerkit.ai/api/manage/workers/{workerId}/run \ -H "Authorization: Bearer pe_mgr_..." \ -H "Content-Type: application/json" -d '{}' curl "https://api.workerkit.ai/api/manage/workers/runs/{runId}/events?afterSeq={lastSeq}" \ -H "Authorization: Bearer pe_mgr_..."

A worker is addressed by its workerId GUID, which every response that names a worker returns; the older sequential integer id still resolves and is deprecated.

Classification on demand

Create a decision worker from your questions.

Categorize, score or triage connected data, then reuse and adjust the worker.

Reuse an existing worker or decision kit when its questions fit. For a custom classification task, creation compiles a supported source recipe and typed questions into a private kit and an installed decision worker. Optional deploy:true adds deployment; creation never starts a run or adds a schedule. The kit can be edited and published later through the normal kit lifecycle.

  • Creation request JSON { "requestId": "customer-email-triage-001", "name": "Customer email triage", "source": { "recipe": "email-previews", "args": { "after": "-7d" } }, "questions": [ { "key": "category", "type": "choice", "instructions": "Which category best describes this message?", "options": { "followup": "A customer asks for a reply", "other": "A different topic" } } ], "confidenceFloor": 0.7, "maxItems": 20, "deploy": false }

Discover recipes with GET /api/directory/mcp/authoring/tools?purpose=decision and read GET /api/directory/mcp/authoring/guide?section=decision; both are anonymous. Check connections with GET /api/manage/apps, then send the request to POST /api/manage/decision-workers. Use the returned worker with the existing deployment, run and instruction endpoints in the workers OpenAPI document. Running needs runWorkers; results need readRuns. Saved setup answers adjust categories/levels; a structural question or source change needs a revised kit and a replacement install. Check receipt status, coverage, omissions, warnings and cost before claiming completion.

Start with email-previews, calendar-events or sheets-rows. These recipes return judgments without app writes. Email previews do not include full threads; calendar events are invitation data, not transcripts; Sheets needs a Google file ID, a finite tab-qualified range and a columns map. A connected app alone does not make every tool a supported source. Source filters select evidence, not permissions: the Sheets recipe grants spreadsheet reads across the linked Drive account.

Supply 1–8 questions: choice with named options, score with ordered levels, or noul for the probability of a statement. Choice adds unclear automatically. Set an explicit confidenceFloor between 0 and 1; it routes uncertainty and does not promise accuracy. maxItems is 1–50, default 20. Creation requires publishKits and installKits; optional deployment also needs manageDeployments.

Use a fresh requestId for each new worker. Retry with the same ID and identical body to recover the original receipt; a changed body returns 409. The response includes tokenId for MCP/CLI worker commands, stable workerId, kitSlug, readiness and nextCall. A deploymentError means the worker already exists: fix deployment on that worker. The receipt is a snapshot; check current worker readiness before running. No worker API secret is returned.

Operating rules

What the backend enforces.

Per-account limits, the polling cadence, and the responses that are terminal rather than transient. Every row is a fact of the API, not advice.

RuleWhat it means
Surface limitsEvery call to the fleet surface counts against two windows of its own: 120 per minute and 1,200 per hour. The kits surface has a separate 60 per minute. Both key on the account behind the credential, not on your IP address, so extra machines buy no extra budget.
Run triggers30 per minute per account, counted on top of the fleet surface windows. The bulk trigger, POST /api/manage/workers/runs/bulk with up to 20 workers a call, has a window of its own: 2 per minute and 20 per hour, on top of the same surface windows.
Request bodiesSend a body on every POST, at least {}: a POST with no Content-Length is refused at the edge with an HTML 411 page before it reaches the API, and that page is not an API error. It bites on the bodyless actions first: cancel, delivery secret rotate, instruction restore, and the kit unpublish, relist and make-private calls.
Runs in flight per workerSet by the plan, not per worker: Free 5, Pro 20, Team 50, Enterprise uncapped. The budget read reports it and the budget PATCH does not take it. A worker at its limit lands the next on-demand run as Skipped with skipReason ConcurrencyLimit. A schedule never overlaps itself: a scheduled fire that finds any run of that worker in flight is Skipped whatever the plan allows, so space a schedule wider than a run takes.
Run events polling120 per minute and 2,400 per hour per account, and exempt from the fleet surface windows so a poll loop cannot starve the calls that finish the flow it is waiting on. Poll every 3 to 5 seconds and pass afterSeq so each call returns only what is new.
Fleet feed long pollGET /api/manage/workers/runs?wait=60 holds the connection until a run on the account is created, starts or settles, up to 60 seconds, then returns the same page it would have without wait. Four held connections per account; a fifth answers at once. wait is ignored when a cursor is passed.
Waiting on a runPOST /api/manage/workers/{workerId}/run with waitSeconds, 0 to 55, holds the connection until the run settles and answers the settled receipt; without it the receipt comes back at once. A run still going at the deadline comes back with its non-terminal status: poll GET /api/manage/workers/runs/{runId} from there.
Kit installs10 per hour per account, exempt from the kits surface's 60 per minute.
Other hourly windows20 kit publishes, 30 app connects, 20 model-key sets, 20 MCP-server registers and 60 MCP-server discoveries per hour per account, each exempt from the per-minute surface windows: every one of them reaches an outside service (a scanner, a provider, an MCP server) on your behalf.
402 limit_exceededThe plan's worker cap is reached. Terminal: retrying will not help, an account admin has to raise the plan or remove a worker.
402 feature_gatedThe plan does not include the feature named in the response's "feature" field: schedule_cadence and schedule_count when creating or editing a schedule, memory_advanced when a memory PATCH moves a fact into the searchable store. Terminal.
409 conflictA structural refusal from the run family, named in the response's "error" field: not_deployed, deployment_paused, deployment_suspended, model_unavailable, run_not_cancelable, run_not_settled, answer_in_progress. Two more name themselves in "code": not_language_worker when a decision worker is sent prompt or modelSlug, and not_decision_worker when a language worker is sent sourceArgs, answers or maxItems on a run, or answers or optionsFor on its instruction. Terminal, not a retry signal: something about the state has to change first.
422 RUNTIME_NOT_ENABLEDThe account's hosted runtime is switched off. A capability switch, not a transient error: do not retry.
404 not_foundThe thing is missing OR belongs to another account. The two are indistinguishable by design.
403 OPERATION_NOT_ALLOWEDThe key lacks a scope; the message names the one it wanted. A wider key is the fix, not a retry.
TimesThree responses carry a server clock: GET /api/manage/workers/key-info, the fleet list GET /api/manage/workers, and the fleet pulse GET /api/manage/workers/fleet/pulse. Compute ages and countdowns against their serverTimeUtc rather than your own; no other response on either surface returns one.
ScoresA null score means unassessed. It is never 0.
429 rate limitThe body is plain text, not JSON. Read Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset from the headers and wait out Retry-After. The auth throttle below is the one 429 that is JSON.

Errors

Three envelopes, named codes.

Every fleet and kits endpoint outside the run family answers with { "error": "Not found", "message": "...", "code": "not_found" }: error is a human label and code is the machine code to branch on. The run family (run, runs, the account run feed, run detail, run events, the run transcript, cancel, clear report, score; a bulk run answers 200 and carries the same codes per item in errorCode) answers with { "error": "not_found", "message": "..." } for refusals raised by the run engine itself: no code field at all, and the machine code in error. Their pre-flight refusals keep the first shape, so the 403, the 422 and the not_language_worker / not_decision_worker 409s above carry the machine code in code even on a run endpoint.

Two exceptions on the first side: both 402s name themselves in error and carry no code field, as { "error": "limit_exceeded", "limitType": "...", "currentCount": 0, "maxAllowed": 0, "message": "..." } on a kit install and { "error": "feature_gated", "feature": "...", "upgradeTrigger": "...", "message": "..." } on a schedule or memory write. And the anonymous catalog surface answers in a third shape of its own, { "statusCode": 404, "message": "Kit not found.", "errorType": "ResourceNotFound", "correlationId": "...", "timestamp": "..." }, with neither field: branch on code when it is present and on error otherwise.

The auth failures, in the order a new connector meets them, all carry the first shape:

StatusCodeWhen
401auth_requiredThe Authorization header is missing or malformed.
401auth_failedThe key is unknown or has been revoked.
401manager_key_expiredThe key passed its expiry.
403account_pausedThe account is paused; every key on it is refused.
429auth_throttledToo many failed attempts from your network. JSON, unlike the rate-limit 429. Honour Retry-After; a valid key is never throttled.