REST API Overview

The clanker REST API provides programmatic access to skills, artifacts, executions, and billing.

Base URL

https://clanker.net/api

Authentication

All API requests require authentication via one of:

MethodHeaderFormat
API Key (recommended)x-api-keyck_live_xxxxxxxxxxxxx — workspace-scoped at creation
Auth Tokenx-auth-tokenSession token from mobile app sign-in
Workspace overridex-workspace-idOptional UUID — session callers only

See Authentication for details, including the External Agents device-code flow for pairing external CLIs.

Request Format

  • Content-Type: application/json for POST/PUT/PATCH requests
  • Accept: application/json for all requests
curl https://clanker.net/api/v1/marketplace/skills \
  -H "x-auth-token: YOUR_AUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json"

Response Format

Success Response

{
  "items": [ ... ],
  "total": 42,
  "limit": 20,
  "offset": 0,
  "hasMore": true
}

Or for simple responses:

{
  "success": true,
  "message": "..."
}

Error Response

Every error is the same envelope:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Skill not found",
    "details": { "field": "slug", "rule": "required" }
  }
}
FieldNotes
error.codeMachine-stable. This is what you branch on. See Error Codes.
error.messageHuman, English, developer-facing. May be reworded or translated at any time — never match on it.
error.detailsOptional structured context, e.g. { field, rule } for validation failures.

Two shapes are deliberately different and worth knowing about:

  • Some responses carry an extra top-level sibling next to error when a client needs to branch on it — e.g. isRunning on a skill-install conflict. It is not inside details because that is exactly the field the client reads.

Common Endpoints

Skills (Public)

MethodEndpointDescription
GET/api/v1/marketplace/skillsList marketplace skills
GET/api/v1/marketplace/skills/categoriesList skill categories
GET/api/v1/marketplace/skills/:slugGet skill details

Skills (User)

MethodEndpointDescription
GET/api/v1/skillsList user’s installed skills
POST/api/v1/skills/:slug/installInstall a skill
GET/api/v1/skills/:slug/versionsVersion history, newest first
POST/api/v1/skills/:slug/versions/:versionNumber/restoreRestore a version (non-destructive: creates a new version)
POST/api/v1/skills/:slug/uninstallUninstall a skill
POST/api/v1/skills/:slug/runExecute a skill (interactive use only)

Note: Direct skill execution is for interactive use (dashboard, MCP/IDE). For bots, CI/CD, and all external integrations, use Workflows — they provide durable execution, automatic queueing, and crash recovery.

Artifacts

MethodEndpointDescription
GET/api/v1/artifactsList artifacts
GET/api/v1/artifacts/:idGet artifact details
GET/api/v1/artifacts/:id/downloadDownload artifact
DELETE/api/v1/artifacts/:idDelete artifact

Executions

MethodEndpointDescription
POST/api/v1/executionsCreate idle execution (Sessions API step 1)
GET/api/v1/executionsList execution history
GET/api/v1/executions/limitCheck execution limit
GET/api/v1/executions/:id/statusGet execution status
GET/api/v1/executions/:id/stream-tokenMint a signed SSE URL for a single execution (Sessions API step 2)
POST/api/v1/executions/:id/eventsSend user.message / user.interrupt (Sessions API step 3)
POST/api/v1/executions/:id/cancelCancel an active execution
POST/api/v1/executions/:id/rerunRerun a completed execution

User Profile & API Keys

MethodEndpointDescription
GET/api/v1/profileGet user profile
PATCH/api/v1/profileUpdate user profile
GET/api/v1/identitiesList user identities
GET/api/v1/api-keysList API keys
POST/api/v1/api-keysCreate API key
DELETE/api/v1/api-keys/:keyIdDelete API key
GET/api/v1/byokGet BYOK key status
PUT/api/v1/byokSet BYOK LLM API key
DELETE/api/v1/byokRemove BYOK key

Device Activation (External Agents)

For agents that need a fresh API key paired through the mobile app’s device-flow (8-char XXXX-XXXX user code). RFC 8628 device authorization — the API key is workspace-bound at issuance.

MethodEndpointDescription
POST/api/v1/activateStart device flow — returns device_code, user_code, verification URL
POST/api/v1/activate/pollPoll for approval — returns api_key when approved
GET/api/v1/activate/lookup(Mobile/web) lookup pending-code metadata to render the approval UI
POST/api/v1/activate/confirm(Mobile/web) approve device code, mint API key
POST/api/v1/activate/deny(Mobile/web) deny device code

For agents that already hold an API key and want to declare the scope set they actually need — the user approves a scoped consent in the mobile app, and a per-request grant token is issued. Full details in /skill.md § “Agent Permissions”.

MethodEndpointDescription
POST/api/v1/agents/connectDeclare desired scopes — returns consent_id, link_code, poll_url
GET/api/v1/agents/connect/poll/:consentIdPoll for approval — once-only emits grant_token + final scopes
POST/api/v1/agents/connect/by-code(Mobile) look up an activation by its link code
POST/api/v1/agents/request-permissionRequest a single additional scope mid-conversation
GET/api/v1/agents/request-permission/poll/:requestIdPoll the escalation — emits grant_token once
DELETE/api/v1/agents/:keyId/scopes/:scope(Mobile/web) revoke a single scope from a key

Grant tokens are sent via x-permission-grant: <token> on subsequent calls. Permission failures use the standard envelope — a credential missing a scope gets 403 with error.code = FORBIDDEN and a message naming the scope. Branch on the code, never on the message.

Billing

MethodEndpointDescription
GET/api/v1/billing/balanceGet balance info
GET/api/v1/billing/packsList credit packs
POST/api/v1/billing/purchasePurchase credits
GET/api/v1/billing/transactionsGet transaction history
GET/api/v1/billing/subscription/tierGet subscription tier
GET/api/v1/billing/subscription/infoGet subscription info
GET/api/v1/billing/publishable-keyGet billing publishable key

Workflows

MethodEndpointDescription
GET/api/v1/workflowsList workflows installed in the active workspace
GET/api/v1/workflows/:slugGet a single workflow, definition included
POST/api/v1/workflows/:slug/installInstall a JSON workflow definition
POST/api/v1/workflows/:slug/uninstallUninstall a workflow
DELETE/api/v1/workflows/:slugSame operation, addressed as a deletion
POST/api/v1/workflows/install-from-artifactInstall a workflow from a saved artifact
GET/api/v1/workflows/definitionsWhat this workspace can launch, and with what inputs
POST/api/v1/workflows/:id/launchStart a workflow run (accepts inputs); returns a runId
GET/api/v1/workflows/runsList workflow runs (manual and chat-started)
GET/api/v1/workflows/runs/:runIdGet workflow run details + step history
GET/api/v1/workflows/runs/:runId/eventsStream a run’s step-snapshot events over SSE
POST/api/v1/workflows/runs/:runId/cancelCancel a workflow run
POST/api/v1/workflows/runs/:runId/resumeResume a suspended workflow
GET/api/v1/workflows/queueList queued/active runs for the workspace
DELETE/api/v1/workflows/queue/:runIdRemove a run from the queue

Workspaces

MethodEndpointDescription
GET/api/v1/workspacesList user’s workspaces
POST/api/v1/workspacesCreate workspace
GET/api/v1/workspaces/currentGet current workspace
PATCH/api/v1/workspaces/:workspaceIdUpdate workspace
DELETE/api/v1/workspaces/:workspaceIdDelete workspace
GET/api/v1/workspaces/:workspaceId/membersList members
POST/api/v1/workspaces/:workspaceId/invitationsInvite a user
DELETE/api/v1/workspaces/:workspaceId/members/:userIdRemove a member
PATCH/api/v1/workspaces/:workspaceId/members/:userIdChange member role
POST/api/v1/workspaces/:workspaceId/leaveLeave a workspace
POST/api/v1/workspaces/:workspaceId/transferTransfer workspace ownership
GET/api/v1/workspaces/:workspaceId/invitationsList pending invitations
DELETE/api/v1/workspaces/:workspaceId/invitations/:invitationIdRevoke invitation
GET/api/v1/invitations/:tokenPreview invitation
POST/api/v1/invitations/:token/acceptAccept invitation

Connectors

MethodEndpointDescription
GET/api/v1/connectors/availableList available connectors
GET/api/v1/connectors/listList configured connectors
GET/api/v1/connectors/statusGet all connector statuses
GET/api/v1/connectors/:type/auth-urlGet OAuth URL
GET/api/v1/connectors/:type/statusGet connector status
GET/api/v1/connectors/:type/configGet connector config
POST/api/v1/connectors/:type/disconnectDisconnect connector
GET/api/v1/connectors/:type/sourcesList connector sources
GET/api/v1/connectors/:type/sources/:repo/branchesList branches for a source

GitHub-specific (first-class)

MethodEndpointAuthDescription
GET/api/v1/connectors/github/confignoneIs the GitHub connector configured?
POST/api/v1/connectors/github/publishx-auth-tokenPublish workspace skills/agents/workflows to a user repo
POST/api/v1/connectors/github/create-prAPI key or sessionOpen a PR from execution diffs

Agents

MethodEndpointDescription
POST/api/v1/chat/:agentIdStream a chat with a workspace-installed agent. Default seed gives every workspace clanka-01; the marketplace adds more. The agentId must match an installed slug. Response carries an x-clanker-run-id header for resumable reconnect.
GET/api/v1/chat/:agentId/streamReconnect to a dropped turn. Query: runId (required, from the x-clanker-run-id response header), threadId, offset (chunks already received, default 0). Replays cached chunks, then resumes the live tail.
POST/api/v1/chat/:agentId/warmPre-warm the chat agent + DB connection ahead of the first turn. Fire-and-forget; never errors.
GET/api/v1/agentsList agents installed in the workspace
GET/api/v1/agents/:slugGet one installed agent
POST/api/v1/agents/installInstall an agent from marketplace ({slug}) or content ({slug,content})
POST/api/v1/agents/install-from-artifactInstall an agent from a saved artifact
DELETE/api/v1/agents/:slugUninstall an agent
GET/api/v1/marketplace/agentsBrowse marketplace agents
GET/api/v1/marketplace/agents/:slugMarketplace agent detail

Threads (Chat History)

Threads are conversation containers — chat messages live inside them.

MethodEndpointDescription
GET/api/v1/threadsList threads in the active workspace (optional apiKeyId filter)
POST/api/v1/threadsCreate a thread
GET/api/v1/threads/:threadIdGet a thread
DELETE/api/v1/threads/:threadIdDelete a thread
GET/api/v1/threads/:threadId/messagesList messages in a thread
POST/api/v1/threads/save-messagesBulk save messages
GET/api/v1/threads/:threadId/membersSnapshot of clients currently active in the thread (presence)

Workspace Memory

Working memory is a workspace-scoped Markdown document the agent reads and writes between turns.

MethodEndpointDescription
GET/api/v1/memoryRead workspace working memory
PUT/api/v1/memoryWrite workspace working memory

Secrets

Per-workspace encrypted credentials. Skills request them at execution time; the screen never shows the raw value.

MethodEndpointDescription
GET/api/v1/secretsList workspace secrets (names only)
POST/api/v1/secretsCreate or update a secret ({name, value})
PUT/api/v1/secrets/:idUpdate secret value
DELETE/api/v1/secrets/:idDelete a secret
GET/api/v1/skills/:skillId/secretsList the secret bindings for an installed skill
POST/api/v1/skills/:skillId/secretsBind a workspace secret to a skill env var
DELETE/api/v1/skills/:skillId/secrets/:bindingIdRemove a skill secret binding

Channels

MethodEndpointDescription
GET/api/v1/channelsWhatsApp channel status for this deployment

The inbound webhook (/api/webhooks/whatsapp/{agentId}, GET for Meta’s verification challenge and POST for message events) is not listed above: it is called by Meta, not by an API client, and authenticates with an HMAC-SHA256 signature rather than a Clanker credential. Inbound third-party callbacks live under /api/webhooks/* and are deliberately unversioned — their URLs sit in someone else’s console, so a version bump would be a coordinated external edit.

MethodEndpointAuthDescription
POST/api/v1/searchsession onlyFull-text search across marketplace, library, artifacts, and memory

Activity — what CHANGED

The workspace change log. See Activity Endpoints.

MethodEndpointAuthDescription
GET/api/v1/activityAPI key or sessionChange log: object mutations, membership, approvals
GET/api/v1/activity/subscribe-urlAPI key or sessionSigned WebSocket URL for the live tail

Traces — what agents DID

Agent runs, turn by turn. See Traces Endpoints.

MethodEndpointAuthDescription
GET/api/v1/tracesAPI key or sessionList runs (filter by kind/status/range)
GET/api/v1/traces/:idAPI key or sessionOne run
GET/api/v1/traces/:id/eventsAPI key or sessionIts turns
POST/api/v1/traces/:id/eventsAPI key or sessionAppend turns (the update primitive)
POST/api/v1/traces/:id/continueAPI key or sessionGet the handle to continue it

Workspace Dashboard

These are scoped by the x-workspace-id header (or the workspace baked into an API key) — there is no workspace id in the path. See Workspace scoping.

MethodEndpointAuthDescription
GET/api/v1/statsAPI key or sessionSessions / sandbox / streak / library tiles
GET/api/v1/stats/dailyAPI key or sessionContribution heatmap series
GET/api/v1/workspace/model-policyAPI key or sessionRead the workspace model policy
PATCH/api/v1/workspace/model-policyAPI key or sessionUpdate it (owner/admin only)
GET/api/v1/workspace/clientssession only“Clients” tiles (one per active API key)
GET/api/v1/workspace/clients/:apiKeyIdsession onlyPer-client summary
POST/api/v1/workspace/clients/:apiKeyId/revokesession onlyRevoke an API key
GET/api/v1/workspace/content-languageAPI key or sessionLanguage the agent replies in (null = inherit)
PATCH/api/v1/workspace/content-languageAPI key or sessionSet it (owner/admin only)

Account Settings

Personal, account-level state — distinct from the workspace settings above. A transcript is shared, so the language the agent replies in is a workspace property; the language your UI renders in is yours.

MethodEndpointDescription
GET/api/v1/settings/languageAccount UI language — { "language": "en" }, null = device locale
PUT/api/v1/settings/languageSet or clear it — { "language": "es" } or { "language": null }
GET/api/v1/settings/default-modelYour account-level default model
PUT/api/v1/settings/default-modelSet it
GET/api/v1/modelsModels you may actually select (deployment allow-list ∩ workspace policy)
POST/api/v1/onboarding/completeMark onboarding done — idempotent, keeps the original timestamp

Audit Logs

MethodEndpointDescription
GET/api/v1/audit-logs?action=…Audit log entries (cursor pagination)

Bootstrap / Identity

MethodEndpointDescription
GET/api/v1/bootstrapCombined profile + workspaces payload — recommended single startup request
GET/api/v1/auth/configServer auth capabilities (e.g. SSO enabled?) — no auth required
POST/api/v1/push-token(Session only) Register a device push token for mobile notifications

Real-time Events

MethodEndpointDescription
GET/api/v1/events/subscribe-urlSigned WebSocket URL for the signed-in user’s realtime channel — execution-state + cache-invalidation events

MCP

MethodEndpointAuthDescription
POST/mcp/x-api-keyMCP Streamable HTTP transport
GET/.well-known/mcp/server-card.jsonnoneMCP server discovery document

MCP traffic is served by the dedicated MCP edge worker, not by the REST backend. Point clients at https://clanker.net/mcp/ and the request is routed transparently.

Rate Limiting

API requests are rate-limited to 100 requests per minute per user. Skill execution endpoints are limited to 30 requests per minute.

Rate limit headers are included in responses:

x-ratelimit-limit: 100
x-ratelimit-remaining: 98
x-ratelimit-reset: 45

Pagination

List endpoints support pagination:

GET /api/v1/artifacts?limit=20&offset=0
ParameterTypeDefaultDescription
limitnumber20Max results per page
offsetnumber0Number of results to skip

SSE Streaming

Execution results stream over Server-Sent Events (SSE) using the Sessions API three-step flow:

  1. Create an idle execution — POST /api/v1/executions
  2. Connect to the live stream — GET /api/v1/executions/:id/stream-token returns a signed sseUrl; open it before step 3
  3. Send input to trigger the run — POST /api/v1/executions/:id/events with a user.message event

The stream replays all history from the beginning, then delivers live events, and closes automatically when session.status_idle arrives.

See Executions API for event types, stop reasons, reconnect parameters, and the session-level stream.

Workflow Results

Launching a workflow (POST /api/v1/workflows/:id/launch) accepts only inputs and returns a runId immediately. The run is asynchronous — retrieve its outcome by polling the run or streaming it:

# Poll until terminal
curl https://clanker.net/api/v1/workflows/runs/run-1770000000000-8fq2k1 \
  -H "x-api-key: ck_live_xxxxxxxxxxxxx"
# → { "run": { "status": "success", ... }, "steps": { "<stepId>": { ... } } }

Terminal statuses are success, failed and canceled; suspended means the run is parked waiting for a human and resumes on request.

For live step events, open the SSE stream at GET /api/v1/workflows/runs/:runId/events (using the runId from launch). Workflows started from a chat thread also report completion back into that thread automatically.

See the Workflows API for full details.

Error Codes

These are the values of error.code. Codes are stable; the accompanying error.message is not.

CodeHTTP StatusDescription
UNAUTHORIZED401Invalid or missing auth
ACTIVATION_REQUIRED409The API key exists but has not been activated yet
FORBIDDEN403Authenticated, but lacks the role, scope or ownership
NOT_FOUND404Resource not found
INSUFFICIENT_CREDITS402Not enough credits
INVALID_INPUT400Malformed or missing request data
VALIDATION_FAILED400A field failed validation — details names it
INVALID_CONNECTOR400Unknown or unsupported connector type
CONNECTOR_NOT_CONFIGURED400Connector not configured on this platform
CONNECTOR_NOT_CONNECTED403User has not connected this connector
ALREADY_EXISTS409The resource is already there
CONFLICT409The request conflicts with the resource’s state
EXECUTION_RUNNING429Another execution is active in this workspace
EXPIRED410Invitation, device code, or retired endpoint
RATE_LIMITED429Too many requests
EXECUTION_FAILED500The run itself failed
INTERNAL_ERROR500Server error
SERVICE_UNAVAILABLE502/503/504A dependency we proxy to is down — retrying may work

This table is pinned against the server’s own ErrorCodes by server/__tests__/api-docs-drift.test.ts — adding a code without a row here, or leaving a row for a code that no longer exists, fails that test.

Statuses are the usual mapping, not a guarantee: a route may answer with a more specific status when it has one. Branch on the code and read the status as a hint, not the reverse.

SDK & Libraries

Currently, no official SDKs are available. We recommend using the MCP protocol with compatible AI clients, or making direct HTTP requests.

Example with fetch:

const response = await fetch("https://clanker.net/api/v1/marketplace/skills", {
  headers: {
    "x-auth-token": process.env.CLANKER_AUTH_TOKEN,
    "Content-Type": "application/json",
  },
});

const skills = await response.json();

Example with curl:

curl https://clanker.net/api/v1/marketplace/skills \
  -H "x-auth-token: $CLANKER_AUTH_TOKEN"