Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Sato Hub public Satobot API
version: 1.1.0
summary: Read access to the onchain agent library, its change feed, and the Agent Passport registry.
description: 'Public reads need no key and no account; the projects and listings routes take a bearer key. A Sato API key is optional on every metered endpoint and only raises limits. What is free, what is paid (the plans are Sato Check Team and Platform & Data), every limit and the fee schedule are listed on the pricing page, and the same sheet is machine-readable at /api/pricing.json.
Pricing: https://satohub.ai/pricing
License: Catalog data CC-BY-4.0 — attribution: data by satohub.ai. Scores/liveness are informational signals, not safety or quality guarantees.
Scores and liveness are informational signals computed from public evidence. They are not safety ratings, audits, or claims about returns. `verification_status` distinguishes self-reported from independently checked; self-reported is never presented as verified.
Every shape this API returns is also published as a versioned JSON Schema (draft 2020-12) at https://satohub.ai/schemas — catalogue at https://satohub.ai/schemas/index.json. They are referenced from components.schemas below, and v1 is additive-only: a breaking change becomes v2 at a new URL. Validate with additional properties allowed.
The same data is available to agents over MCP (Streamable HTTP, JSON-RPC) at https://satohub.ai/api/mcp — documented at https://satohub.ai/mcp. That endpoint is not described here because it is not REST.
INTERPRETED ANSWERS. A route template sent literally (`{slug}`), an empty query or body, a parameter under another name (`?package=` for `?target=`) or another spelling of a chain (`8453`, `eth`, `bsc`) is answered with the closest honest thing instead of a bare 4xx, and always LABELLED: the body carries an `interpretation` object (`interpreted_as`, `requested`, `rule`, `note`; the same four keys are repeated at the top level when they cannot collide with the record''s own fields), and the response carries the header `X-Sato-Interpreted: ` (plus `Content-Location` when there is a canonical URL). An interpreted answer is never an exact match. Nothing that moves money is ever interpreted beyond a chain spelling: no amount, token, taker, recipient, deployer or slippage is defaulted, a missing chain is never assumed, a chain is never guessed from an address, and a generic network word (`mainnet`, `testnet`) is never read as a chain (the answer lists the candidates). Writes are never interpreted, and a receipt is never served for a template.'
contact:
name: Sato Hub
url: https://satohub.ai
x-guidance: 'Free: search and read the onchain-agent catalog (/api/export/index.json, /api/changes, /api/resolve) and use the MCP server at /api/mcp. Paid over x402 (USDC on Base, no account or key): GET /api/x402/history/{slug} for one listing''s daily Sato Score record, GET /api/x402/agent-economy for the weekly agent-economy series. Each paid read is priced per unit delivered (daily points or rows returned): the 402 states the exact amount, the unit, the quantity and the formula, which is also on /pricing. The Sato Score measures how open, active and verifiable a project is; it is not a safety or returns grade.'
x-status:
page: https://satohub.ai/status/sato-hub
json: https://satohub.ai/api/status.json
feed: https://satohub.ai/status/feed.xml
note: Success ratios and latencies of Sato Hub's own hourly checks. Not a service-level agreement.
license:
name: CC-BY-4.0
url: https://creativecommons.org/licenses/by/4.0/
servers:
- url: https://satohub.ai
security: []
tags:
- name: satobot
description: 'Sato Bot. A goal in plain words in, a BUILD PLAN out: the goal restated, a stack of real directory listings each carrying its Sato Score and `sato_url`, a deploy spec and a Preflight verdict per item, the first action when the goal implies one, the open questions and the next steps. Nothing in a plan is invented, `null` is unknown rather than zero, and a plan is a recommendation assembled from Sato Hub''s own records at `checked_at` — not a security review, not a quality judgment, not a statement about returns. This tag holds no keys and signs nothing: a swap first-action is quoted at a NOMINAL size, never the caller''s, and a launch first-action is a config the caller reads and signs itself.'
paths:
/api/satobot/plan:
get:
tags:
- satobot
operationId: satobotPlan
security:
- {}
- bearerAuth: []
- satoKey: []
summary: Turn a goal in plain words into a build plan
description: 'Describe the onchain agent you want; get a plan you can act on.
WHAT COMES BACK: the goal restated as it was understood (including the parsed intent and which chain was read from your words), a stack of REAL directory listings bucketed into slots — framework, wallet, payments, trading, data, MCP tooling, security — each carrying its Sato Score, liveness, the share of Sato Hub''s own daily checks it answered, whether its documented install was reproduced by us, and its `sato_url`; the published deploy spec for every item that has one; a Preflight verdict per item with one evidence line per check; the first action when the goal implies one; the questions you still have to answer; and the next steps.
WHAT IT IS: a recommendation assembled from Sato Hub''s own records at `checked_at`. Nothing in a plan is invented — a component that is not a listing cannot appear — and `null` is unknown, never zero. A Sato Score measures how open, active and verifiable a project is; it is not a security review, a quality judgment or a statement about returns. A Preflight `unknown` means Sato Hub holds no record, not that something is wrong.
CUSTODY: none. This endpoint never holds keys, signs, deploys or moves funds. A swap first-action carries a quote taken at a NOMINAL size — your size is yours to choose — and a launch first-action carries a config you read and sign yourself, with the fee disclosed before anything is signed.
POST takes the same fields as a JSON body, with `constraints` as an array.'
parameters:
- name: goal
in: query
required: true
schema:
type: string
maxLength: 600
description: What you want to build, in plain words, e.g. 'a Base trading agent that swaps USDC to ETH on a signal'.
- name: chain
in: query
required: false
schema:
type: string
maxLength: 40
description: Chain the agent runs on. When omitted it is read from the goal, and `chain_source` says which.
- name: budget_usd
in: query
required: false
schema:
type: number
minimum: 0
description: Rough monthly budget. Restated in the plan; it does not filter the stack.
- name: constraints
in: query
required: false
schema:
type: string
description: Comma-separated hard constraints to restate back, e.g. self-custody only,no API keys.
- name: format
in: query
required: false
schema:
type: string
enum:
- json
- markdown
description: '''json'' (default) or ''markdown'' — the short chat render, for a channel adapter.'
responses:
'200':
description: The build plan.
content:
application/json:
schema:
type: object
required:
- goal
- restatement
- intent
- stack
- first_action
- open_questions
- next_steps
- caveat
- checked_at
properties:
goal:
type: string
restatement:
type: string
description: The goal as it was understood, so a misread is visible before anything is built on it.
intent:
type: string
enum:
- swap
- launch
- trading
- payments
- data
- identity
- general
intent_signals:
type: array
items:
type: string
description: Which rule matched, and on what words.
chain:
type:
- string
- 'null'
chain_source:
type: string
enum:
- given
- parsed
- unknown
budget_usd:
type:
- number
- 'null'
constraints:
type: array
items:
type: string
matched_use_cases:
type: array
items:
type: string
stack:
type: array
items:
type: object
properties:
slot:
type: string
slot_label:
type: string
slug:
type: string
name:
type: string
category:
type: string
sato_url:
type: string
description: The canonical record. Cite it — it is the live one; this plan is a copy.
verify_url:
type:
- string
- 'null'
trust_score:
type:
- integer
- 'null'
trust_tier:
type:
- string
- 'null'
liveness_ok:
type:
- boolean
- 'null'
observed_success_pct:
type:
- number
- 'null'
description: Share of Sato Hub's OWN daily checks that succeeded. Never uptime.
observed_days:
type:
- integer
- 'null'
observed_window_start:
type:
- string
- 'null'
description: First check date the rate is over (additive).
install_verified:
type: boolean
description: The documented install was reproduced in an ephemeral container on the spec's date. It says nothing about runtime.
chains:
type: array
items:
type: string
why:
type: string
description: The fields this pick was ranked on.
deploy_spec:
type:
- object
- 'null'
description: runtime, install, entry, requires, deploy_status, source_url, as_of — null when the listing publishes none.
preflight:
type:
- object
- 'null'
description: '{ verdict: go|caution|no|unknown, rule, checked_at, evidence[], reason }. Null when the item was outside the preflight budget; `unknown` with a reason when the check did not complete.'
gaps:
type: array
items:
type: string
description: Where the directory has no strong match. Stated, not hidden.
first_action:
type: object
description: '{ kind: none|swap|launch, ready, missing[], note, ... }. A swap carries the route quote; a launch carries the venue route and, when name/symbol/deployer are known, a prepared config.'
open_questions:
type: array
items:
type: string
next_steps:
type: array
items:
type: string
citation_ask:
type: string
caveat:
type: string
rules:
type: array
items:
type: string
checked_at:
type: string
format: date-time
plan_url:
type: string
text/markdown:
schema:
type: string
description: The short chat render, when format=markdown.
'400':
description: Missing or malformed goal.
post:
tags:
- satobot
operationId: satobotPlanPost
security:
- {}
- bearerAuth: []
- satoKey: []
summary: Same plan, JSON body
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- goal
properties:
goal:
type: string
maxLength: 600
chain:
type: string
maxLength: 40
budget_usd:
type: number
minimum: 0
constraints:
type: array
items:
type: string
maxLength: 200
maxItems: 10
format:
type: string
enum:
- json
- markdown
responses:
'200':
description: As GET.
'400':
description: Missing or malformed input.
/api/satobot/scaffold:
get:
tags:
- satobot
operationId: satobotScaffold
security:
- {}
- bearerAuth: []
- satoKey: []
summary: The build plan, as a starter repo (zip)
description: 'Builds the plan for a goal and writes it into a small starter repository, returned as a zip.
WHAT IS IN IT: README.md (the plan rendered, every source URL, and the disclosure that Sato OS is ours) · sato.plan.json (the plan, signed at its own checked_at when a signing key is configured) · .env.example (every environment variable the stack''s own deploy specs declare, values BLANK, each under a comment naming which listing wants it) · install.sh (the documented install lines in order, each under its Preflight verdict) · agent.config.json (chain, tokens and the venue Sato Route chose, with chosen_by) · .mcp.json · docker-compose.yml, present only when every stack item documents a docker install.
NOTHING IS GENERATED. Every line is a template constant or a field of the plan, copied verbatim. A value we do not hold is left blank with a comment, never filled with a plausible default.
THE ONE SAFETY RULE: a documented install that pipes a remote script into a shell is written COMMENTED, with a warning above it — never as an executable line.
DETERMINISTIC: the same plan yields a byte-identical archive; the timestamps come from the plan''s checked_at, not the clock. Capped at 2 MB.
NON-CUSTODIAL: the archive holds no keys and no secrets, and nothing here signs, deploys or moves anything.'
parameters:
- name: goal
in: query
required: true
schema:
type: string
maxLength: 600
description: What you want to build, in plain words.
- name: chain
in: query
schema:
type: string
maxLength: 40
description: Chain the agent runs on. Read from the goal when omitted.
- name: budget_usd
in: query
schema:
type: number
minimum: 0
- name: constraints
in: query
schema:
type: string
description: Comma-separated hard constraints, restated back in the plan.
responses:
'200':
description: The starter repo. `Content-Disposition` names the file; `Sato-Scaffold-Files` lists its contents.
content:
application/zip:
schema:
type: string
format: binary
'400':
description: Missing or malformed goal.
'413':
description: The archive exceeded the 2 MB cap.
post:
tags:
- satobot
operationId: satobotScaffoldPost
security:
- {}
- bearerAuth: []
- satoKey: []
summary: Same archive, JSON body — or scaffold a plan you already hold
description: 'Identical to GET, plus one thing: post a `plan` you already have (as /api/satobot/plan returned it) and it is written into files without being rebuilt. The archive is byte-identical to the one that plan produces anywhere else.'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
goal:
type: string
maxLength: 600
chain:
type: string
maxLength: 40
budget_usd:
type: number
minimum: 0
constraints:
type: array
items:
type: string
maxLength: 200
maxItems: 10
plan:
type: object
description: A build plan as /api/satobot/plan returns it. When present, goal/chain are ignored and the plan is used verbatim.
responses:
'200':
description: As GET.
'400':
description: Missing or malformed input.
'413':
description: The archive exceeded the 2 MB cap.
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'Two different credentials ride this header, and they are told apart by their shape.
• A SATO API KEY, `sk_sato_…` — optional on every metered endpoint. It is NEVER required: each of those endpoints answers an anonymous caller at the free limits, and a key only raises the caps and attributes the calls to an account. A key may also be sent as `X-Sato-Key`. An unknown or revoked key is served as if no key were present, never refused. Limits and plans: /pricing.
• A PRIVY ACCESS TOKEN for a signed-in account — required by the claim endpoints and the key-management endpoints. A token that is not a Sato key is treated as one of these.'
satoKey:
type: apiKey
in: header
name: X-Sato-Key
description: 'The same optional Sato API key, on its own header. Equivalent to `Authorization: Bearer sk_sato_…`.'
externalDocs:
description: The published Sato Hub formats, as JSON Schema.
url: https://satohub.ai/schemas