Skip to content

API Reference

Base URL: https://<your-paws-host>/v1

All endpoints require Authorization: Bearer <API_KEY> unless noted. The OpenAPI spec is available at /openapi.json.

POST /v1/sessions

Submit a workload for execution in an isolated VM.

{
"snapshot": "claude-code",
"workload": {
"type": "script",
"script": "#!/bin/bash\necho hello",
"env": { "MY_VAR": "value" }
},
"resources": { "vcpus": 2, "memoryMB": 4096 },
"timeoutMs": 600000,
"network": {
"allowOut": ["api.anthropic.com", "github.com"],
"credentials": {
"api.anthropic.com": {
"headers": { "x-api-key": "sk-ant-..." }
}
},
"expose": [{ "port": 3000, "label": "Dev server", "access": "sso" }]
},
"callbackUrl": "https://myapp.com/webhooks/paws",
"metadata": { "issueId": "123" }
}
FieldTypeRequiredDefaultDescription
snapshotstringYesSnapshot ID to boot from
workloadobjectYesScript to execute (type, script, env)
resources.vcpusnumberNo2vCPUs (1-8)
resources.memoryMBnumberNo4096Memory in MB (256-16384)
timeoutMsnumberNo600000Max execution time in ms
network.allowOutstring[]No[]Allowed outbound domains (supports *.example.com)
network.credentialsobjectNo{}Per-domain credential headers
network.exposearrayNo[]Ports to expose via port exposure
callbackUrlstringNoURL to POST result on completion
metadataobjectNoOpaque metadata, returned in result

Response: 202

{ "sessionId": "a1b2c3d4-...", "status": "pending" }
GET /v1/sessions/:id

Response: 200

{
"sessionId": "a1b2c3d4-...",
"status": "completed",
"exitCode": 0,
"stdout": "hello\n",
"stderr": "",
"output": { "key": "value" },
"startedAt": "2026-03-29T10:00:00Z",
"completedAt": "2026-03-29T10:00:05Z",
"durationMs": 5000,
"worker": "worker-node-1",
"metadata": { "issueId": "123" },
"resources": { "vcpus": 2, "memoryMB": 4096 },
"vcpuSeconds": 10,
"exposedPorts": [
{ "port": 3000, "url": "https://sess-abc-3000.fleet.example.com", "access": "sso" }
]
}
StatusMeaning
pendingQueued, waiting for a VM slot
runningVM active, workload executing
completedFinished successfully
failedWorkload error (non-zero exit)
timeoutExceeded timeoutMs
cancelledCancelled via DELETE
DELETE /v1/sessions/:id

Response: 200

{ "sessionId": "a1b2c3d4-...", "status": "cancelled" }

POST /v1/daemons

Register a daemon role. Activates immediately and begins watching for triggers. Provide either workload or agent (not both).

{
"role": "pr-helper",
"description": "Review PRs and fix CI failures",
"snapshot": "claude-code",
"trigger": { "type": "webhook", "events": ["pull_request.opened"] },
"agent": {
"framework": "claude-code",
"prompt": "Review the PR in $TRIGGER_PAYLOAD",
"maxTurns": 20,
"allowedTools": ["Read", "Bash"]
},
"network": { "allowOut": ["api.anthropic.com", "github.com"] },
"governance": {
"maxActionsPerHour": 20,
"requiresApproval": ["merge"],
"auditLog": true
}
}

Trigger types:

TypeFieldsDescription
webhookevents, secretFires when matching webhook received
schedulecronFires on cron schedule
watchcondition, intervalMsFires when polled condition is met
githubrepos, events, commandFires on GitHub App events

Response: 201

{ "role": "pr-helper", "status": "active", "createdAt": "2026-03-29T10:00:00Z" }
GET /v1/daemons
GET /v1/daemons/:role
PATCH /v1/daemons/:role

Partial update. Send only the fields you want to change.

DELETE /v1/daemons/:role

Stops the daemon. Running sessions complete, but no new triggers are accepted.


POST /v1/webhooks/:role

No auth required (validated via webhook secret configured in daemon). Triggers a session for the daemon with TRIGGER_PAYLOAD set to the request body.

Response: 202

{ "accepted": true, "sessionId": "a1b2c3d4-..." }

POST /v1/snapshot-configs
{
"id": "my-snapshot",
"template": "node",
"setup": "npm install -g typescript",
"requiredDomains": ["registry.npmjs.org"],
"resources": { "vcpus": 2, "memoryMB": 4096 }
}

Response: 201 — returns the created config.

GET /v1/snapshot-configs
GET /v1/snapshot-configs/:id
PUT /v1/snapshot-configs/:id
DELETE /v1/snapshot-configs/:id

POST /v1/snapshots/:id/build

Triggers a snapshot build from the config with the given ID.

Response: 202

{ "snapshotId": "my-snapshot", "status": "building", "jobId": "build-a1b2c3d4" }
GET /v1/snapshots

GET /v1/fleet
{
"totalWorkers": 3,
"healthyWorkers": 3,
"totalCapacity": 15,
"usedCapacity": 7,
"queuedSessions": 2,
"activeDaemons": 4
}
GET /v1/fleet/workers

Returns all workers with health status, capacity, and snapshot info.


All errors follow a consistent format:

{
"error": {
"code": "SESSION_NOT_FOUND",
"message": "Session a1b2c3d4-... not found"
}
}
CodeHTTPMeaning
UNAUTHORIZED401Invalid or missing API key
FORBIDDEN403API key lacks permission
SESSION_NOT_FOUND404Session ID not found
DAEMON_NOT_FOUND404Daemon role not found
DAEMON_ALREADY_EXISTS409Daemon role already registered
SNAPSHOT_NOT_FOUND404Snapshot ID not found
CAPACITY_EXHAUSTED503All workers are full
RATE_LIMITED429Governance rate limit exceeded
VALIDATION_ERROR400Invalid request body