Portal
Documentation: all sections

Agent runtime

The agent runtime makes agents stateful and cooperative. It gives you two things: durable state, a sealed key/value store your code reads and writes across runs, and messaging, account-scoped mailboxes your agents deliver to each other. Both are key-authed on a sk-sable_ API key, and both seal their contents at rest.

A hosted agent is a bounded run that starts and exits, so it has nowhere to keep anything between runs on its own. State is where it keeps that: a hosted agent uses its own agent id as its state namespace, so its memory is naturally scoped to itself.

Durable state

State is namespaced key/value storage. The value is any JSON, sealed at rest and opened only in-frame when you read it. namespace is optional; omit it for a default namespace, or pass one (a hosted agent uses its agent id).

# Write
curl -X PUT https://api.buildsable.com/v1/state/cursor \
-H "authorization: Bearer $SABLE_API_KEY" \
-H 'content-type: application/json' \
-d '{"value": {"page": 3, "seen": 128}, "namespace": "crawler"}'

# Read
curl "https://api.buildsable.com/v1/state/cursor?namespace=crawler" \
-H "authorization: Bearer $SABLE_API_KEY"

# List keys in a namespace (no values)
curl "https://api.buildsable.com/v1/state?namespace=crawler" \
-H "authorization: Bearer $SABLE_API_KEY"

# Delete
curl -X DELETE "https://api.buildsable.com/v1/state/cursor?namespace=crawler" \
-H "authorization: Bearer $SABLE_API_KEY"

Listing a namespace returns the keys only, never the values, so it stays cheap and never has to open a sealed envelope:

{ "keys": ["cursor", "backoff", "last_seen_id"] }

Agent-to-agent messaging

An agent can drop a message into another of your agents' mailboxes. The body is any JSON, sealed at rest. Delivery is account-scoped: the target agent must belong to the calling account. There is no cross-account delivery in v1.

# Send a message to agent AGENT_ID
curl https://api.buildsable.com/v1/agents/$AGENT_ID/messages \
-H "authorization: Bearer $SABLE_API_KEY" \
-H 'content-type: application/json' \
-d '{"body": {"task": "summarize", "url": "https://example.com"}, "from_label": "planner"}'

# Read the mailbox, marking messages read as you consume them
curl "https://api.buildsable.com/v1/agents/$AGENT_ID/messages?consume=true&unread_only=true" \
-H "authorization: Bearer $SABLE_API_KEY"
{
  "messages": [
    {
      "id": "msg_7c1a…",
      "from_label": "planner",
      "body": { "task": "summarize", "url": "https://example.com" },
      "created_at": "2026-09-03T12:00:00Z",
      "read_at": null
    }
  ]
}

Pass consume=true to mark the returned messages read, and unread_only=true to fetch only messages not yet read.

Endpoints

All key-authed (Authorization: Bearer sk-sable_…).

MethodPathWhat it does
PUT/v1/state/{key}Set a value. Body {value, namespace?}. Sealed at rest.
GET/v1/state/{key}Read one value. ?namespace= selects the namespace.
GET/v1/stateList keys in a namespace (no values). ?namespace=.
DELETE/v1/state/{key}Delete one value. ?namespace=.
POST/v1/agents/{id}/messagesDeliver a message to that agent's mailbox. Body {body, from_label?}.
GET/v1/agents/{id}/messagesRead a mailbox. ?consume=true marks read; ?unread_only=true.

Privacy and limits