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 Create 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: Create
description: 'create-sato-agent: a runnable agent repo from a goal, generated from a nightly-checked template. The goal is never stored.'
paths:
/api/create:
post:
tags:
- Create
operationId: createAgent
security:
- {}
- bearerAuth: []
- satoKey: []
summary: Generate a runnable agent repo from a goal
description: The same handler as the MCP tool onchain_agent_create_agent and the create-sato-agent CLI. The goal picks a template (pinned commit of satohubai/sato-agent-templates) and never changes a template code file; a goal no template answers is refused with `no_template` and the nearest templates. Fork by default; `mainnet` is refused unless `mainnet_risk_accepted` is true. `last_green` is the day the template last passed its nightly checks, or null. The goal is not stored or logged. Rate limited per caller; an API key is optional.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- goal
properties:
goal:
type: string
maxLength: 500
framework:
type: string
enum:
- plain-ts
- agentkit
- eliza
- ai-sdk
- claude-agent-sdk
- openai-agents
chain:
type: string
enum:
- base
- base-sepolia
- solana
network:
type: string
enum:
- fork
- testnet
- mainnet
default: fork
mainnet_risk_accepted:
type: boolean
template:
type: string
format:
type: string
enum:
- files
- zip
default: files
responses:
'200':
description: 'sato.create.response/v1 with ok: true — template, files (sorted by path), env_names, next_commands, manifest, last_green.'
content:
application/json:
schema:
type: object
required:
- schema
- ok
- template
- files
- env_names
- next_commands
- manifest
- last_green
- status_url
- cli
properties:
schema:
const: sato.create.response/v1
ok:
const: true
template:
type: object
required:
- id
- version
- digest
- framework
properties:
id:
type: string
version:
type: string
digest:
type: string
framework:
type: string
files:
type: array
description: Every generated file, sorted by path.
items:
type: object
required:
- path
- encoding
- content
properties:
path:
type: string
encoding:
type: string
enum:
- utf8
- base64
content:
type: string
zip_base64:
type: string
description: 'The same repo as a zip archive, base64. Present only with format: zip.'
env_names:
type: array
items:
type: string
description: Environment variable names the repo reads. Names only, never values.
next_commands:
type: array
items:
type: string
manifest:
type: object
description: 'The repo''s sato.create.json (sato.create/v1): template, plan, policy, lock and per-file digests.'
last_green:
type:
- string
- 'null'
format: date
description: The day the template last passed its nightly checks; null when unknown.
status_url:
type: string
format: uri
cli:
type: string
description: The equivalent create-sato-agent command.
'413':
description: The body is larger than 8 KB.
'422':
description: 'sato.create.response/v1 with ok: false — error is one of no_template, custody_blocked, network_mainnet_not_enabled, network_not_supported, invalid_request, template_unavailable.'
content:
application/json:
schema:
type: object
required:
- schema
- ok
- error
- message
properties:
schema:
const: sato.create.response/v1
ok:
const: false
error:
type: string
enum:
- no_template
- custody_blocked
- network_mainnet_not_enabled
- network_not_supported
- invalid_request
- template_unavailable
message:
type: string
rule:
type: string
nearest:
type: array
description: 'On no_template: the nearest templates, with `mismatched` naming what differs from the request.'
items:
type: object
properties:
id:
type: string
framework:
type: string
intents:
type: array
items:
type: string
chains:
type: array
items:
type: string
mismatched:
type: array
items:
type: string
last_green:
type:
- string
- 'null'
format: date
blocked:
type: array
description: 'On custody_blocked: what was blocked and why.'
items:
type: object
properties:
name:
type: string
reason:
type: string
'429':
description: Too many requests from this address, or the API key is over its daily budget.
/api/create/templates:
get:
tags:
- Create
operationId: listCreateTemplates
summary: The template catalogue at the pinned templates ref
description: 'sato.template-catalogue/v1: every template × framework at `templates_ref` with its version, digest (as the create engine seals it), pinned-lane `last_green` (or null), `upstream` (every exact pin) and `dependencies` (the runtime pins sato.lock.json covers); additive in M4: `title`, `summary`, `intents`, `chains`, `networks`, `last_result` (the pinned lane''s most recent result, or null) and `sponsored` ({by, since} or null — a label only, never an input to resolution or ordering). `upstream_breaks` lists pkg@version pairs a latest-lane nightly run failed on AND the bisect attributed to that single package; combination or inconclusive attributions are not listed. Cached up to one hour.'
responses:
'200':
description: sato.template-catalogue/v1.
content:
application/json:
schema:
type: object
required:
- schema
- templates_ref
- templates
- upstream_breaks
properties:
schema:
const: sato.template-catalogue/v1
templates_ref:
type: string
description: The pinned commit of satohubai/sato-agent-templates.
templates:
type: array
items:
type: object
required:
- id
- framework
- version
- digest
- last_green
- upstream
- dependencies
properties:
id:
type: string
framework:
type: string
version:
type: string
digest:
type: string
last_green:
type:
- string
- 'null'
format: date
upstream:
type: object
additionalProperties:
type: string
description: Every exact pin, package → version.
dependencies:
type: object
additionalProperties:
type: string
description: The runtime pins sato.lock.json covers.
title:
type: string
summary:
type: string
intents:
type: array
items:
type: string
chains:
type: array
items:
type: string
networks:
type: array
items:
type: string
last_result:
type:
- string
- 'null'
sponsored:
type:
- object
- 'null'
properties:
by:
type: string
since:
type: string
upstream_breaks:
type: array
items:
type: object
required:
- pkg
- version
- template
- framework
- since
- evidence_url
properties:
pkg:
type: string
version:
type: string
template:
type: string
framework:
type: string
since:
type: string
evidence_url:
type: string
format: uri
'503':
description: The template archive could not be read.
/api/create/drift:
post:
tags:
- Create
operationId: createDrift
summary: What changed for a generated repo since it was generated
description: 'Body: the repo''s sato.create.json as `create` and its sato.lock.json as `lock` (optional `framework` when it cannot be recovered). Returns sato.template-drift/v1 with one entry per change and a stable `key`: `template_update` (the template''s latest version is green on its pinned lane and its digest differs), `custody_change` (a stored Sato Check profile of the same pkg@version now reads a worse known value than the lock recorded; unknown is never a change; nothing is profiled live) and `upstream_break` (the repo pins a pkg@version listed in the catalogue''s upstream_breaks). Used by preflight-action `mode: template-drift` and `sato-kit doctor`. Nothing from the body is stored; rate limited per caller.'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- create
- lock
properties:
create:
type: object
description: sato.create.json (sato.create/v1).
lock:
type: object
description: sato.lock.json (sato.lock/v1).
framework:
type: string
responses:
'200':
description: sato.template-drift/v1.
content:
application/json:
schema:
type: object
required:
- schema
- template
- changes
properties:
schema:
const: sato.template-drift/v1
template:
type: object
required:
- id
- framework
- pinned_version
- pinned_digest
- latest_version
- latest_digest
- latest_last_green
properties:
id:
type: string
framework:
type: string
pinned_version:
type: string
pinned_digest:
type: string
latest_version:
type: string
latest_digest:
type: string
latest_last_green:
type:
- string
- 'null'
format: date
changes:
type: array
items:
type: object
required:
- key
- kind
- title
- body_markdown
- evidence_urls
properties:
key:
type: string
description: Stable across runs, so a caller can de-duplicate.
kind:
type: string
enum:
- template_update
- custody_change
- upstream_break
title:
type: string
body_markdown:
type: string
evidence_urls:
type: array
items:
type: string
format: uri
'400':
description: The body is not {create, lock} in their v1 shapes.
'413':
description: The body is larger than 256 KB.
'422':
description: The template is not in the catalogue, or its framework could not be recovered.
'429':
description: Too many requests from this address.
'503':
description: The template archive could not be read.
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