Skip to main content

Conductor Deck API & developer reference

A public, read-only REST API and an MCP server. No account, no API key, no sales call — every endpoint on this page answers an anonymous request right now.

curl -s "https://www.conductordeck.com/api/v1/integrations?q=spotify&availability=available&limit=3"

Endpoints

Base URL https://www.conductordeck.com. The complete typed contract — parameters, response schemas, and error shapes — is in the OpenAPI 3.1 schema.

MethodPathOperation IDWhat it returns
GET/api/v1/healthgetPublicApiHealthLiveness and deployed revision of the versioned public API.
GET/api/v1/integrationslistIntegrationsSearch and page the apps Conductor Deck can connect to. Filters: q, category, availability, limit, offset.
GET/api/v1/integrations/{slug}getIntegrationOne app plus the exact triggers and actions a workflow can use for it.
GET/api/v1/templateslistWorkflowTemplatesSummaries of the built-in workflow templates. Filters: q, category.
GET/api/v1/templates/{id}getWorkflowTemplateOne template including its full node and edge graph.
GET/api/v1/megetAuthenticatedIdentityIdentify an API key: the account it belongs to and the scopes it carries. Needs a key, but no particular scope.
GET/api/v1/me/workflowslistOwnWorkflowsThe key owner's workflows as summaries. Requires the workflows:read scope.
GET/api/v1/me/runslistOwnRunsThe key owner's run history. Requires the runs:read scope.
POST/api/mcpcallMcpServerModel Context Protocol server over Streamable HTTP, speaking JSON-RPC 2.0.

Authentication and permissions

Everything under /api/v1 is anonymous and read-only. The single permission it needs is public:read, declared in RFC 9728 protected-resource metadata. Every caller holds it; nothing needs to be requested or granted.

Account access with a scoped API key

The endpoints under /api/v1/meread the key owner's own workflows and run history. Create a key yourself in Settings → API keys — no form, no sales call. The key is shown once and stored only as a SHA-256 hash, so it cannot be recovered afterwards.

A key carries exactly the scopes you pick at creation, and scopes cannot be added to an existing key — mint a new one instead. Keys are read-only, and a key can never create another key, so a leaked key cannot escalate itself. Revoking takes effect on the next request.

  • workflows:read — your workflows: name, status, trigger summary, step count. The node and edge graph is not returned.
  • runs:read — your run history: status, timing, failure summary. Step output is not returned.

A 401 or 403 carries an RFC 6750 WWW-Authenticate challenge naming the scope you needed and pointing at the RFC 9728 metadata, so a client can discover the scope list from a failure alone.

If you are building an agent rather than a script, prefer OAuth over asking someone for a key — see OAuth 2.1 below.

Everything else

Writing — creating workflows, running them, driving devices — is not reachable with an API key and is not part of this specification. The web app and the Stream Deck plugin use a Supabase-issued session JWT for that.

curl -s -H "Authorization: Bearer cd_live_…" \
  "https://www.conductordeck.com/api/v1/me/workflows"

OAuth 2.1 for agents

An agent that needs read access to someone's account should ask for it, not ask them to paste a key. Conductor Deck runs an OAuth 2.1 authorization server for exactly that: the account holder sees a consent screen naming your app and the scopes it wants, and you get a short-lived token if they approve. Server metadata is published at /.well-known/oauth-authorization-server (RFC 8414), so a standards client can discover all of this without reading this page.

  • Public clients only. No client secret is issued, so there is none to leak, and PKCE with S256 is required — plain is rejected, not merely discouraged.
  • The only grantable scopes are the two read scopes above. There is no write scope to grant, so a stolen token cannot change anything.
  • Tokens expire after 8 hours. No refresh tokens are issued — re-run the flow instead.
  • Redirect URIs are matched exactly, never normalised, and must be https or http on a loopback address for a native client.

Revoke a token early by posting it to /api/oauth/revoke (RFC 7009), or let it expire.

# 1. Register once per installation (RFC 7591). No secret is issued.
curl -s -X POST "https://www.conductordeck.com/api/oauth/register" \
  -H "Content-Type: application/json" \
  -d '{"client_name":"My agent","redirect_uris":["http://127.0.0.1:8976/cb"]}'

# 2. Send the account holder to the consent screen.
https://www.conductordeck.com/oauth/authorize
  ?response_type=code
  &client_id=cdc_…
  &redirect_uri=http://127.0.0.1:8976/cb
  &scope=workflows:read%20runs:read
  &code_challenge=<S256(verifier)>
  &code_challenge_method=S256
  &state=<random>

# 3. Exchange the returned code for a token.
curl -s -X POST "https://www.conductordeck.com/api/oauth/token" \
  -d grant_type=authorization_code \
  -d code=<code> \
  -d client_id=cdc_… \
  -d redirect_uri=http://127.0.0.1:8976/cb \
  -d code_verifier=<verifier>

Rate limits

Public endpoints allow 120 requests per 60 seconds per client IP. Every response carries the RateLimit header family so you can self-throttle instead of retrying into a 429:

  • RateLimit-Limit — requests permitted in the current window.
  • RateLimit-Remaining — requests still permitted. Omitted rather than guessed if the limiter could not report a count.
  • RateLimit-Reset — seconds until the window resets.
  • RateLimit-Policy — the named quota, e.g. "public";q=120;w=60.
  • A 429 additionally carries Retry-After in seconds.

Errors

Every non-2xx response uses one shape. Switch on code, show message, act on hint, and quote request_id if you need support. Codes are a closed set: bad_request, not_found, rate_limited, upstream_unavailable, internal_error.

{
  "error": {
    "code": "not_found",
    "message": "No integration matches the slug \"slak\".",
    "hint": "Search for the app with GET /api/v1/integrations?q=<name> and use the \"slug\" it returns.",
    "documentation_url": "https://www.conductordeck.com/developers#errors",
    "request_id": "0f0f2b1e-6d3a-4a2f-9d4c-7d1c2a5f9b10"
  }
}

Any /api/ path with no handler returns this shape as JSON with a 404 status, never an HTML error page.

Versioning and deprecation

The version is in the path: /api/v1. Every response also echoes X-API-Version.

Within a major version only backward-compatible changes ship: new endpoints, new optional parameters, and new fields on existing objects. Clients must ignore unknown response fields. Breaking changes ship under a new prefix while the previous version keeps answering.

When something is scheduled for removal, its responses carry Deprecation (RFC 9745) with the date the deprecation took effect and Sunset (RFC 8594) with the date it stops answering, plus a Link header with rel="deprecation" pointing at the migration notes. The minimum interval between the first Sunset header and removal is 180 days. Nothing is currently deprecated.

The full policy, including how each header is used and where to read the same commitments as data, is at /developers/versioning.

MCP server

Two Model Context Protocol servers exist, both listed in /.well-known/mcp.

The remote server at https://www.conductordeck.com/api/mcp speaks JSON-RPC 2.0 over the Streamable HTTP transport, is stateless, and needs no credential. Its five tools answer catalog questions: search_integrations, get_integration, list_workflow_templates, get_workflow_template, and get_docs_article.

The local server ships inside the Stream Deck plugin and is where running a workflow or driving hardware happens, because both need the user's own machine. Bridge a stdio client to it with the @conductordeck/mcp-shim npm package. Full tool reference: /mcp.

curl -s -X POST "https://www.conductordeck.com/api/mcp" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Machine-readable files

Markdown for public pages

Public pages answer with markdown when you ask for it explicitly, following the acceptmarkdown.com convention. Responses carry Vary: Accept, so a cache cannot hand a markdown reader the HTML variant. A URL that does not exist answers 404 with a markdown body listing where to look instead.

curl -sH "Accept: text/markdown" "https://www.conductordeck.com/docs/create-your-first-workflow"

Support

Questions about the API go to support@conductordeck.com. Include the request_id from the failing response. Live service state is on the status page.