B3OS workflows are durable, auditable automations that move real value on-chain, call dozens of integrations, and wait for human approval when needed. Any of them can be exposed to an AI agent as a tool call: your agent hands B3OS a payload, B3OS runs the workflow, and your agent tracks the run to completion and reads the result.

This guide is the end-to-end path for an agent builder: mint a least-privilege key, run a published workflow, follow it to a terminal status, and list run history — all over the REST API, from any agent framework.

To create workflows from code (define → validate → publish), see the API Quickstart. This page is about invoking and tracking workflows your org already owns, which is what an agent does at runtime.

The loop

1

Mint a scoped key

Create a service account with only the permissions an agent needs, then mint an API key for it.

2

Run a published workflow

POST /v1/workflows/:id/run with a payload. Returns a runId immediately — execution is asynchronous.

3

Track it to a terminal status

Poll GET /v1/runs/:id, or stream GET /v1/runs/:id/stream (SSE), until the run reaches success, partial, failure, or cancelled.

4

Read the result and history

Read per-node outputs from executionState, and list prior runs with GET /v1/workflows/:id/runs.

1. Mint a least-privilege key

API keys use the b3sk_ prefix and are sent as Authorization: Bearer b3sk_.... A key is permanently bound to its organization — it can never read or run another org's data.

For an agent, prefer a service account over a coarse read-write user key. A service account carries an explicit permission list, so you can grant exactly "run workflows + read runs" and nothing else. (A read-write user key also holds apikey:create/apikey:revoke, so it can mint more keys — avoid handing that to an agent.)

1

Create the service account

bash
curl -sS -X POST "$B3OS_API_URL/v1/service-accounts" \ -H "Authorization: Bearer $B3OS_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "trading-agent", "description": "Runs market + swap workflows for the trading agent", "permissions": ["workflow:read", "workflow:execute", "run:read"] }'

You can only grant permissions you hold yourself. workflow:read + workflow:execute + run:read is the complete set for the agent loop — discover, run, poll, stream, cancel, and read history. No extra permissions are needed: SSE streaming is gated on run:read, and cancelling a run is gated on workflow:execute, both already in the set.

2

Mint a key for it

bash
curl -sS -X POST "$B3OS_API_URL/v1/api-keys" \ -H "Authorization: Bearer $B3OS_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "trading-agent key", "serviceAccountId": "sa_123" }'

The plaintext key (key in the response) is shown once — store it in a secret manager. Hand this key to the agent; keep B3OS_ADMIN_KEY (the owner/developer key that created the account) on your provisioning path only.

Today a service account and its key are created by an existing org owner or developer (in the B3OS app or via the API above). There is no anonymous "sign up and get a key" flow — an agent always acts inside a B3OS organization that someone provisioned. Plan your integration as "my org runs my workflows on behalf of my users."

2. Run a published workflow

The workflow must be published (status active). Pass run-time inputs in payload; everything is optional.

bash
curl -sS -X POST "$B3OS_API_URL/v1/workflows/$WORKFLOW_ID/run" \ -H "Authorization: Bearer $B3OS_AGENT_KEY" \ -H "Content-Type: application/json" \ -d '{ "payload": { "asset": "USDC", "amount": "100" } }'
json
{ "data": { "runId": "run_c9i6j8k2l0m3" }, "code": 200, "message": "success" }

The call returns as soon as the run is queued — it does not wait for completion. Useful options in the body:

FieldTypePurpose
payloadobjectRun-time inputs, read inside the workflow via {{$trigger.body.*}}
runIdstringPre-choose the run id (must start run_) so you can open the SSE stream before running
simulatebooleanDry-run — executes logic without sending on-chain transactions
versionintegerRun a specific published version instead of the default
triggerNodeIdstringFor multi-trigger workflows, which trigger to attribute the run to

A manual workflow also exposes an unauthenticated webhook: POST /v1/workflows/:id/webhook?secret=..., where the secret comes from GET /v1/workflows/:id/webhook-secret. It fires a run and returns only { action, runId } — handy for "trigger and forget", but it exposes no run internals, so use the authenticated path above when your agent needs the result.

3. Track the run to a terminal status

A run's status is one of running, waiting, success, partial, failure, or cancelled. The last four are terminal. (waiting means a node is paused — e.g. a human-approval or wait-for-event gate.)

Poll

bash
curl -sS "$B3OS_API_URL/v1/runs/$RUN_ID?summary=true" \ -H "Authorization: Bearer $B3OS_AGENT_KEY"

?summary=true drops the heavy executionState and workflowDefinition so a status poll stays light; omit it (or pass ?nodeIds=a,b) when you want per-node results. Poll until status is terminal, then read the result (below).

Stream (SSE)

For push updates instead of polling, open the Server-Sent Events stream. It needs run:read (a read-scope key can stream). The stream closes itself when the run completes.

bash
curl -N "$B3OS_API_URL/v1/runs/$RUN_ID/stream" \ -H "Authorization: Bearer $B3OS_AGENT_KEY"

To guarantee you see run_started, choose the runId yourself, open the stream first, then run with that same runId in the body. The stream lets you subscribe to a run id before it exists.

Read the result

GET /v1/runs/:id returns the full run, including executionState — a map of nodeId → { status, input, result, startedAt, finishedAt }. Read the result of the node whose output your agent needs; that's the tool's return value. Secrets are masked in the response.

4. Read run history

WantEndpoint
Runs for one workflowGET /v1/workflows/:id/runs
All runs in the orgGET /v1/runs
Counts grouped by statusGET /v1/runs/status-counts

All list endpoints take limit (default 20, max 100), offset, and an optional status filter, and return { data: { items, limit, offset, hasMore } }. There is no total — page with offset until hasMore is false.

Permissions at a glance

Grant a service account exactly the rows the agent uses. (For a legacy user key, read scope covers the read/stream rows but not workflow:execute; read-write covers everything.)

OperationEndpointPermissionread keyread-write key
Run a workflowPOST /v1/workflows/:id/runworkflow:execute
Get a run / its resultGET /v1/runs/:idrun:read
List run historyGET /v1/runs, .../runsrun:read
Stream a run (SSE)GET /v1/runs/:id/streamrun:read
Cancel a runPOST /v1/runs/:id/cancelworkflow:execute
Discover workflowsGET /v1/workflowsworkflow:read

Wire it into your agent

Expose each workflow as one tool. The tool's input schema mirrors the workflow's manual-trigger inputSchema; the implementation is the run-then-track loop above.

json
{ "name": "run_treasury_rebalance", "description": "Rebalance the org treasury to target allocation. Returns the per-swap results.", "input_schema": { "type": "object", "properties": { "maxSlippageBps": { "type": "integer", "description": "Max slippage in basis points" } } }}
text
on tool call(args): runId = POST /v1/workflows/{id}/run { payload: args } # → run_... loop: run = GET /v1/runs/{runId}?summary=true if run.status in {success, partial, failure, cancelled}: break sleep(1s) # or use the SSE stream full = GET /v1/runs/{runId} # read executionState[node].result return summarize(full)

If your agent speaks MCP, the B3OS MCP server wraps these same endpoints as tools so Claude can discover, run, and inspect workflows without hand-writing HTTP. The REST path on this page is the framework-agnostic equivalent and the source of truth for scopes.

What's supported today

Your org's published workflows — fully supported

Run, track, and read history for any active workflow in your org with a service-account key. This is the primary path.

Owner-published public workflows — anonymous run

A workflow whose owner set visibility to public_execute can be triggered with no auth via POST /v1/public/workflows/:id/run. The run is billed to the owner's org and uses the owner's connectors and wallets; the caller only supplies a payload. The consumer cannot opt a workflow into this — only the owner can.

Public templates — adopt, then run

Library templates are definitions, not runnable endpoints. To use one, read it (GET /v1/templates/:id), create a workflow in your org from its definition, publish it, then run your copy. Your org supplies the connectors and CU — credentials are never carried over from the template.

Authentication

API keys, scopes, service accounts, and organization context.

Learn More
Runs and Executions

Exact request/response schemas for every run and execution endpoint.

Learn More
Execution Hooks

Push signed run events to your backend instead of polling.

Learn More