@getspinup/sdk
v1.3.0
Published
Fetch-based client for the Spinup public API.
Downloads
1,485
Readme
@getspinup/sdk
Fetch-based client for the Spinup public API.
Install
npm install @getspinup/sdkFirst Success Workflow
Create a client with a workspace API key and default workspace slug from your own app configuration, then create a Spinup Agent and read back its environment status:
import { SpinupApiError, createSpinupClient } from "@getspinup/sdk";
const spinup = createSpinupClient({
apiKey: process.env.SPINUP_API_KEY,
defaultWorkspaceSlug: process.env.SPINUP_WORKSPACE,
});
try {
const created = await spinup.agents.create({
name: "Docs Runner",
});
console.log("created", created.agent.slug, created.environment.status);
const agents = await spinup.agents.list();
console.log(
"agents",
agents.agents.map((agent) => `${agent.slug}:${agent.status}`),
);
const current = await spinup.agents.get({
agentSlug: created.agent.slug,
});
console.log("current status", current.environment.status);
} catch (error) {
if (error instanceof SpinupApiError) {
console.error("Spinup API error", {
code: error.code,
message: error.message,
status: error.status,
});
} else {
throw error;
}
}You can still override those values per call:
await spinup.agents.list({
apiKey: process.env.OTHER_SPINUP_API_KEY,
workspaceSlug: "other-workspace",
});In Cloudflare Workers or other edge runtimes, pass bindings from the request handler's env argument instead of reading process.env at module scope. The Env type is generated from your Worker bindings:
import { createSpinupClient } from "@getspinup/sdk";
export default {
async fetch(_request, env) {
const spinup = createSpinupClient({
apiKey: env.SPINUP_API_KEY,
defaultWorkspaceSlug: env.SPINUP_WORKSPACE,
});
const agents = await spinup.agents.list();
return Response.json({ agents: agents.agents });
},
} satisfies ExportedHandler<Env>;Public Resources
The SDK exposes workspace-scoped control-plane operations:
spinup.me.get()spinup.workspaces.list()spinup.workspaces.secrets.list()spinup.workspaces.secrets.get({ secretId })spinup.workspaces.secrets.create({ name, defaultProjectionName, value })spinup.workspaces.secrets.update({ secretId, name, defaultProjectionName, value })spinup.workspaces.secrets.delete({ secretId })spinup.agents.list()spinup.agents.get({ agentSlug })spinup.agents.create({ name })spinup.agents.update({ agentSlug, name })spinup.agents.update({ agentSlug, primaryModel: { provider, model } })spinup.agents.update({ agentSlug, runtimePolicy: { allowedPackageInstallationMode } })spinup.agents.update({ agentSlug, runtimePolicy: { resourceLimits: { memoryMiB, diskGiB } } })spinup.agents.updateHarnesses({ agentSlug, defaultHarness })spinup.agents.instructions.get({ agentSlug })spinup.agents.instructions.set({ agentSlug, coreInstructions })spinup.agents.instructions.clear({ agentSlug })spinup.agents.setupCommand.get({ agentSlug })spinup.agents.setupCommand.set({ agentSlug, setupCommand })spinup.agents.setupCommand.clear({ agentSlug })spinup.agents.capabilities.list({ agentSlug })spinup.agents.capabilities.add({ agentSlug, capability })spinup.agents.capabilities.update({ agentSlug, capabilityId, capability })spinup.agents.capabilities.remove({ agentSlug, capabilityId })spinup.agents.runtimeKey.issue({ agentSlug })spinup.agents.schedules.list({ agentSlug })spinup.agents.schedules.create({ agentSlug, schedule })spinup.agents.schedules.update({ agentSlug, scheduleId, schedule })spinup.agents.schedules.disable({ agentSlug, scheduleId })spinup.agents.schedules.delete({ agentSlug, scheduleId })spinup.agents.schedules.preview({ agentSlug, schedule })spinup.agents.secretBindings.list({ agentSlug })spinup.agents.secretBindings.update({ agentSlug, bindings, expectedStateVersion })spinup.agents.proposedChanges.list({ agentSlug, status })spinup.agents.proposedChanges.get({ agentSlug, proposedChangeId })spinup.agents.proposedChanges.approve({ agentSlug, proposedChangeId, expectedBaseStateVersionId, expectedPayloadHash })spinup.agents.proposedChanges.reject({ agentSlug, proposedChangeId, reason })spinup.agents.delete({ agentSlug, confirmationSlug })
The SDK also exposes agent-runtime operations that require an agent runtime key (sk_agent_...) scoped to the target agentId:
spinup.agents.status({ agentId })spinup.agents.runs.list({ agentId })spinup.agents.runs.create({ agentId, input, model })spinup.agents.runs.get({ agentId, runId })spinup.agents.runs.wait({ agentId, runId })
Use spinup.agents.runtimeKey.issue({ agentSlug }) with a workspace or personal/device control-plane key to issue or replace that one-agent runtime key. The returned plaintext apiKey is shown once, and the returned agentId is the identifier used by runtime status and run methods.
Device authorization is CLI-only. Use a dashboard-created workspace API key for application code.
Use spinup.agents.capabilities.update({ agentSlug, capabilityId, capability: { status: "disabled" } }) for reversible disable/re-enable flows. spinup.agents.capabilities.remove({ agentSlug, capabilityId }) deletes the binding from the agent state.
Install-backed command-line capabilities are governed by the agent runtime policy. The default declared mode allows supported user-declared package and remote-script install plans. Use curated to restrict installs to Spinup's recognized installer set such as Firecrawl CLI and the Loops installer, or none to block install-backed capabilities. Spinup-owned runtime tools such as ffmpeg should use installPlan.strategy: "none" with an executable validation plan; Spinup materializes the pinned Worker Host artifact on demand before validation.
await spinup.agents.update({
agentSlug: "support-agent",
runtimePolicy: {
allowedPackageInstallationMode: "declared",
},
});
await spinup.agents.capabilities.add({
agentSlug: "support-agent",
capability: {
installPlan: {
executable: "loops",
interpreter: "bash",
strategy: "remote_script",
url: "https://cli.loops.so",
},
kind: "cli",
name: "Loops CLI",
secretBindingIds: ["agentsecretbinding_loops"],
source: "https://loops.so",
validationPlan: {
executable: "loops",
strategy: "executable",
},
},
});For secret-backed CLIs, bind secrets by ID and project names through the relevant capability or secret-binding flow. Do not put secret values, API keys, or pasted shell installers such as curl ... | bash in capability payloads.
