The API seam
The hand-authored OpenAPI 3.1 contract both repos build against, and the versioning discipline that keeps it frozen.
Everything the backend and frontend agree on lives in one file: botanary-v1.yaml, a hand-authored
OpenAPI 3.1 contract. It's written before the backend logic behind it exists, specifically so the
frontend can generate a typed client and build against mocks while the backend is still catching up -
"this hand-authored file is authoritative" until the backend can emit an equivalent spec from its own
decorators, which it doesn't yet.
The spec is called "the frozen backend-frontend seam" in its own header. Both repos build against
it directly - the frontend by codegen (see API client), the backend by
serving it as-is at /docs.
What's in it
info.versionis1.0.0.- Three servers are declared: production, staging (on Base and Arbitrum Sepolia), and a local server
pointing at
http://localhost:3000/v1for the anvil + docker-compose stack described in Local development. - A global security requirement applies an opaque bearer scheme,
sessionToken, to every operation by default; a handful of public routes (session creation itself, for example) explicitly opt out. See Authentication. - Tags group operations by surface: Session, Account, Devices, Balance, Delegations, Activity, Rules, Simulation, Money, Gas, Notifications, Recovery, Depeg, UserOps, Agent, Waitlist, Marketplace, Market, Launchpad, Markets - the same surfaces the backend's modules are organized around (see Architecture). The full interactive reference for every one of them lives at /api.
Two conventions load-bearing enough to be marked in the schema
Two behaviors are so central to how Botanary works that they're encoded directly into the contract, not just described in prose:
- Build, sign, relay. Every endpoint that moves funds or authority builds and returns an
UnsignedUserOp(plus theuserOpHashthe owner needs to sign) rather than executing anything itself. Those schemas and endpoints carry anx-client-signed: truemarker. See ERC-4337 for the shape of that operation, and User operations for how a signed one gets relayed. - Presentation-only balance data. Unified and per-token balance schemas carry an
x-presentation-only: truemarker - a signal that this data is for display, never something to build a transaction's authority from.
Errors all render through one envelope, ApiError (see Architecture
for the exact shape), and policy declines carry a DeclineReason enum meant to mirror what the
equivalent on-chain revert would say. The activity feed is cursor-paginated - see
Activity.
Versioning discipline
A backward-compatible addition to the contract is a minor or patch bump: ship the backend change, then regenerate the frontend client whenever it's convenient. A breaking change requires a major version bump and a coordinated rollout - ship the backend first, then regenerate and ship the frontend. The contract isn't just documentation; it's the thing both sides are actually contractually building against, so changes to it are versioned like an API, not edited like a wiki page.
Validating it yourself
The contract can be linted locally without any of the surrounding infrastructure:
python3 -m pip install openapi-spec-validator
python3 -c "from openapi_spec_validator import validate; from openapi_spec_validator.readers import read_from_filename; validate(read_from_filename('botanary-v1.yaml')[0]); print('VALID')"
# or:
npx @redocly/cli lint botanary-v1.yaml