Call actions
Find a marketplace action by describing what it should do, read its schemas, and call it with a stored connection, from code, a routine or an agent.
Search
GET /v1/actions/search takes words and returns references ranked for agents:
bashcurl -s -G https://beta-api.b3os.org/v1/actions/search \ -H "Authorization: Bearer $B3OS_API_KEY" \ --data-urlencode "q=create a github issue" -d limit=5
json{ "object": "list", "data": [ { "ref": "io.b3os/github/create-issue@1.2.0", "pack": "io.b3os/github", "title": "Create an issue", "description": "Open an issue in a repository. Returns the issue number and URL.", "effects": "write", "connections": ["api"], "mcp_name": "github__create-issue", "score": 0.92 } ], "next_cursor": null}
The values are illustrative. Narrow the search with pack (io.b3os/github) or effects (read, for example).
Describe
GET /v1/actions/describe?ref=io.b3os/github/create-issue@1 returns everything needed to call the action: input_schema and output_schema (JSON Schema 2020-12), the effect class, MCP annotations, the action as an MCP tool definition, and the connections it needs, each with its key and type (bearer, api_key, basic or oauth2). A major version such as @1 resolves to the newest matching release, and the response names the exact one.
Call
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{"ref": "io.b3os/github/create-issue@1", "input": {"owner": "acme", "repo": "web", "title": "Checkout button misaligned on mobile"}, "connections": {"api": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}}'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call( { ref: "io.b3os/github/create-issue@1", input: { owner: "acme", repo: "web", title: "Checkout button misaligned on mobile" }, connections: { api: "conn_01m5t6cbgdjs1ketgcqwa2sne8" }, }, { idempotencyKey: crypto.randomUUID() },);console.log(result.ref, result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call( { "ref": "io.b3os/github/create-issue@1", "input": {"owner": "acme", "repo": "web", "title": "Checkout button misaligned on mobile"}, "connections": {"api": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}, }, idempotency_key=str(uuid.uuid4()),)print(result["ref"], result["output"])
textOpen an issue in acme/web titled "Checkout button misaligned on mobile".
The agent calls actions_search, then actions_describe for the best match, then actions_call with the input. Packs you expose directly (--packs github for the local server, ?packs=github on the remote URL) appear as their own tools, such as github__create-issue. actions_call takes no credential: it uses your vault connections.
json{ "object": "action_result", "ref": "io.b3os/github/create-issue@1.2.0", "output": { "number": 1423, "url": "https://github.com/acme/web/issues/1423" }, "upstream_status": 201, "timing": { "validate_ms": 0.03, "inject_ms": 0.02, "upstream_ms": 412.6, "map_ms": 0.04, "total_ms": 412.8 }}
The values are illustrative. ref is the exact version that ran. timing separates B3OS's own work (validating the input, injecting the credential, mapping the response) from the time the upstream service took.
Connections
connections maps each of the action's connection keys to a vault connection ID. Leave a key out and B3OS uses your project's only connection for that pack and key; with several, name one. Naming a connection needs vault:run on top of actions:run. Vault explains how to store one.
The credential is added at the egress proxy, only for the hosts the pack declares for that connection. The call fails with connection_required when the action needs a connection and none is available to the caller, and with connection_mismatch when the connection's type, pack or hosts do not fit the action.
Retries and idempotency
B3OS retries pure and read actions on its own. It never retries write or irreversible actions for you: send an Idempotency-Key with them, as above, so that your own retry after a timeout returns the stored result instead of acting twice. Packs that support it pass the key on to the service.
When it fails
| Code | Status | Meaning |
|---|---|---|
action_input_invalid | 422 | The input does not match the input schema; errors[] points at the field, such as /input/title |
upstream_error | 502 | The service answered with an error. upstream_status has its status and pack_error the pack's reading of it |
action_output_invalid | 502 | The service answered, but the result does not match the output schema; report it to the pack publisher |
action_not_found, pack_not_found | 404 | No such action or pack on the node |
connection_required | 422 | The action needs a credential you have not supplied or may not use |
From routines and sandboxes
- In a routine, an action is a step:
uses: io.b3os/github/create-issue@1with the input aswith, and the connections bound withconnections. A major version is pinned when the routine version is published. See definitions. - In a sandbox, grant
actions:runandvault:run, and list the connections inapi.connections; code inside then callshttp://127.0.0.1:7700/v1/actions/callwith no key, and the credential never enters the sandbox. See agents in sandboxes.