Authorizing agents
Sui Agent Payments has one spend account for agent escrow and two ways to provision a spender on it. Both issue a scoped grant bound to a delegate address. The agent holds the key in both cases.
The rail tag on the wire is delegate (renamed from shared_pool, ADR-0035).
The Move module is spend_account.
MCP OAuth (hosted / interactive)
Remote MCP agents connect through the platform OAuth flow:
- The agent generates a delegate keypair (or reuses the one it already holds) and opens the Sui Agent Payments MCP endpoint to start OAuth.
- The owner consents in the browser, selects policies, and signs an on-chain grant transaction with their wallet.
- The grant is bound to the address the agent supplied. The platform never mints or stores the delegate secret.
The agent never sees the owner key. This path is best when the agent runtime is hosted or interactive and OAuth is acceptable.
Local MCP URL shape (example for the local stack):
http://localhost:4340/mcpSee Pay with MCP.
Bring-your-own delegated key (SDK / REST)
Non-custodial agents generate their own keypair and share only the public Sui address:
- The agent generates an Ed25519 (or other Sui-supported) keypair and keeps the private key in its own runtime.
- The owner calls POST /v1/delegated-signers (verified owner session) with that address, name, policy/profile selection, and per-asset scopes (total budget, max per payment, expiry).
- The real authority is an owner-wallet-signed
create_granttransaction. An owner session alone cannot mint a grant. - Finalization verifies the grant-created event (delegate, caps, expiry, policy set, package target, finality) before the grant is reported active.
Sui Agent Payments never holds the agent's private key. Registration stores the public address and grant metadata only.
See Authorize an agent and Pay with the SDK.
Side-by-side
| MCP OAuth | Bring-your-own key | |
|---|---|---|
| Key custody | Agent generates and holds the key; OAuth binds the grant to that address | Agent generates the keypair; Sui Agent Payments stores only the public address |
| How you connect | Remote MCP OAuth consent | POST /v1/delegated-signers + owner-signed create_grant |
| On-chain grant | Spend-account grant bound to the agent-held address | Same grant model via create_grant (includes max_per_payment) |
| Settlement | Agent signs in the process that holds the key | spend_account::settle_policy_payment with the BYO delegate as sender |
Same policy model
Regardless of provisioning method, scope is:
- Service allowlist via policy targets (method/path → target hash → fixed recipient)
- Per-asset total budget (grant session cap)
- Per-signer per-payment cap (
max_per_paymenton the grant) - Asset (one grant per asset under a logical signer)
- Expiry
Enforcement is on chain at pay time. Changing scope means a new grant; policy IDs on a grant are an immutable snapshot.
Revoke and pause
- Revoke is terminal: owner-signed
revoke_grant(API: DELETE prepare + finalize). Revoked grants cannot spend. - Pause is reversible: owner-signed
pause_grant/resume_grant(API:POST /v1/delegated-signers/:id/pause/prepareand.../resume/prepare, then per-grant finalize). A paused signer cannot pay until the owner resumes.
What is not a third path
The V1 allowance rail (per-recipient escrow plus a raw delegate key) is
retired. Do not provision new agent authority on allowance. Migrate to a
spend-account delegated signer (MCP or BYO).