Skip to main content
Twin exposes a REST API that lets you create agents, trigger runs, inspect events, manage API keys, and register webhooks for run lifecycle notifications.

Base URL

https://api.twin.so

Authentication

Use one of these headers on every request:
x-api-key: YOUR_API_KEY
Authorization: Bearer YOUR_JWT
Generate an API key from your Twin account or via the API itself (see below).

Error Handling

Error responses use this shape:
{
  "error": {
    "code": "INVALID_ARGUMENT",
    "message": "Description of what went wrong"
  }
}
code maps to gRPC status names (for example: NOT_FOUND, UNAUTHENTICATED, FAILED_PRECONDITION).

API Keys

API key management endpoints currently use the /api/public/v1 path family.

List API keys

Returns all API keys for the authenticated user.Example
curl https://api.twin.so/api/public/v1/access-api-keys \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "keys": [
    {
      "keyId": "abc123",
      "name": "my-integration",
      "displayPrefix": "tw_live_abc...",
      "createdAt": 1706000000,
      "lastUsedAt": 1706100000
    }
  ]
}

Create an API key

Creates a new API key. The full key is only returned once, so store it securely.Request body
FieldTypeRequiredDescription
namestringNoOptional name for the key
Example
curl -X POST https://api.twin.so/api/public/v1/access-api-keys \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-integration"}'
Response
{
  "keyId": "abc123",
  "name": "my-integration",
  "apiKey": "tw_live_...",
  "displayPrefix": "tw_live_abc..."
}
The apiKey field is only returned at creation time. Store it immediately.

Revoke an API key

Permanently revokes an API key. Requests using it stop working immediately.Path parameters
FieldTypeRequiredDescription
keyIdstringYesID of the key to revoke
Example
curl -X DELETE https://api.twin.so/api/public/v1/access-api-keys/abc123 \
  -H "x-api-key: YOUR_API_KEY"

Identity

Get current user

Returns the authenticated user ID.Example
curl https://api.twin.so/v1/me \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "userId": "user_123"
}

Agents

Versioned agent endpoints live under /v1/agents.

List agents

Returns agents for the authenticated user, with optional pagination and project filtering.Query parameters
FieldTypeRequiredDescription
project_idstringNoFilter to a specific project
cursorstringNoCursor for pagination
limitintegerNoMax results to return
Example
curl "https://api.twin.so/v1/agents?limit=20" \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "agents": [
    {
      "agentId": "agent_abc123",
      "latestRunId": "run_xyz789",
      "latestRunIsFinished": true,
      "hasRuns": true,
      "deploymentState": "deployed"
    }
  ]
}

Create an agent

Creates a new agent and returns its ID.Request body
FieldTypeRequiredDescription
project_idstringNoProject to assign the agent to
owner_user_idstringNoOptional owner override
is_subagentbooleanNoWhether the new agent is a subagent
derived_from_agent_idstringNoSource agent ID for derived agents
agent_idstringNoExplicit agent ID override
Example
curl -X POST https://api.twin.so/v1/agents \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "proj_001"}'
Response
{
  "agentId": "agent_abc123"
}

Get an agent

Returns full details for a specific agent.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
Example
curl https://api.twin.so/v1/agents/agent_abc123 \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "agent": {
    "agentId": "agent_abc123",
    "latestRunId": "run_xyz789",
    "lastActivityAt": "2026-02-20T14:30:00Z",
    "latestRunIsFinished": true,
    "hasRuns": true,
    "projectId": "proj_001",
    "deploymentState": "deployed",
    "deployedAt": "2026-02-18T10:00:00Z"
  }
}

Delete an agent

Permanently deletes an agent and its run data.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
Example
curl -X DELETE https://api.twin.so/v1/agents/agent_abc123 \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "deleted": true
}

Runs

Trigger, list, and delete runs under each agent.

List runs

Returns run history for an agent.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
Query parameters
FieldTypeRequiredDescription
pageintegerNoPage number (default 1)
page_sizeintegerNoResults per page (default 100)
filter_statusstringNoRun status filter
filter_run_idstringNoFilter by exact run ID
filter_started_afterstringNoISO-8601 lower bound
filter_started_beforestringNoISO-8601 upper bound
filter_policy_typestringNoFilter by exact policy type (e.g. runner_v2, builder_v3)
filter_policy_groupstringNoFilter by policy group: builder or runner. Mutually exclusive with filter_policy_type.
Example
curl "https://api.twin.so/v1/agents/agent_abc123/runs?page=1&page_size=10&filter_status=finished" \
  -H "x-api-key: YOUR_API_KEY"
Response fields
FieldTypeDescription
runsarrayPaginated list of run objects for the requested page
total_runsstringTotal number of matching runs (respects all filters)
pageintegerCurrent page number
page_sizeintegerNumber of results per page
all_run_summariesarrayLightweight summaries for up to 2 000 matching runs (for UI use)
Run object
FieldTypeDescription
run_idstringUnique run identifier
agent_idstringParent agent identifier
user_idstringUser who owns the agent
user_emailstringEmail of the owning user
started_atstringISO-8601 run start time
last_event_atstringISO-8601 timestamp of last event
event_countstringNumber of events in the run
event_bytesstringTotal event payload size in bytes
run_numberinteger1-based position within the result set
is_finishedbooleanWhether the run has completed
is_pausedbooleanWhether the run is paused
statusstringCurrent run status
goalstringAgent goal at time of run
summarystringRun summary (if available)
outcomestringRun outcome (if available)
policy_typestringPolicy type used for the run
policy_modelstringModel used by the policy
webhook_subscription_idstringWebhook subscription that triggered run
schedule_agent_idstringSchedule that triggered run
Run summary object (all_run_summaries)
FieldTypeDescription
run_idstringUnique run identifier
run_numberinteger1-based position within the result set
started_atstringISO-8601 run start time
is_finishedbooleanWhether the run has completed
is_pausedbooleanWhether the run is paused
summarystringRun summary (if available)
outcomestringRun outcome (if available)
policy_typestringPolicy type used for the run
policy_modelstringModel used by the policy
credits_consumedintegerCredits consumed by the run
webhook_subscription_idstringWebhook subscription that triggered run
schedule_agent_idstringSchedule that triggered run
tool_iconsarrayTool icons used during the run
total_action_countintegerNumber of tool actions in the run
Example
{
  "runs": [
    {
      "run_id": "run_xyz789",
      "agent_id": "agent_abc123",
      "status": "completed",
      "started_at": "2026-02-20T14:30:00Z",
      "last_event_at": "2026-02-20T14:32:15Z",
      "event_count": "128",
      "is_finished": true,
      "policy_type": "runner_v2",
      "run_number": 1
    }
  ],
  "total_runs": "42",
  "page": 1,
  "page_size": 10,
  "all_run_summaries": [
    {
      "run_id": "run_xyz789",
      "run_number": 1,
      "started_at": "2026-02-20T14:30:00Z",
      "is_finished": true,
      "policy_type": "runner_v2"
    }
  ]
}
all_run_summaries returns at most 2 000 entries. For agents with more runs, rely on total_runs and paginate through runs using page / page_size.

Start a run

Starts a run for an existing agent.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
Request body
FieldTypeRequiredDescription
run_modestringNo"build" or "run"
user_messagestringNoOptional user message for the run
skip_deploy_checkbooleanNoSkip deployment checks before starting
Example
curl -X POST https://api.twin.so/v1/agents/agent_abc123/runs \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"run_mode": "run", "user_message": "Please execute the latest workflow."}'
Response
{
  "agentId": "agent_abc123",
  "runId": "run_xyz789"
}

Delete a run

Deletes a run for a specific agent.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
run_idstringYesThe run ID
Example
curl -X DELETE https://api.twin.so/v1/agents/agent_abc123/runs/run_xyz789 \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "deleted": true
}

Events

List run events

Returns events for a specific run.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
run_idstringYesThe run ID
Query parameters
FieldTypeRequiredDescription
limitintegerNoMax events to return
after_indexintegerNoReturn events after this event index
Example
curl "https://api.twin.so/v1/agents/agent_abc123/runs/run_xyz789/events?limit=50" \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "events": [
    {
      "index": 1,
      "event": {
        "started": {}
      }
    }
  ]
}

Webhooks

Register webhook URLs to receive push notifications when runs change state. Instead of polling for run completion, your backend gets an HTTP POST for each lifecycle event.

Event types

EventFired when
run.startedA run begins executing
run.completedA run finishes (success, partial, or fail outcome)
run.failedA run hits a policy error
run.stoppedA run is stopped by the user
run.pausedA run is paused by the user, or paused by the agent for 15+ minutes

Create a webhook

Registers a webhook URL for the given agent. The signing secret is returned only once in the response — store it immediately.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
Request body
FieldTypeRequiredDescription
urlstringYesHTTPS (or HTTP) endpoint to receive events
eventsstring[]YesEvent types to subscribe to (at least one required)
Example
curl -X POST https://api.twin.so/v1/agents/agent_abc123/webhooks \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/twin",
    "events": ["run.completed", "run.failed"]
  }'
Response 201 Created
{
  "webhook_id": "01234567-89ab-cdef-0123-456789abcdef",
  "url": "https://example.com/webhooks/twin",
  "events": ["run.completed", "run.failed"],
  "signing_secret": "whsec_a1b2c3d4e5f6...",
  "status": "active",
  "created_at": "2026-03-11T12:00:00Z"
}
The signing_secret is only returned at creation time. Store it securely — you need it to verify incoming webhook signatures.

List webhooks

Returns all webhooks registered for the given agent.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
Example
curl https://api.twin.so/v1/agents/agent_abc123/webhooks \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "webhooks": [
    {
      "webhook_id": "01234567-89ab-cdef-0123-456789abcdef",
      "agent_id": "agent_abc123",
      "user_id": "user_123",
      "url": "https://example.com/webhooks/twin",
      "events": ["run.completed", "run.failed"],
      "status": "active",
      "created_at": "2026-03-11T12:00:00Z",
      "updated_at": "2026-03-11T12:00:00Z"
    }
  ]
}

Get a webhook

Returns details for a specific webhook.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
webhook_idstringYesThe webhook ID
Example
curl https://api.twin.so/v1/agents/agent_abc123/webhooks/01234567-89ab-cdef-0123-456789abcdef \
  -H "x-api-key: YOUR_API_KEY"
Response
{
  "webhook_id": "01234567-89ab-cdef-0123-456789abcdef",
  "agent_id": "agent_abc123",
  "user_id": "user_123",
  "url": "https://example.com/webhooks/twin",
  "events": ["run.completed", "run.failed"],
  "status": "active",
  "created_at": "2026-03-11T12:00:00Z",
  "updated_at": "2026-03-11T12:00:00Z"
}

Update a webhook

Updates a webhook’s URL, subscribed events, or status. All fields are optional — only provided fields are changed.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
webhook_idstringYesThe webhook ID
Request body
FieldTypeRequiredDescription
urlstringNoNew endpoint URL
eventsstring[]NoNew set of event types
statusstringNo"active" or "disabled"
Example
curl -X PATCH https://api.twin.so/v1/agents/agent_abc123/webhooks/01234567-89ab-cdef-0123-456789abcdef \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "disabled"}'
Response
{
  "webhook_id": "01234567-89ab-cdef-0123-456789abcdef",
  "agent_id": "agent_abc123",
  "user_id": "user_123",
  "url": "https://example.com/webhooks/twin",
  "events": ["run.completed", "run.failed"],
  "status": "disabled",
  "created_at": "2026-03-11T12:00:00Z",
  "updated_at": "2026-03-11T13:00:00Z"
}

Delete a webhook

Permanently deletes a webhook. No further events will be delivered.Path parameters
FieldTypeRequiredDescription
agent_idstringYesThe agent ID
webhook_idstringYesThe webhook ID
Example
curl -X DELETE https://api.twin.so/v1/agents/agent_abc123/webhooks/01234567-89ab-cdef-0123-456789abcdef \
  -H "x-api-key: YOUR_API_KEY"
Response 204 No Content

Webhook payload

When a subscribed event fires, Twin sends an HTTP POST to your webhook URL with a JSON body:
{
  "event": "run.completed",
  "timestamp": "2026-03-11T14:32:15Z",
  "data": {
    "run_id": "run_xyz789",
    "agent_id": "agent_abc123",
    "status": "completed",
    "outcome": "success",
    "finished_at": "2026-03-11T14:32:15Z"
  }
}
FieldDescription
eventThe event type (e.g. run.completed)
timestampISO-8601 timestamp of when the event was dispatched
data.run_idThe run that triggered the event
data.agent_idThe agent the run belongs to
data.statusRun status: in_progress, completed, error, stopped, or paused
data.outcomePresent on run.completed: success, partial, or fail
data.finished_atPresent on terminal events (run.completed, run.failed, run.stopped)

Verifying webhook signatures

Every webhook delivery includes two headers:
HeaderValue
X-Cobb-Signaturesha256=<hex HMAC-SHA256>
X-Cobb-EventThe event type (e.g. run.completed)
To verify authenticity, compute HMAC-SHA256(signing_secret, raw_request_body) and compare it to the signature in the header. Example (Node.js)
const crypto = require("crypto");

function verifyWebhookSignature(secret, body, signatureHeader) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

Quick Reference

ActionMethodEndpoint
List API keysGET/api/public/v1/access-api-keys
Create API keyPOST/api/public/v1/access-api-keys
Revoke API keyDELETE/api/public/v1/access-api-keys/{keyId}
Get current userGET/v1/me
List agentsGET/v1/agents
Create agentPOST/v1/agents
Get agentGET/v1/agents/{agent_id}
Delete agentDELETE/v1/agents/{agent_id}
List runsGET/v1/agents/{agent_id}/runs
Start runPOST/v1/agents/{agent_id}/runs
Delete runDELETE/v1/agents/{agent_id}/runs/{run_id}
List run eventsGET/v1/agents/{agent_id}/runs/{run_id}/events
Create webhookPOST/v1/agents/{agent_id}/webhooks
List webhooksGET/v1/agents/{agent_id}/webhooks
Get webhookGET/v1/agents/{agent_id}/webhooks/{webhook_id}
Update webhookPATCH/v1/agents/{agent_id}/webhooks/{webhook_id}
Delete webhookDELETE/v1/agents/{agent_id}/webhooks/{webhook_id}
Agent, run, and event APIs are now versioned REST endpoints under /v1 with standard HTTP methods.

Get your API key

Sign in to Twin to generate your API key and start building.