diff --git a/CLAUDE.md b/CLAUDE.md
index 38355a5..83dc0cc 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -31,12 +31,12 @@ Any agent should be able to take a product PR and update these docs without a hu
| Fact | Canonical home |
| --- | --- |
-| Workspace definition, creating a workspace, setup steps | `/workspaces` |
+| Workspace definition, creating a workspace, setup steps, workspaces created from an agent | `/workspaces` |
| Roles, capability matrix, settings visibility, API key scopes, read-only members | `/workspaces/roles` |
| Recovery, recovery signers, verifying them | `/workspaces/recovery` |
| Keeping workspaces unlinked onchain: per-workspace keys and recovery signers, sender/recipient hygiene | `/workspaces/privacy` |
| Settings map (each section, who sees it) | `/workspaces/settings` |
-| Member (the person), signing up, inviting, roles-are-per-team pointer, removal | `/members` |
+| Member (the person or the agent), signing up, inviting, roles-are-per-team pointer, removal, agent members | `/members` |
| Signing keys: passkeys, password managers, EOAs, verifying access, troubleshooting | `/members/keys` |
| Account types, ownership chain (Root → Treasury → sub-accounts) | `/accounts` |
| Signer definition, signers-vs-membership boundary | `/accounts/signers` |
@@ -44,7 +44,7 @@ Any agent should be able to take a product PR and update these docs without a hu
| Renaming, changing signers and thresholds, resetting signers via the owner | `/accounts/editing` |
| Proposal model, transaction types | `/transactions` |
| Gas sponsorship order, plan budgets, gas balance, top-ups | `/transactions/gas` |
-| API overview, CLI/MCP setup, API key scopes model, headless signing | `/introduction/agents` |
+| API overview, CLI/MCP setup, browser login, API key scopes model, headless signing | `/introduction/agents` |
| Experiment definition, prototype caveats | `/experiments` |
| PACT: raise mechanics, contract guarantees, limitations | `/experiments/pact` |
diff --git a/src/pages/accounts/earn.mdx b/src/pages/accounts/earn.mdx
index c920f0b..b9c6228 100644
--- a/src/pages/accounts/earn.mdx
+++ b/src/pages/accounts/earn.mdx
@@ -64,3 +64,14 @@ Splits checks each wrapper's owner and fee settings, and each Steakhouse vault's
Using Earn does not require you to manually account for vault shares or calculate the yield yourself. [Accounting](/accounting) treats a deposit as a swap of USDC into vault shares and a withdrawal as a swap back. Vault shares are tracked as their own tax lots, and yield is realized as gain on the shares when you withdraw.
Deposits and withdrawals remain in the transaction history and CSV exports. The displayed yield is net of the performance fee.
+
+## Programmatic access
+
+Via the [Splits CLI / MCP](/introduction/agents):
+
+- `splits accounts balances
`: balances, with each Earn position's underlying asset and value (**Read** scope)
+- `splits transactions create earn-deposit --account 0x... --chain-id 8453 --asset 0x... --amount 100`: propose a deposit, in asset units (**Write** scope)
+- `splits transactions create earn-withdraw ...`: propose a withdrawal, in asset units (**Write** scope)
+- `splits transactions create transfer ... --source-token `: pay a recipient from a position; see [Sends](/transactions/sends#programmatic-access)
+- `splits settings get`: the workspace's Automated Earn state (**Read** scope)
+- `splits transactions create auto-earn-on` / `auto-earn-off`: propose the Treasury transaction that toggles Automated Earn (**Write** scope, as an Owner or Treasury signer)
diff --git a/src/pages/accounts/editing.mdx b/src/pages/accounts/editing.mdx
index 5de6402..bd271ea 100644
--- a/src/pages/accounts/editing.mdx
+++ b/src/pages/accounts/editing.mdx
@@ -45,7 +45,7 @@ If every passkey on the workspace is lost, reset the Treasury first (recovery wa
Via the [Splits CLI / MCP](/introduction/agents):
-- `splits accounts update-signers --threshold N ...`: propose signer/threshold changes; approval happens in the web UI (**Owner** scope)
+- `splits accounts update-signers --add-eoa-signer-ids --threshold N`: propose signer/threshold changes, signed in the web UI or with a registered EOA (**Owner** scope)
- `splits accounts rename `: rename an account (**Owner** scope)
Resets are web-only today.
diff --git a/src/pages/accounts/index.mdx b/src/pages/accounts/index.mdx
index 045a154..cfe2e9e 100644
--- a/src/pages/accounts/index.mdx
+++ b/src/pages/accounts/index.mdx
@@ -67,4 +67,8 @@ Via the [Splits CLI / MCP](/introduction/agents):
- `splits accounts list`: all accounts in the workspace (**Read** scope)
- `splits accounts create --name "Name" --threshold 2`: create an operating account (**Owner** scope)
- `splits accounts rename ` / `archive` / `unarchive`: manage accounts (**Owner** scope)
+- `splits accounts sign-message `: sign a message as the account; see [WalletConnect](/integrations/walletconnect#programmatic-access)
- `splits automations list`: the workspace's automations (**Read** scope)
+- `splits automations create --name "Name" --forwarder 0x...`: create an automation account with its policy (**Owner** scope)
+
+Editing automations and watching external accounts are web-only today.
diff --git a/src/pages/accounts/signers.mdx b/src/pages/accounts/signers.mdx
index 6ae8df6..840cad6 100644
--- a/src/pages/accounts/signers.mdx
+++ b/src/pages/accounts/signers.mdx
@@ -35,5 +35,7 @@ The [Root account](/accounts#root)'s signers are the workspace's recovery signer
Via the [Splits CLI / MCP](/introduction/agents):
- `splits accounts signers `: an account's signers and threshold (**Read** scope)
-- `splits accounts update-signers ...`: propose signer/threshold changes; approval happens in the web UI (**Owner** scope)
+- `splits accounts update-signers ...`: propose signer/threshold changes, signed in the web UI or with a registered EOA (**Owner** scope)
+- `splits auth register-signer `: register an EOA so it can be added as a signer (**Write** scope)
+- `splits auth signers`: the EOAs registered under the key's member, with their ids (**Read** scope)
- `splits members signers `: a member's passkey IDs, for adding them as a signer (**Read** scope)
diff --git a/src/pages/banking/offramping.mdx b/src/pages/banking/offramping.mdx
index 9be4327..d62b2ed 100644
--- a/src/pages/banking/offramping.mdx
+++ b/src/pages/banking/offramping.mdx
@@ -28,3 +28,12 @@ For IBAN banks supporting SEPA Instant, settlement occurs in under 30 seconds.
If your workspace already has an offramping provider, you can offramp through it instead, without completing Splits' [entity verification](/banking#getting-verified). Most providers issue a **liquidation address**: a deposit address that converts incoming stablecoins to fiat and forwards them to your bank account. Save that address as a [contact](/contacts), then [send](/transactions/sends) stablecoins to it like any other recipient.
Splits treats these as ordinary sends: the 0.25% banking fee and the settlement times above don't apply; your provider's own fees and timing do.
+
+## Programmatic access
+
+Via the [Splits CLI / MCP](/introduction/agents):
+
+- `splits offramp external-accounts`: the workspace's bank accounts (**Owner** scope)
+- `splits transactions create offramp --account 0x... --external-account-id --amount 100`: propose an off-ramp of the amount the bank receives (**Write** and **Owner** scopes)
+
+Adding bank accounts and onramping are web-only today.
diff --git a/src/pages/contacts/index.mdx b/src/pages/contacts/index.mdx
index 5a36cb8..7cfac0d 100644
--- a/src/pages/contacts/index.mdx
+++ b/src/pages/contacts/index.mdx
@@ -46,7 +46,7 @@ Two recipient types are stored separately from contacts but appear alongside the
Via the [Splits CLI / MCP](/introduction/agents):
-- `splits contacts list --q "acme"`: search contacts by name or address; returns up to 500 (**Read** scope)
-- `splits contacts lookup --addresses 0x...,0x...`: batch address-to-name lookup, max 100 addresses (**Read** scope)
+- `splits contacts list --q "acme"`: search contacts by name or address, with their send rules; returns up to 500 (**Read** scope)
+- `splits contacts lookup --addresses 0x...,0x...`: batch address-to-name lookup, with send rules, max 100 addresses (**Read** scope)
Creating and editing contacts is web-only today.
diff --git a/src/pages/integrations/bankr.mdx b/src/pages/integrations/bankr.mdx
index b5a8edb..06bc168 100644
--- a/src/pages/integrations/bankr.mdx
+++ b/src/pages/integrations/bankr.mdx
@@ -27,7 +27,7 @@ The module path exists for autonomous execution, including calls to contracts th
## Setup
-1. An Owner creates an API key in [Settings > API Keys](https://app.splits.org/settings/team/api-keys/) (**Owner** scope is required for the agent to create accounts or propose signer changes).
+1. The agent gets access: an Owner approves its [browser login](/introduction/agents#sign-in-from-the-browser), or creates an API key in [Settings > API Keys](https://app.splits.org/settings/team/api-keys/) (**Owner** scope is required for the agent to create accounts or propose signer changes).
2. The agent authenticates (`splits auth login`), generates and registers its own signing EOA (`splits auth create-key --register`), and either creates a new account with itself and a human passkey as signers, or proposes adding itself to an existing account, approved by a human in the app.
The skill covers the exact commands, key handling, and validation rules. Everything the agent does surfaces like any other activity: proposals in the transaction feed, and module executions logged onchain and in the feed.
diff --git a/src/pages/integrations/walletconnect.mdx b/src/pages/integrations/walletconnect.mdx
index f38fee5..c08be03 100644
--- a/src/pages/integrations/walletconnect.mdx
+++ b/src/pages/integrations/walletconnect.mdx
@@ -17,3 +17,11 @@ description: Connect a Splits account to third-party apps over WalletConnect whe
2. On the account's page in Splits, paste the URI into the WalletConnect section and approve the connection.
The app's transaction and signature requests then appear in Splits, where you sign at the account's [threshold](/accounts/thresholds), the same as any transaction. Requests can also be [added to a batch](/transactions/batch#batching-from-external-apps).
+
+## Programmatic access
+
+Via the [Splits CLI / MCP](/introduction/agents):
+
+- `splits accounts sign-message --chain-id 8453 --message "..."`: sign a message as the account with a registered EOA (**Write** scope)
+
+Pairing an account with an app is web-only today.
diff --git a/src/pages/introduction/agents.mdx b/src/pages/introduction/agents.mdx
index 9340904..e607ea4 100644
--- a/src/pages/introduction/agents.mdx
+++ b/src/pages/introduction/agents.mdx
@@ -1,11 +1,11 @@
---
title: Agents & API
-description: "Operate Splits via the API or self-describing CLI, or connect AI tools over MCP: scopes, the proposal model, headless signing, and output tuning."
+description: "Operate Splits via the API or self-describing CLI, or connect AI tools over MCP: browser login, agent members, scopes, the proposal model, headless signing, and output tuning."
---
# Agents & API [Operate Splits programmatically via the API, CLI, or MCP]
-The Splits API and CLI let applications, scripts, and agents operate Splits programmatically. The CLI also runs as an MCP server for AI tools (Claude Code, Cursor, Amp).
+The Splits API and CLI let applications, scripts, and agents operate Splits programmatically. The CLI also runs as an MCP server for AI tools (Claude Code, Cursor, Codex, and others).
**The CLI is self-describing, and it, not this page, is the reference for the command surface:**
@@ -13,29 +13,50 @@ The Splits API and CLI let applications, scripts, and agents operate Splits prog
npx @splits/splits-cli@latest --llms # machine-readable manifest of every command
```
-Every command answers `--help` and `--schema`, and over [MCP](#connect-to-ai-tools-mcp) each command is exposed as a tool with its schema. This page covers what the manifest doesn't: scopes, the proposal model, headless signing, and output tuning.
+Every command answers `--help` and `--schema`, and over [MCP](#connect-to-ai-tools-mcp) each command is exposed as a tool with its schema. This page covers what the manifest doesn't: how an agent gets access, what an agent is inside a workspace, scopes, the proposal model, headless signing, and output tuning.
## Get set up
-### Get an API key
+Install the CLI where the agent runs.
-Create a key in [Settings > API Keys](https://app.splits.org/settings/team/api-keys/) with the scopes you need (the full matrix is in [Roles](/workspaces/roles#api-key-scopes)):
+```bash
+npm install -g @splits/splits-cli@latest # or run via npx @splits/splits-cli@latest
+```
-- **Read**: query data only
-- **Write**: create and propose transactions; update transaction memos and properties
-- **Owner**: manage accounts and workspace settings
+Then give it access to a workspace in one of two ways.
-Copy the key (it starts with `sk_`) and save it somewhere secure. You won't be able to see it again.
+### Sign in from the browser
-### Install the CLI and sign in
+The agent asks for access, and you approve it in the browser. No API key is copied or pasted, and the key never appears in the agent's output or conversation.
```bash
-npm install -g @splits/splits-cli@latest # or run via npx @splits/splits-cli@latest
-splits auth login --api-key sk_...
-splits auth whoami # verify: workspace, scopes, key source, local signing key
+splits auth login --client-name "Claude Code"
```
-`splits auth logout` removes the saved key.
+1. The CLI generates a local signing key, opens an approval page in the app, and prints a code. The request expires after 10 minutes.
+2. You sign in to Splits, enter the code, and pick a tab:
+ - *Connect*: choose one of your workspaces and the key's [scopes](#scopes). The **Owner** scope is offered only in workspaces where you are an Owner, and granting it makes the agent an Owner too.
+ - *Create*: create a new workspace with the agent's key on its Treasury. See [Creating a workspace from an agent](/workspaces#from-an-agent).
+3. The CLI saves the key as a workspace in `~/.splits/config.json` and makes it active.
+
+The approval makes the agent an [agent member](/members#agent-members) of the workspace, named after the `--client-name` you passed, and the key acts as that member.
+
+Under MCP, or when an agent runs the CLI in a shell tool and can't show you its output while it waits, the same flow is two calls: `splits auth login-start --client-name "..."` returns the URL and the code to show you, and `splits auth login-status` waits for the approval and saves the key.
+
+### Or bring an API key
+
+Create a key in [Settings > API Keys](https://app.splits.org/settings/team/api-keys/) with the scopes you need. Copy the key (it starts with `sk_`) and save it somewhere secure. You won't be able to see it again. A key created here acts as you: the agent's actions are recorded under your member, not under an agent of its own.
+
+```bash
+echo $SPLITS_API_KEY | splits auth login # pipe it, so the key stays out of shell history and tool-call transcripts
+splits auth whoami # verify: workspace, scopes, the user the key acts as, local signing keys
+```
+
+The `SPLITS_API_KEY` environment variable also works and takes precedence over every saved workspace, which suits CI and headless contexts.
+
+### Several workspaces
+
+Each login saves a workspace in the local config, named after the workspace it belongs to (or after `--name`). `splits auth workspaces` lists them, `splits auth use ` switches the active one, and every command takes `--workspace ` (or the `SPLITS_WORKSPACE` variable) to run once in another. `splits auth logout [alias]` removes a saved workspace.
## Use the API
@@ -48,16 +69,28 @@ The [Swagger docs](https://api.splits.org/public/docs) are the source of truth f
MCP exposes **every CLI command as a tool automatically**, including commands added later.
```bash
-splits mcp add # auto-detects Claude Code, Cursor, and other clients
+splits mcp add # registers the server with the AI tools installed on this machine (Claude Code, Cursor, Codex, and others)
```
-For any stdio MCP client, run `SPLITS_API_KEY=sk_... npx @splits/splits-cli --mcp`. `splits skills add` syncs ready-made skill files for agents. Verify the connection by asking the tool to run `splits auth whoami`.
+For any stdio MCP client, run `npx @splits/splits-cli --mcp`, with `SPLITS_API_KEY=sk_...` in its environment if you aren't using the browser login. `splits skills add` syncs ready-made skill files for agents. Verify the connection by asking the tool to run `splits auth whoami`. Under MCP, the browser login runs through the `auth_login-start` and `auth_login-status` tools, and `workspace_create` opens the approval page on its *Create* tab.
+
+## Scopes
+
+Every API key carries one or more scopes, whether you created it in Settings or granted it at a browser login. The full matrix is in [Roles](/workspaces/roles#api-key-scopes):
+
+- **Read**: query data only
+- **Write**: create and propose transactions; update transaction memos and properties
+- **Owner**: manage accounts, automations, invoices, and workspace settings
+
+Scopes don't include each other: a command that needs two, such as an off-ramp (**Write** and **Owner**), needs a key granted both. A key acts as a member, and some operations also require that member to hold the Owner role; see [API key scopes](/workspaces/roles#api-key-scopes). Scopes grant **no onchain signing authority**: moving funds headlessly requires a [registered EOA](#sign-locally-with-an-eoa) on the account's signer set.
## The model
-Everything visible in the app is queryable with the **Read** scope: accounts, balances, transactions (filterable by account, direction, amount, date, and memo), contacts, tokens, networks, members, settings, and automations.
+Everything visible in the app is queryable with the **Read** scope: accounts, balances (including [Earn](/accounts/earn#programmatic-access) positions), transactions (filterable by account, direction, amount, date, and memo), contacts with their send rules, tokens, networks, members, settings, automations, and invoices. Listing bank accounts and transferring to them require the **Owner** scope.
-Writes follow the same rule as the app: **a transaction is a [proposal](/transactions)** that executes only once signatures meet the account's threshold. `transactions create transfer` and `create custom` produce proposals (**Write** scope); signing happens in the web UI with a passkey, or headlessly with a [registered EOA](#sign-locally-with-an-eoa). **Owner**-scoped commands create and manage accounts and propose signer changes, whose approval always stays in the web UI. A brand-new workspace can be bootstrapped with `org create`; completion also happens in the web UI.
+Writes follow the same rule as the app: **a transaction is a [proposal](/transactions)** that executes only once signatures meet the account's threshold. `splits transactions create` has a subcommand per kind: `transfer` (including paying with another held token or an Earn position), `swap` (including across networks), `earn-deposit` and `earn-withdraw`, `auto-earn-on` and `auto-earn-off`, `offramp` (which also needs **Owner**), and `custom` (**Write** scope). Signing happens in the web UI with a passkey, or headlessly with a [registered EOA](#sign-locally-with-an-eoa). **Owner**-scoped commands create accounts, automations, and invoices, and propose signer and network changes; those proposals are signed like any other. Each page's "Programmatic access" section lists the commands for its surface.
+
+Every transaction the API returns carries a `dataType` (`transaction`, `merkleTransaction` for a proposal that runs on several networks, such as a signer change, or `assetTransfer`) and one object with that kind's details.
## Transaction metadata
@@ -65,23 +98,30 @@ Every transaction can carry a [memo](/transactions/memos) (max 500 characters) a
## Sign locally with an EOA
-By default, signing happens in the web UI with a passkey. To operate headlessly, register a local EOA and sign from the CLI:
+By default, signing happens in the web UI with a passkey. To operate headlessly, the agent signs with a local EOA that is a signer on the account:
-1. `splits auth create-key --register`: generate a local EOA (stored in `~/.splits/config.json`) and register it. Import an existing key instead with `echo $PRIVATE_KEY | splits auth import-key`.
-2. `splits accounts update-signers --addEoaSignerIds ... --threshold N`: propose adding it as a signer (**Owner** scope). A human approves the proposal in the web UI, and the update applies to every active network.
-3. `splits transactions sign `: sign pending proposals with the local key (**Write** scope). Auto-submits once the threshold is met.
+1. `splits auth create-key --register`: generate a local EOA (stored in `~/.splits/config.json`) and register it. Import an existing key instead with `echo $PRIVATE_KEY | splits auth import-key`. `splits auth whoami` lists the local keys and whether each is registered.
+2. `splits accounts update-signers --add-eoa-signer-ids --threshold N`: propose adding it as a signer (**Owner** scope). An agent member can propose adding its own keys, and an Owner signs it. A workspace [created from an agent](/workspaces#from-an-agent) already has the agent's key as the Treasury's only signer.
+3. `splits transactions sign `: sign pending proposals with the local key (**Write** scope). Auto-submits once the threshold is met. Signer and network changes sign the same way and execute on every network at once; on a multisig, run `splits transactions update-gas-estimation ` before the last signature.
-`splits auth delete-key` removes the local key but does **not** revoke it onchain; remove it from accounts via `update-signers`.
+`splits accounts sign-message ` signs a message as the account (ERC-1271) with the same key, as the app does for a [WalletConnect](/integrations/walletconnect#programmatic-access) request. `splits auth delete-key` removes the local key but does **not** revoke it onchain; remove it from accounts via `update-signers`.
## Tune output for agents
The CLI prints tables for humans and JSON when piped or under MCP. Global flags reshape output: `--format toon|json|yaml|md|jsonl` (`toon` is token-efficient for LLM context), `--filter-output ` to project specific fields, and `--token-count` / `--token-limit` / `--token-offset` to measure or budget output tokens.
+## Feedback
+
+`splits feedback send --text "..."` sends a note to the Splits team: the goal, the command, what came back, and what was expected. Any scope works, as long as the key acts as a member. Never include keys or other secrets in it.
+
## Examples
-- "Show me the balances for all my accounts on Base"
+- "Show me the balances for all my accounts on Base, including what's in Earn"
- "Find all outbound payments to Acme between $4,500 and $5,500 last month"
- "Tag the last 5 outbound transfers with property `category=payroll`"
- "Create a new account called 'Ops' with a 2-of-3 threshold"
-- "Send 100 USDC from my account on Base to 0x..."
+- "Send 100 USDC from my account on Base to 0x..., paying from Earn"
+- "Swap 0.5 ETH on Base for USDC on Arbitrum"
+- "Off-ramp $2,000 to our Chase account"
+- "Invoice Globex 1,500 USDC on Base, due November 1st, and email it to billing@globex.com"
- "Add my local EOA as a signer on the Ops account, then sign the pending transfer"
diff --git a/src/pages/introduction/core-concepts.mdx b/src/pages/introduction/core-concepts.mdx
index 4a32e9c..4182b8c 100644
--- a/src/pages/introduction/core-concepts.mdx
+++ b/src/pages/introduction/core-concepts.mdx
@@ -6,7 +6,7 @@ description: The three concepts Splits is built around (Workspace, Member, and A
# Core concepts [Workspace, Member, and Account: the three ideas everything else builds on]
- **[Workspace](/workspaces)**: the unit everything is scoped to. One workspace per set of books: a company, an individual, or a project.
-- **[Member](/members)**: a person who belongs to a workspace, with a role and their own signing keys.
+- **[Member](/members)**: a person, or an agent, who belongs to a workspace, with a role and their own signing keys.
- **[Account](/accounts)**: where a workspace's assets live, at the same address on every network, controlled by signers at a threshold.
## Workspace
@@ -19,7 +19,7 @@ When deciding between a new workspace and an existing one, ask "who are the owne
## Member
-A member is a person who belongs to a [workspace](/workspaces). Members authenticate with email, and one member can belong to many workspaces. Every member has a [role](/workspaces/roles) (Owner or Member) that determines what they can administer, and holds **[signing keys](/members/keys)**: passkeys saved in the app, or EOAs [registered via the CLI](/introduction/agents#sign-locally-with-an-eoa).
+A member is a person who belongs to a [workspace](/workspaces). Members authenticate with email, and one member can belong to many workspaces. An AI agent can be a member too, with its own name and keys, acting through API keys instead of a login; see [Agent members](/members#agent-members). Every member has a [role](/workspaces/roles) (Owner or Member) that determines what they can administer, and holds **[signing keys](/members/keys)**: passkeys saved in the app, or EOAs [registered via the CLI](/introduction/agents#sign-locally-with-an-eoa).
A member's signing keys can become [signers](/accounts/signers) on accounts; membership alone grants no signing authority. Signing keys, email, display name, and avatar belong to the member, not the workspace, so they work across every workspace a member is part of ([Settings > Personal](https://app.splits.org/settings/personal/general/)). For roles, inviting, and removal, see [Members](/members).
diff --git a/src/pages/introduction/networks-and-assets.mdx b/src/pages/introduction/networks-and-assets.mdx
index 724113e..0a84b25 100644
--- a/src/pages/introduction/networks-and-assets.mdx
+++ b/src/pages/introduction/networks-and-assets.mdx
@@ -73,5 +73,8 @@ Via the [Splits CLI / MCP](/introduction/agents):
- `splits chains list`: every listed network with its tier and per-feature capability flags (**Read** scope)
- `splits chains get --chainId 8453`: one network's entry (**Read** scope)
+- `splits accounts networks`: the networks enabled on the workspace (**Read** scope)
+- `splits accounts add-networks --chain-ids 10,42161`: enable networks, as a proposal when an onchain change is needed (**Owner** scope)
+- `splits accounts remove-networks --chain-ids 42161`: disable networks (**Owner** scope)
The underlying endpoint is `GET /public/v1/chains` (API key with **Read** scope); see [Use the API](/introduction/agents#use-the-api). Networks in gradual rollout are excluded until fully rolled out.
diff --git a/src/pages/invoicing/index.mdx b/src/pages/invoicing/index.mdx
index 802075e..4b2cc68 100644
--- a/src/pages/invoicing/index.mdx
+++ b/src/pages/invoicing/index.mdx
@@ -41,4 +41,10 @@ Bank payments settle to the account and network configured in the bank settings,
## Programmatic access
-Invoicing is web-only today: the [CLI / MCP](/introduction/agents) has no invoice commands.
+Via the [Splits CLI / MCP](/introduction/agents):
+
+- `splits invoices list`: the workspace's invoices, with the link each payer pays from (**Read** scope)
+- `splits invoices get `: one invoice (**Read** scope)
+- `splits invoices create`: issue an invoice, emailed to the payer in the same call (**Owner** scope, Pro plan or higher)
+
+Attachments and managing invoices are web-only today.
diff --git a/src/pages/invoicing/recurring.mdx b/src/pages/invoicing/recurring.mdx
index 14bdaa1..86a5a68 100644
--- a/src/pages/invoicing/recurring.mdx
+++ b/src/pages/invoicing/recurring.mdx
@@ -10,3 +10,11 @@ When [issuing an invoice](/invoicing), choose *Weekly*, *Monthly*, or *Annually*
Schedules run until paused: there is no end date or occurrence limit. If the first issue date is in the future, only the schedule is created, and the first invoice generates on that date. If the issue date is today or in the past but its due date has not passed, the first invoice is issued when the schedule is created. If the first due date has passed, Splits either issues that occurrence at the next available run or skips it and advances to the next occurrence; the form previews which will happen before creation. New occurrences generate daily at 11:00 UTC.
From the *Schedules* tab on the *Invoices* page, any workspace member can view a schedule's timeline and download its attachments. Owners can edit a recurring schedule or pause and resume any schedule. An Owner can also send an active one-time schedule now instead of waiting for its scheduled send. Only Owners can manage schedules; see [Roles](/workspaces/roles).
+
+## Programmatic access
+
+Via the [Splits CLI / MCP](/introduction/agents):
+
+- `splits invoices create --interval MONTHLY --due-date-days 14`: create a schedule (**Owner** scope, Pro plan or higher)
+
+Managing schedules is web-only today.
diff --git a/src/pages/members/index.mdx b/src/pages/members/index.mdx
index 5614ef9..571ff33 100644
--- a/src/pages/members/index.mdx
+++ b/src/pages/members/index.mdx
@@ -5,7 +5,7 @@ description: "What a member is in Splits: one person across many workspaces, wit
# Members [One person across many workspaces, with their own profile, keys, and a role per workspace]
-A **member** is a person in Splits, identified by their email address. One member can belong to any number of [workspaces](/workspaces), and holds two kinds of things:
+A **member** is a person in Splits, identified by their email address, or an [agent](#agent-members) acting through API keys. One member can belong to any number of [workspaces](/workspaces), and holds two kinds of things:
- **Across every workspace**: their profile (display name, email, avatar) and their [signing keys](/members/keys) (passkeys and registered EOAs). These belong to the member, not to any workspace.
- **Per workspace**: a membership, stored offchain, with a [role](/workspaces/roles) (Owner or Member), granting read access to that workspace's accounts, balances, and transactions plus the role's administrative capabilities.
@@ -32,13 +32,25 @@ To give the new member signing power on an account, continue to [Changing signer
Owners can change a member's role, remove a member, or revoke a pending invitation from the member's row in [Settings > Members](https://app.splits.org/settings/team/members/).
-Removing a member revokes their offchain access only. If their signing keys are signers on any account, remove them via a separate onchain [signer update](/accounts/editing#changing-signers-and-thresholds).
+Removing a member revokes their offchain access only, including any API keys they created in the workspace. If their signing keys are signers on any account, remove them via a separate onchain [signer update](/accounts/editing#changing-signers-and-thresholds).
+
+## Agent members
+
+An **agent member** is an AI agent that joined the workspace when a member approved its [sign-in](/introduction/agents#sign-in-from-the-browser), or by [creating the workspace](/workspaces#from-an-agent) itself. [Settings > Members](https://app.splits.org/settings/team/members/) shows it with an *Agent* label, and its activity is recorded under its name. One agent member exists per agent signing key, in every workspace that key is approved in, named after the client name the agent gave at its first sign-in.
+
+What differs from a person:
+
+- **It has no email and cannot sign in to the app.** It acts only through its API keys. A key created in Settings > API Keys acts as the person who created it, never as an agent.
+- **Its signing keys are EOAs** registered under it, never passkeys.
+- **Its role is set at approval.** It joins as a Member, or as an Owner when the approver granted its key the **Owner** scope (see [API key scopes](/workspaces/roles#api-key-scopes)). An agent that created the workspace is its Owner. Owners can change an agent's role later from its row in Settings > Members; a role change never changes the key's scopes.
+- **It cannot be invited.** Membership comes only from an approved login or an agent-created workspace.
+- **Removing it also proposes removing its keys.** Removing an agent revokes its access and creates one signer update per account where its keys are signers, dropping them; Owners sign those like any [signer change](/accounts/editing#changing-signers-and-thresholds). An account that the removal would leave below its threshold is reported instead, for a [reset](/accounts/editing#resetting-signers) through its owner.
## Programmatic access
Via the [Splits CLI / MCP](/introduction/agents):
-- `splits members list`: list all members of the workspace (requires **Read** scope)
+- `splits members list`: list all members of the workspace, people and agents (requires **Read** scope)
- `splits members signers `: list a member's passkey IDs, needed when adding them as a signer via `accounts create` or `accounts update-signers` (requires **Read** scope)
Managing members (inviting, removing, changing roles) is web-only today.
diff --git a/src/pages/members/keys.mdx b/src/pages/members/keys.mdx
index 0bbc5b5..0af3e8e 100644
--- a/src/pages/members/keys.mdx
+++ b/src/pages/members/keys.mdx
@@ -23,7 +23,7 @@ Browsers order password manager options differently. If yours doesn't appear, cl
## EOAs
-An EOA (externally owned account, a standard Ethereum keypair) can be [registered via the CLI](/introduction/agents#sign-locally-with-an-eoa) and added as a signer, letting agents and servers sign headlessly. A workspace's [recovery signers](/workspaces/recovery#recovery-signers) are also EOAs.
+An EOA (externally owned account, a standard Ethereum keypair) can be [registered via the CLI](/introduction/agents#sign-locally-with-an-eoa) and added as a signer, letting agents and servers sign headlessly. An EOA is registered under the member whose API key registers it, so an [agent member](/members#agent-members)'s keys are its own. A workspace's [recovery signers](/workspaces/recovery#recovery-signers) are also EOAs.
## Verifying access
@@ -47,7 +47,9 @@ The two key types also differ in what they expose. A passkey's public key is onc
Via the [Splits CLI / MCP](/introduction/agents):
-- `splits auth register-signer `: register an EOA so it can be added as a signer
+- `splits auth create-key --register`: generate a local EOA and register it (**Write** scope)
+- `splits auth register-signer `: register an EOA so it can be added as a signer (**Write** scope)
+- `splits auth signers`: the EOAs registered under the key's member (**Read** scope)
- `splits members signers `: a member's passkey IDs, needed when adding them as a signer (**Read** scope)
For the full headless flow (create key → register → attach → sign), see [Sign locally with an EOA](/introduction/agents#sign-locally-with-an-eoa).
diff --git a/src/pages/solutions/ai-agents.mdx b/src/pages/solutions/ai-agents.mdx
index 9cdea7d..c62b535 100644
--- a/src/pages/solutions/ai-agents.mdx
+++ b/src/pages/solutions/ai-agents.mdx
@@ -25,17 +25,18 @@ A key copied to an agent has the human's full authority on every account that th
- **Recovery is contract-enforced.** The Treasury owns the account, so the Treasury's signers can remove the agent's key by [resetting signers](/accounts/editing#resetting-signers). The reset needs no signature from the account's own signers and does not change the account's address. Deposits and integrations that point at the address keep working.
- **Scopes bound the API, signers bound the chain.** The agent's API key carries a [scope](/workspaces/roles#api-key-scopes) (Read, Write, or Owner). The scope governs what the agent can query and propose. Scopes grant **no onchain signing authority**. Only the agent's registered key on the account's signer set grants that authority.
- **Every action is a proposal.** The agent proposes [transactions](/transactions) like any client. A transaction executes when its signatures meet the threshold. The agent proposes signer changes, and a human approves them in the app.
+- **The agent is a member.** When you approve the agent's [browser login](/introduction/agents#sign-in-from-the-browser), it joins the workspace as an [agent member](/members#agent-members) with its own name and key. The workspace records its actions under its name, not yours.
- **The whole surface is available.** The CLI ships a built-in MCP server. An agent can do over the [CLI or MCP](/introduction/agents) anything that a human can do in the app.
## Setting up an agent
-Prerequisites: an [API key](/introduction/agents#get-an-api-key), and the CLI installed where the agent runs.
+Prerequisites: a [workspace](/workspaces), and the CLI installed where the agent runs.
::::steps
### Sign the agent in
-The agent [signs in to the CLI](/introduction/agents#install-the-cli-and-sign-in) with the API key. The agent then confirms the workspace, scopes, and key source.
+The agent starts a [browser login](/introduction/agents#sign-in-from-the-browser) and gives you a code. A Splits login page opens. Sign in, enter the code, and connect the workspace with the [scopes](/workspaces/roles#api-key-scopes) you choose. No API key passes through the agent. The agent then confirms the workspace, scopes, and key source.
### Generate the agent's key
@@ -62,7 +63,7 @@ Fund the account with what the agent operates on. The agent's transactions appea
- **Per-signer restrictions by target contract or function do not exist onchain today.** A key that meets the threshold alone can take any action from its account, including changing the account's signer set. The bound is the account.
- Approval steps that happen only in the app (accepting a signer change, completing workspace setup) are platform policy.
-- You create the API key in the browser. There is no programmatic route.
+- A person approves the agent's access in the browser. The exception is a [workspace the agent creates](/workspaces#from-an-agent), which needs no approval.
## Next steps
@@ -75,7 +76,8 @@ Fund the account with what the agent operates on. The agent's transactions appea
Via the [Splits CLI / MCP](/introduction/agents):
- `npx -y @splits/splits-cli@latest --llms-full`: the full command surface and MCP tool list, no install
-- `splits auth login --api-key sk_...`: sign the agent in
+- `splits auth login --client-name ""`: sign the agent in through your browser approval
+- `splits workspace create --name "" --client-name ""`: create a workspace for the agent, which you approve in the browser
- `splits auth create-key --register`: generate the agent's EOA and register it as a signer candidate
- `splits accounts update-signers --add-eoa-signer-ids --threshold N`: propose adding the agent's key, which a human approves in the app (**Owner** scope)
- `splits accounts create --name "