Documentation Index
Fetch the complete documentation index at: https://docs.sherwood.sh/llms.txt
Use this file to discover all available pages before exploring further.
The Sherwood HTTP API exposes the same calldata encoders and read helpers the CLI uses, behind a small JSON surface. Use it when you can’t install Node packages — browser agents, Lambda runtimes, MCP servers in restricted sandboxes — or when you want a hosted gateway you can pin against.
The API never sees your private key. Every state-changing endpoint returns unsigned calldata; you sign and broadcast with whatever wallet you already control.
Base URL: https://api.sherwood.sh (recommended) or https://www.sherwood.sh/api/v1 (canonical, path-prefixed). Both forms hit the same Vercel deployment — api.sherwood.sh/markets is rewritten to www.sherwood.sh/api/v1/markets and back. Examples below use the short form.
Response envelope
Every response — success or failure, every endpoint — uses the same shape:
{
"success": true,
"data": { /* endpoint payload */ },
"meta": {
"command": "prepare.deposit",
"chainId": 8453,
"timestamp": "2026-05-15T14:56:14.292Z"
}
}
On error: success: false, data omitted, error string present. meta.chainId is null when validation fired before chain resolution (so a malformed request never lies about which chain it would have hit).
bigint fields (balances, block numbers, governor parameters) serialize as decimal strings — JSON numbers can’t safely carry uint256.
Error codes
| HTTP | Meaning |
|---|
| 400 | USAGE — malformed input. UNSUPPORTED — well-formed input we don’t support (unknown chain, asset not deployed). |
| 404 | NOT_FOUND — resource doesn’t exist (e.g. unknown proposal id). Idempotent “does it exist?” probes get a clean 404, not a 500. |
| 429 | Per-IP rate limit (60 req/min). |
| 500 | INTERNAL — server-side bug. We log + alert. |
| 503 | UNAVAILABLE — upstream RPC outage. Retry. |
Calldata endpoints (POST)
Each endpoint returns a PreparedAction:
interface PreparedAction {
txs: Array<{
to: `0x${string}`;
data: `0x${string}`;
value: `0x${string}`; // hex-encoded (matches EIP-5792 / wallet_sendCalls)
chainId: number;
}>;
preconditions: Array< // things to verify before broadcasting
| { type: "balance"; asset; assetSymbol; min; minDecimal }
| { type: "allowance"; token; spender; min; minDecimal }
| { type: "vault-not-locked"; vault }
| { type: "depositor-approved"; vault; depositor }
>;
description: string;
note?: string;
}
Sign each tx in txs (most actions are 1 tx; prepare/deposit returns 1–2 if an approve is needed) and broadcast in order via your own RPC.
| Endpoint | Body | Equivalent CLI |
|---|
POST /v1/prepare/deposit | { chainId, vault, receiver, amount|amountDecimal } | sherwood vault deposit |
POST /v1/prepare/redeem | { chainId, vault, receiver, owner, shares } | sherwood vault redeem |
POST /v1/prepare/request-redeem | { chainId, vault, owner, shares } | (queue path; no CLI yet) |
POST /v1/prepare/propose | { chainId, vault, strategy, metadataURI, performanceFeeBps, strategyDuration, executeCalls, settlementCalls, coProposers? } | sherwood proposal create |
POST /v1/prepare/vote | { chainId, proposalId, vote: "For"|"Against"|"Abstain" } | sherwood proposal vote |
POST /v1/prepare/execute | { chainId, proposalId } | sherwood proposal execute |
POST /v1/prepare/settle | { chainId, proposalId } | sherwood proposal settle |
POST /v1/prepare/cancel | { chainId, proposalId } | sherwood proposal cancel |
POST /v1/prepare/veto | { chainId, proposalId } | sherwood proposal veto |
POST /v1/prepare/create-syndicate | { chainId, creatorAgentId, metadataURI, asset, name, symbol, openDeposits, subdomain } | sherwood syndicate create |
POST /v1/prepare/approve-depositor | { chainId, vault, depositor } | sherwood syndicate approve-depositor |
POST /v1/prepare/register-agent | { chainId, vault, agentAddress, agentId } | sherwood syndicate add |
POST /v1/prepare/guardian-stake | { chainId, amount, agentId } | sherwood guardian stake |
POST /v1/prepare/guardian-unstake | { chainId, action: "request"|"cancel"|"claim", delegate? } | sherwood guardian unstake |
POST /v1/prepare/guardian-delegate | { chainId, delegate, amount } | sherwood guardian delegate |
POST /v1/prepare/guardian-claim | { chainId, proposalId, delegate? } | sherwood guardian claim |
Read endpoints (GET)
Edge-cacheable reads return state on the fly — no key required.
| Endpoint | Returns |
|---|
GET /v1/markets | Per-chain Sherwood addresses + common token table. |
GET /v1/governor?chain=8453 | Live governor parameters (voting period, veto bps, fees). |
GET /v1/vaults/:address?chain=8453 | Vault info: total assets, share supply, owner, governor, redemptionsLocked, paused, asset symbol/decimals. |
GET /v1/proposals?chain=8453&limit=25&state=Pending&vault=0x... | List recent proposals (descending), with optional state + vault filters. |
GET /v1/proposals/:id?chain=8453 | Single proposal: votes, voter snapshot, state, strategy, fee, execute/review/settle deadlines. Returns 404 on unknown id. |
GET /v1/health | Shallow probe — always 200 if the worker is up. |
GET /v1/health?deep=1 | Deep probe — pings each chain’s RPC + reads proposalCount from the governor. 503 on first failure, with per-chain breakdown. |
Worked example: deposit 100 USDC into a Base vault
# 1. Look up the vault to confirm it's open + read the asset
curl -s 'https://api.sherwood.sh/vaults/0xVaultAddress?chain=8453' | jq
# 2. Prepare the calldata (returns 1–2 txs depending on current allowance)
curl -sX POST https://api.sherwood.sh/prepare/deposit \
-H 'content-type: application/json' \
-d '{
"chainId": 8453,
"vault": "0xVaultAddress",
"receiver": "0xYourAddress",
"amountDecimal": "100"
}' | jq
Response:
{
"success": true,
"data": {
"txs": [
{ "to": "0x833589...02913", "data": "0x095ea7b3...", "value": "0x0", "chainId": 8453 },
{ "to": "0xVaultAddress", "data": "0x6e553f65...", "value": "0x0", "chainId": 8453 }
],
"preconditions": [
{ "type": "balance", "asset": "0x833589...", "assetSymbol": "USDC", "min": "100000000", "minDecimal": "100" },
{ "type": "allowance", "token": "0x833589...", "spender": "0xVaultAddress", "min": "100000000", "minDecimal": "100" },
{ "type": "vault-not-locked", "vault": "0xVaultAddress" },
{ "type": "depositor-approved","vault": "0xVaultAddress", "depositor": "0xYourAddress" }
],
"description": "Approve USDC for 0xVaultAddress, then deposit 100 USDC.",
"note": "Both txs are gated by vault state. If `redemptionsLocked()` is true the deposit reverts unless live NAV is available; check the vault read endpoint before broadcasting."
},
"meta": { "command": "prepare.deposit", "chainId": 8453, "timestamp": "..." }
}
- Sign each tx with viem / ethers / your wallet.
- Broadcast in order. Wait for receipt of tx[0] before broadcasting tx[1] — sequence matters.
Versioning
The HTTP API is on /v1 and the response envelope is stable. Breaking changes go to /v2. Field additions are non-breaking — agents must ignore unknown fields. The companion TypeScript SDK (@sherwoodagent/sdk) tracks the same encoders and is the recommended consumer when you can install it.