API reference
This page covers what applies to every call. The calls themselves are described where you use them: Run an automation, Incoming webhooks, API keys and, for an App, the App SDK and the workstudio CLI, which make the calls for you.
Base URL
Section titled “Base URL”https://api.work.studio/api/v1/workflow/Every path in these docs is relative to it, for example POST /api/v1/workflow/execute/{endpoint}.
Authentication
Section titled “Authentication”| Caller | Send |
|---|---|
| Your backend, with an API key | X-API-Key: svx_tk_… (organization key) or svx_ck_… (customer key). Add X-Scope-Key: customer:acme to act for one customer with an organization key. |
| A short-lived token for one customer | Authorization: Bearer <accessToken> from the token exchange |
| Embed | Authorization: Bearer svx_ik_… or svx_st_… plus X-Embed-Tenant. See Embed authentication. |
If a request carries both a bearer token and an API key, the bearer token is used.
Errors
Section titled “Errors”Most errors come back as one flat JSON object:
{ "timestamp": "2026-10-21T17:04:12.345Z", "status": 400, "error": "Bad Request", "message": "…what went wrong…", "path": "/api/v1/workflow/run/6f1c2a9e-…", "service": "…", "details": null}erroris the HTTP reason phrase.messagesays what went wrong.detailsmaps each field to its problem when the request body fails validation.
There is no separate error code field. Branch on the HTTP status.
A few places answer in their own shape:
- A refused API key (401 or 403) gets the server’s default error body.
- The OAuth token exchange answers in the standard OAuth form,
{ "error": …, "error_description": … }. - Incoming webhooks answer security refusals with
{ "ERROR": "…" }.
- The refusals for an organization that requires MFA, below, use the same OAuth form.
When an organization requires MFA
Section titled “When an organization requires MFA”An organization can require two-factor authentication for its members (see Account security). A request made with a member’s work.studio sign-in token is then refused unless that sign-in included a code:
HTTP/1.1 401 UnauthorizedWWW-Authenticate: Bearer error="insufficient_user_authentication", error_description="This organization requires two-factor authentication", acr_values="mfa"{ "error": "mfa_required", "error_description": "This organization requires two-factor authentication. Sign in again with the code from your authenticator app.", "acr_values": "mfa", "tenantId": "…"}Refreshing the token doesn’t help, because a refreshed token comes from the same sign-in. Send the person through sign-in again with prompt=login&acr_values=mfa on the authorization request. That sign-in always asks for a code, or has them set one up. Then retry with the new token. If the retry is refused the same way within a few minutes, show the error instead of sending them round again.
Two related answers:
503with"error": "mfa_policy_unavailable"means the organization’s sign-in policy couldn’t be checked. Retry shortly.403with"error": "tenant_mismatch"means the organization in the path, such as/tenants/{tenantId}/…, isn’t the one the request selected.
API keys, tokens from the token exchange, embed credentials, service accounts and App SDK end users are never refused for this.
Rate limits
Section titled “Rate limits”The general API publishes no per-key rate limit. Each incoming webhook has its own limit, set on the webhook (see Incoming webhooks), and your plan limits how many automations run at once.