SpinupSpinup Docs
Runtime API

Control Plane Agents

Read and manage workspace-scoped Spinup Agents through the public control-plane API.

Use the control-plane API when you need workspace-scoped metadata or basic management for a Spinup Agent. Authenticate with a workspace API key for SDK/direct API usage, or a personal/device key for CLI usage. Do not use an agent runtime key here.

Inspect an agent

curl -sS "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

Example response:

{
  "agent": {
    "id": "agent_01hxyz...",
    "name": "Support Agent",
    "slug": "support-agent",
    "createdAt": "2026-04-17T10:00:00.000Z",
    "updatedAt": "2026-04-17T10:05:00.000Z",
    "deploymentStatus": "pending_deploy",
    "hasUndeployedChanges": true,
    "undeployedChangeCount": 1,
    "activeRelease": {
      "id": "agent_release_01hxyz...",
      "version": 1,
      "status": "active",
      "stateVersionId": "agentstateversion_01hxyz...",
      "createdAt": "2026-04-17T10:04:00.000Z",
      "lastMaterializationStatus": "ready",
      "lastMaterializationError": null,
      "lastMaterializedAt": "2026-04-17T10:06:00.000Z"
    },
    "modelPolicy": {
      "provider": "openai",
      "model": "gpt-5.4"
    },
    "harnessTargets": [
      { "harnessName": "openclaw", "enabled": true, "role": "default" },
      { "harnessName": "hermes", "enabled": true, "role": "available" }
    ],
    "capabilityBindings": [],
    "runtimePolicy": {
      "resourceLimits": { "memoryMiB": 4096, "diskGiB": 4 },
      "networkPolicy": { "mode": "allow_all", "allowList": [] },
      "storagePolicy": { "persistent": true, "sizeGb": 4 }
    }
  },
  "environment": {
    "status": "ready",
    "attention": "none",
    "readyAt": "2026-04-17T10:06:00.000Z",
    "createdAt": "2026-04-17T10:01:00.000Z",
    "updatedAt": "2026-04-17T10:06:00.000Z",
    "lastError": null,
    "runtimeReconciliation": {
      "status": "applied",
      "lastError": null
    }
  }
}

The response is an inspection-safe subset of the agent's current draft model, harnesses, capabilities, runtime sizing and network policy, active release, pending-deploy state, and environment status. It does not return secret values or internal runtime identifiers.

Configuration writes update the agent's draft. Runs, schedules, and Agent Chat use the active release. When deploymentStatus is draft_only there is no active release yet; when it is pending_deploy, the saved draft differs from the active release; when it is deployed, the draft and active release match.

You won't find snapshot lifecycle controls in these examples on purpose. Spinup manages runtime persistence for you today, and there's no public way to stop, start, or snapshot an agent through /v1. A customer-operable lifecycle is on the roadmap; for now, persistence is a property the runtime guarantees, not a primitive you call.

Create an agent

curl -sS "https://api.getspinup.com/v1/workspaces/acme/agents" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Support Agent" }'

Creation saves a draft-only agent. It does not start runtime capacity and cannot run until you deploy it.

Deploy an agent

Deploy promotes the current draft configuration into the active release used by future runs, schedules, and Agent Chat. It does not start a microVM by itself.

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/deploy" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

The response is the same inspection shape as GET /workspaces/{workspaceSlug}/agents/{agentSlug}. After a successful deploy, deploymentStatus is usually deployed, activeRelease contains the promoted release, and runtime materialization still waits for a run, schedule dispatch, or Agent Chat.

Rename an agent

curl -sS -X PATCH "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Support Agent v2" }'

The returned agent.slug may change after a rename.

Update model and runtime policy

Use the same patch endpoint for primary model and supported runtime policy changes:

curl -sS -X PATCH "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{
    "primaryModel": {
      "provider": "openai",
      "model": "gpt-5.4",
      "maxOutputTokens": 64000
    },
    "runtimePolicy": {
      "allowedPackageInstallationMode": "declared",
      "resourceLimits": {
        "memoryMiB": 8192,
        "diskGiB": 10
      }
    }
  }'

Public runtime sizing accepts memory values 4096, 8192, or 16384 MiB and disk values 4 or 10 GiB. Model updates use the provider and model identifiers returned in the agent inspection shape, and may fail when the workspace is missing the provider credential required by that model. primaryModel.maxOutputTokens caps the model response budget for each run; omit it to use Spinup's default of 64000.

The patch response reflects the saved draft and sets deploymentStatus to draft_only or pending_deploy until you call the deploy endpoint.

Update the default harness

curl -sS -X PATCH "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/harnesses" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{ "defaultHarness": "hermes" }'

Today, the supported harness names are openclaw and hermes. Spinup keeps supported harnesses available for the agent; this endpoint only chooses which one is used when a runtime request does not specify harness.

Default harness updates save draft configuration. Future runs keep using the active release default until you deploy the draft.

Issue a runtime key

Use a control-plane key to issue or replace the agent-scoped runtime key. The response includes the plaintext apiKey once and the durable agentId you must use with /v1/agents/{agentId}/status and /v1/agents/{agentId}/runs.

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/runtime-key" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

Example response:

{
  "agentId": "agent_01hxyz...",
  "agentSlug": "support-agent",
  "apiKeyId": "apikey_01hxyz...",
  "apiKey": "sk_agent_0123456789abcdef..."
}

Issuing a new runtime key immediately replaces the previous mapped runtime key for that agent. Agent runtime keys cannot mint or rotate themselves.

Add a capability

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/capabilities" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{
    "capability": {
      "kind": "skill",
      "name": "vercel-react-best-practices",
      "source": "vercel-labs/agent-skills",
      "installPlan": {
        "strategy": "skill",
        "manager": "skills_cli",
        "skillName": "vercel-react-best-practices",
        "source": "vercel-labs/agent-skills"
      },
      "validationPlan": {
        "strategy": "skills_lock",
        "skillName": "vercel-react-best-practices",
        "source": "vercel-labs/agent-skills"
      }
    }
  }'

For skills, installPlan.source is the exact Skills CLI source passed to skills add. Set installPlan.skillName only when you want Spinup to pass --skill; omit it or set it to null for direct skill paths or sources that should install without a selector.

Capabilities are the public control-plane surface for skills and future installable capabilities. Use PATCH /capabilities/{capabilityId} to update writable fields such as status, and DELETE /capabilities/{capabilityId} to remove one.

Capability updates save draft configuration. Future runs keep using the active release capability set until you deploy the draft.

Manage schedules

Use schedules when an agent should run on a recurring cadence without an external cron job. Schedules are workspace-scoped control-plane resources under the agent slug.

Create a weekly cron schedule:

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/newsletter/schedules" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": {
      "name": "Friday newsletter",
      "input": "Draft the weekly newsletter",
      "timezone": "Europe/Amsterdam",
      "cadence": {
        "kind": "cron",
        "expression": "0 9 * * 5",
        "syntaxVersion": "spinup-cron-v1",
        "timezone": "Europe/Amsterdam"
      }
    }
  }'

Preview upcoming occurrences:

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/newsletter/schedules/preview" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": {
      "timezone": "Europe/Amsterdam",
      "cadence": {
        "kind": "cron",
        "expression": "0 9 * * 5",
        "syntaxVersion": "spinup-cron-v1",
        "timezone": "Europe/Amsterdam"
      }
    }
  }'

List, update, disable, or delete schedules:

curl -sS "https://api.getspinup.com/v1/workspaces/acme/agents/newsletter/schedules" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

curl -sS -X PATCH "https://api.getspinup.com/v1/workspaces/acme/agents/newsletter/schedules/agentsched_01hxyz..." \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{ "schedule": { "enabled": false } }'

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/newsletter/schedules/agentsched_01hxyz.../disable" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

curl -sS -X DELETE "https://api.getspinup.com/v1/workspaces/acme/agents/newsletter/schedules/agentsched_01hxyz..." \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

Scheduled dispatch starts normal Spinup runs. The agent needs an active deploy/release before a schedule can execute successfully; if there is no deployable active release, Spinup records the blocked scheduled occurrence and pauses the schedule for action.

Manage capabilities

See Capabilities for the concept. Use the control-plane API to list, add, update, or remove declared capability settings.

You can set capability status to declared or disabled. Runtime statuses such as materialized, validated, projected, available, and failed are recorded by Spinup as environment evidence, not written directly through this API.

List capabilities:

curl -sS "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/capabilities" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

Add a declared CLI requirement:

curl -sS -X POST "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/capabilities" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{
    "capability": {
      "kind": "cli",
      "name": "ffmpeg",
      "source": "spinup-runtime",
      "status": "declared",
      "validationPlan": {
        "strategy": "executable",
        "executable": "ffmpeg",
        "versionArgs": ["-version"]
      }
    }
  }'

Update or disable a capability:

curl -sS -X PATCH "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/capabilities/capability_01hxyz..." \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{ "capability": { "status": "disabled" } }'

Remove a capability:

curl -sS -X DELETE "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent/capabilities/capability_01hxyz..." \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..."

The response includes the saved state version, the current capability list, and any missing secret requirements. Secret values are never returned.

Delete an agent

curl -sS -X DELETE "https://api.getspinup.com/v1/workspaces/acme/agents/support-agent" \
  -H "Authorization: Bearer sk_workspace_0123456789abcdef..." \
  -H "Content-Type: application/json" \
  -d '{ "confirmationSlug": "support-agent" }'

The confirmation value must match the current agent slug. If the agent has a ready environment, deletion first follows the same teardown path used by the dashboard. If an environment lifecycle operation is in progress, deletion is rejected.