Skip to content

API Keys and Webhooks

Yes, there is an API, and which one you want depends on what you are driving. The workspace MCP endpoint is the programmatic interface to a workspace: an MCP client or script connected with a workspace API key can list and create agents, start and read sessions, and work with documents, data tables, boards, and the inbox. An agent API serves one agent’s tools to outside callers, who sign in with OAuth or a machine credential; see Give an Agent an API. A webhook starts an assignment run from any system that can send an HTTP POST, and is covered on this page. Other agent frameworks can also delegate work over A2A. There is no published REST API reference beyond these.

The workspace API key is the credential for all of them except the agent API. A webhook caller presents it in an X-API-Key header; MCP and A2A clients send it as Authorization: Bearer wak_….

The webhook surface is deliberately narrow. Everything about what happens — the instructions, the tools, the deliverable — lives on the assignment; the webhook only says now, and optionally hands over a payload. That keeps the integration contract small enough to fit in one table (below) while still covering the real cases: a ticketing system that wants an agent on every new ticket, a form tool that wants each submission enriched, a CI pipeline that wants a report after each deploy. Any system that can send an HTTP POST can start agent work.

Manage keys in Workspace settings → API keys. Workspace admins create, rotate, and revoke keys; other members see the list.

  • New API key asks only for a name. The full key — it starts with wak_ — is shown exactly once: “This is the only time the full key will be shown. Store it securely.” Afterward, the list shows only each key’s prefix and when it was last used.
  • Rotate issues a replacement key (also shown once) and revokes the old one.
  • Revoke disables a key immediately.

A key acts as the person who created it, and only while they remain a member of the workspace. When someone leaves, their keys are revoked, so the callers that used them need a key from someone who is staying.

Because rotating issues a new key, every webhook bound to the old one refuses deliveries until it is bound to the replacement. Webhook consumer updates, below the key list, shows each webhook assignment with the key it is bound to, marked Bound to active key or Replacement needed; Update binding points it at the replacement. Then give the calling system the new key.

Name keys after their callers (ticketing-webhook, ci-pipeline) so rotation and revocation stay surgical. When the ticketing vendor has an incident, you rotate ticketing-webhook, rebind the one assignment that uses it, and the CI pipeline never notices; when a system is decommissioned, you revoke its key and nothing else changes. One shared key across callers turns every one of those events into an all-hands re-credentialing.

On an assignment’s Schedule tab, under Triggers, check Run via webhook, choose the API key callers will present, and set a Webhook path. The contract:

Method POST
URL https://workprentice.ai/api/v1/hooks/<workspace-id>/<path>
Auth X-API-Key: wak_… header carrying the key bound to this webhook, or sender-signature mode below
Body Optional JSON, up to 5 MiB — delivered to the run as its webhook payload
Dry run Append ?run_type=dry_run to hold back the assignment’s follow-up hooks
Success 200 with the started session’s id, "status": "started", and the run type
Errors 400 invalid JSON · 401 bad or missing credential · 403 paused assignment or agent · 404 unknown path · 413 body over 5 MiB (a 401 in sender-signature mode)

A credential is required in either mode. Every delivery starts a real agent run, so a webhook with no credential bound is not an open endpoint — it rejects every call with a 401 until you bind an API key (the default mode) or a signing secret (sender-signature mode, below). Only the bound key opens it: another valid key from the same workspace is refused too.

Some SaaS senders cannot set custom headers on their webhook deliveries, so they cannot present an API key. Intercom is the canonical example: it signs each delivery instead, sending an X-Hub-Signature header carrying an HMAC-SHA1 of the raw request body computed with your Intercom app’s client secret. Senders that sign with SHA-256 send X-Hub-Signature-256 instead, and both are accepted. A delivery that carries both headers is verified against the SHA-256 one.

For those senders, switch the webhook’s Authentication to Sender signature and paste the Signing secret (for Intercom, the app’s client secret from its Basic Info page). Deliveries then authenticate by signature: a missing or wrong signature is a 401, exactly like a bad API key. Because the body is what gets verified, it is read before the caller is authenticated, so a body over 5 MiB, or one that arrives too slowly, is also a 401 in this mode; an unauthenticated caller cannot tell which mode a webhook uses. The secret is write-only — it is never shown again after saving — and can be rotated by pasting a new value. Everything else in the contract, including ?run_type=dry_run, works the same in both modes.

Suppose a support assignment listens at the path ticketing/new-ticket. While you are still tuning the instructions, rehearse with a dry run and a sample ticket. A dry run holds back the follow-up actions listed on the assignment’s Hooks tab, but the agent’s own tool calls still happen, so point early tests at records it is safe to change:

Terminal window
curl -X POST \
"https://workprentice.ai/api/v1/hooks/<workspace-id>/ticketing/new-ticket?run_type=dry_run" \
-H "X-API-Key: wak_..." \
-H "Content-Type: application/json" \
-d '{"ticket_id": "12345", "subject": "Cannot log in"}'

A successful trigger returns the session that started:

{ "session_id": "…", "status": "started", "run_type": "dry_run" }

Open that session in Workprentice to watch the run. The JSON body is handed to the agent as the webhook payload, so the assignment’s instructions can refer to it directly — “enrich the ticket in the payload” — and each caller can send whatever fields its runs need. When the output looks right, drop the run_type parameter and point the real system at the same URL; every delivery starts a session and returns its id, so the calling system can link straight to the run.

A 404 means the path matches no webhook-enabled assignment in the workspace: the path is unknown, the assignment is archived, or its webhook trigger was turned off. A 403 means the assignment or its agent is paused, the agent is archived, or the agent is a template, which never runs. The credential is checked before any 403 case, so a caller without a valid credential gets a 401 and cannot learn the assignment’s or agent’s state; only an authenticated caller sees the 403.

The webhook guide walks the full setup with example calls, from creating the key to going live.

  • One key per caller — ticketing-webhook, ci-pipeline, forms-intake. Rotation and revocation stay scoped to the one system involved.
  • Dry run while iterating — keep ?run_type=dry_run on the URL until the sessions look right, then remove it. Same endpoint, same payloads, and the assignment’s follow-up hooks held back; send sample records, since the agent’s own tool calls still run.
  • Pause as the off switch — pausing the assignment makes its webhook return 403, so you can take an intake offline during an incident without revoking any keys, and turn it back on just as cheaply.
  • Payload-aware instructions — write the assignment’s instructions against the payload’s fields (“look up ticket_id, draft a response to subject”), so the caller controls the input and the assignment controls everything else.

For the complete site index, see llms.txt.