DOCS /TEAMS & ORGANIZATIONS
Teams & organizations
An organization is a shared expense account: one roof for your team's agent keys, approvals, budgets, and ledger. Members come and go by wallet address, every receipt is attributed to the agent that paid, and a single org-level cap sits above each agent's own budget.
Members, roles, and the invite that isn't an email
Create an org from the dashboard's scope switcher and you become its owner. Adding a teammate is just adding their wallet address — that isthe invite. There's no email, no pending state, no signup link: membership takes effect the next time that wallet signs in with SIWE.
Three roles, checked server-side on every call:
- member — sees everything: members, agents, approvals, the ledger, the report.
- admin — manages the spending surface: mints and revokes org keys, toggles approvals, sets budgets, renames the org, invites members.
- owner — exactly one per org: changes roles, transfers ownership (atomic — the old owner steps down to admin in the same transaction), deletes the org.
One rule has no exceptions: org management is SIWE-only. A yf_… Bearer key can never add members, change roles, or edit the org policy it spends under — the same trust split as an agent not being able to raise its own budget.
Org keys — the org's agents, not anyone's
Keys minted in org scope (admin+) belong to the organization: any admin can manage them, every receipt they sync is attributed to the org's ledger, and they draw on the org'sgrant and approvals — not their minter's personal ones. An org key can't even sync a receipt into its minter's personal account; attribution can't lie.
The two-level budget
Each agent key keeps its own per-day budget, and the org adds a level above it: a daily USD cap across all of the org's keys, set in Org settings (admin+). The SDK's pre-flight returns both levels — over either means stop paying:
GET /api/agent/policy
Authorization: Bearer yf_… // an ORG key
{
"org": {
"id": "cmq…",
"name": "Acme Robotics",
"perDayUsd": 25, // the org cap; null = per-key budgets alone govern
"spentTodayUsd": 7.43, // summed across ALL the org's keys
"remainingTodayUsd": 17.57,
"overBudget": false
},
"agent": { … }, // this key's own budget, as on /docs/agents
"grant": { … } // the ORG's grant — its allowlist + caps
}Receipt syncs echo the same org block, so a busy agent learns it crossed the org cap on the very next settlement it reports.
The honesty clause from Agents & budgets applies doubly here: org caps are enforced by the SDK, which reads this policy and refuses locally. They're advisory at the rails — the agent pays from its own wallet, so Yeetful can't block it on-chain. Hard enforcement arrives with Coinbase Spend Permissions, where the on-chain allowance is the cap.
The expense report
GET /api/orgs/[id]/report?from&to (any member) returns totals plus three breakdowns — by agent, by member, and by service— and the Organization page renders it with a CSV download. Attribution is key-based and honest: "by agent" is ground truth (every Bearer-synced row carries its key), "by member" maps each agent to the wallet that minted it, and rows synced without a key land in an unattributed bucket instead of being guessed.
Personal scope is untouched
Everything you had before orgs — your wallet's keys, grant, approvals, ledger — is the Personal scope in the dashboard switcher, and org rows never leak into it. The same APIs serve both: pass ?org=<id> (or orgId in write bodies) and the server re-checks your membership on every single call.
Next: give each connected app its own allowance on Agents & budgets, or wire receipts into the dashboard with ledger sync.