Skip to content
Thyme Docs

Management API

The Flow Management API exposes projects, enabled chains, immutable function releases, executables, execution history and logs, profiles, executable storage, project secrets, and executable webhooks.

Use the HTTP API base URL for the deployment you intend to manage. Development and production have separate resources and credentials. Examples use:

export THYME_API_URL='https://YOUR_FLOW_API_HOST/http'

Replace this placeholder with the supplied API base, including any deployment path prefix. A Console website URL is not necessarily its HTTP API base. The CLI's packaged default is documented under API URL configuration; select the development URL explicitly when working with the development rollout.

All versioned routes start with /api/v1. Function bundle upload currently uses POST /api/task/upload because it accepts multipart form data.

Authentication

Create a workspace-bound management credential through the CLI:

thyme login --management

The browser consent screen requires an owner or admin to select one workspace. The resulting token cannot access a different workspace. Send it as a bearer token:

curl "$THYME_API_URL/api/v1/projects" \
  -H "Authorization: Bearer $THYME_AUTH_TOKEN"

Legacy unbound keys must also send X-Workspace-Id. When both the header and a workspaceId query parameter are present, they must match. A bound key rejects either value when it names another workspace.

Scopes

Every route checks one narrow scope. Management consent grants the complete Flow management bundle:

ResourceReadWrite or privileged action
Projectsprojects:readprojects:write
Chainschains:read—
Functionsfunctions:readfunctions:upload, functions:delete, functions:source
Executablesexecutables:readexecutables:write, executables:run
Executionsexecutions:read—
Storagestorage:readstorage:write
Profilesprofiles:readprofiles:write
Secretssecrets:readsecrets:write
Webhookswebhooks:readwebhooks:write
Usageusage:read—

Management access intentionally does not cover project deletion, private-key import, billing, workspace/member administration, or API-key administration. Read operations require active workspace membership and the corresponding scope. Mutations additionally require an owner or admin role. Losing membership or revoking the key removes access even when the client still has a stored token.

The profile creation route is the legacy account creation path. It does not replace the owner wallet signatures used to onboard a Safe or Roles profile in the Console. Legacy creation can be disabled by the deployment.

Idempotency and request IDs

Send Idempotency-Key on a mutating request to make its response replayable for 24 hours. Use a unique key for each intended operation and target resource. Reusing the key for the same method, route template, credential, workspace, and canonical JSON body returns the original status and body with Idempotency-Replayed: true. Reusing it with a different request returns 409 idempotency_conflict when the recorded request fingerprint differs.

The current fingerprint uses the route template, and some actions do not include the resource ID in their body. Reusing a key across two resource IDs can therefore replay the first response. Include the target ID in your key, for example pause-EXECUTABLE_ID-CHANGE_ID, even when the request body is identical.

The CLI generates a key automatically for mutations and retries a network failure once with that same key. For a manual retry, provide your own stable key:

curl -X POST "$THYME_API_URL/api/v1/projects" \
  -H "Authorization: Bearer $THYME_AUTH_TOKEN" \
  -H "Idempotency-Key: project-acme-production" \
  -H "Content-Type: application/json" \
  --data '{"name":"Acme","slug":"acme","environment":"production"}'

Every management response includes an X-Request-Id header. Include it when reporting an API failure. Errors use a stable shape:

{
  "error": "Pause the executable before changing its function",
  "code": "executable_must_be_paused",
  "requestId": "3e6d..."
}

Unknown server failures are deliberately opaque; provider messages, stack frames, and configuration values are not returned.

The multipart upload endpoint uses release name, version tag, and archive checksum for deduplication; it does not use the management mutation replay mechanism. See uploading a function.

See Errors & Retries for in-progress requests, permission refusals, and recovery steps. Save both the idempotency key and request ID with your automation logs; never log the bearer token.

Pagination

Collection routes that may grow large accept limit (default 50, maximum 200) and cursor. The response is:

{
  "data": [],
  "pagination": {
    "cursor": "opaque-convex-cursor",
    "isDone": false
  }
}

Pass the returned cursor unchanged on the next request. Stop when isDone is true. Projects, chains, secrets, and executable webhook lists return { "data": [...] } without a pagination object. Execution lists at /api/v1/executions also accept a status filter.

Function releases

A function is an immutable release identified by (projectId, name, versionTag). A new name defaults to v1; another upload or copy into that name must supply a tag. Tags are lowercase, 1–32 characters, match ^[a-z0-9][a-z0-9._-]{0,31}$, and latest is reserved. A deleted tag remains reserved.

Repeating the same active name, tag, and checksum returns the existing function. The same tag with different code returns version_tag_conflict, together with reservedVersionTags and suggestedVersionTag.

Changing an executable's function is not an in-place code edit. Pause the executable, then call its function patch route with the target function ID. The API returns 202 with a switch request ID and rebuilding state. A new sandbox is built asynchronously and committed atomically; the previous function and sandbox remain live if the build fails.

Storage and secrets

Executable storage is stored directly in Convex file storage; R2 or another external object store is not required. The runtime storage ceiling is 100 MiB, but this JSON HTTP endpoint accepts and returns at most 16 MiB so its envelope stays below Convex's 20 MiB HTTP-action boundary. Writes require expectedVersion, providing optimistic concurrency and protecting state while an execution holds the storage lock.

Project secret values are write-only. Create and rotate operations send a value, but list and mutation responses return metadata only. Values are never returned through the management API.

Permissions and execution environments

An uploaded permissions.json is part of the checksummed archive. Creating an executable, switching its function/profile, changing args, and resuming can reject a release whose permissions are not covered by its profile. A binding refusal returns 409 permissions_not_covered, with diagnostic fields described in Errors & Retries. Edit the task's manifest and upload a new release or extend the on-chain role through its owner; an API key cannot grant wallet permissions.

Real execution checks permissions again asynchronously. An accepted /run request can later fail that check; read the execution and logs for its outcome. API clients must supply valid JSON-encoded args matching the function schema; the management API does not run all of the Console's args validation before storing an update. The task runtime validates args when it runs.

sandboxRuntime selects daytona or gvisor when creating an executable. The default is daytona. The deployment must have the selected runtime available. The sandbox runs task code; the profile separately controls on-chain execution. See runtime limits and profiles.

See Resources for routes and examples, browse the interactive reference, or download the OpenAPI 3.1 document.