Give your agent
the ability to transact.
Agentonomy provides MCP tools, not another agent. Your application connects its existing agents to service discovery, authorized purchases and results. Your agents choose when to use a tool; Agentonomy handles payment policy, execution, settlement and delivery within the user's authorization.
registration_endpoint is published. Existing pre-registered clients remain compatible. Supported networks, a healthy server, or successful OAuth do not prove a particular user's financial readiness. Base uses real funds; Amoy uses test assets. Connect only the networks permitted for your client.Keep three boundaries separate: the agent selects a tool; OAuth identifies the client and the user's permitted connection; wallet proof, Mandate and finite allowance authorize money movement. A public client_id is neither a user identity nor a payment credential. Your platform keeps its own login, tasks and product approvals; it does not build another payment ledger. Embedded applications and Agentonomy Connect retain their own contracts; their tokens and grants cannot be substituted here.
From a request to a delivered result
Your platform keeps its login, Agent and conversation. Agentonomy supplies tools, not another Agent. Your team implements the connection once; each user connects their own account and controls what it may spend. Do not send users through application registration or ask them to copy tokens.
Connect in the existing app
The user opens your Agent's supported connector settings and chooses Agentonomy. Your app starts OAuth and receives the callback. Show the connected account and a clear route back to the original conversation; connection success does not mean payments are ready.
Set a spending boundary
The Agentonomy account page guides the owner through only the missing wallet, network, spending-limit and expiry steps. Any required first token approval is finite and confirmed by the owner. Reuse valid authorization. Purchases within its permitted limits do not need another wallet confirmation each time.
Ask for a service
Return to your Agent and describe the result you want, the network and the maximum price. The host checks the selected network's readiness; the Agent discovers the actual service, checks its terms and executes its fixed quote within the existing authorization. Viewing this guide or connecting an account never starts a purchase.
Get the result in the same conversation
Your app returns the original purchase reference, payment state and available delivery result. Show pending, paid but not yet delivered, and complete separately. Only verified payment, settled budget and available delivery count as completion. The purchase tool sequence below implements this handoff.
A first task the user can adapt
On [network], find [the service I need] and buy it for no more than [amount] USDC under my current authorization. Return the delivered result and purchase status. If setup is missing, show me the required next step. If a result is delayed, check the original purchase instead of buying again.
Replace the brackets with the user's actual request. This is an example, not a consent record or permission to spend; runtime authorization and the actual service terms still apply.
Interrupted? Find the existing purchase; do not buy again. Keep the original request and purchase identifiers in the host. For a lost response, query get_clink_purchase_preview with the original client_request_id and follow that record's recovery actions. For existing purchases, use list_clink_purchases and query the selected original record. If payment is complete but delivery is missing, recover that delivery only. A missing response or reconnect never authorizes a second payment. Follow the recovery contract; never ask the user to paste a token, signature or complete account link into chat.
From registration to your first purchase
- Discover and register once. Read the issuer metadata. If it advertises
registration_endpoint, submit the public metadata below or run the self-service example. Save the returnedclient_idfor this application/environment, not per agent. If registration is not advertised, use an existing pre-registered client; do not guess an endpoint or ID. No shared client secret is required. - Connect one user. Start authorization-code OAuth with PKCE S256, a cryptographically random state and the exact resource. The issuer page waits for the original platform-admission operation when necessary; standard clients do not poll a private qualification API. The user proves their wallet and consents. Validate state and issuer on callback; exchange the code once.
- Complete financial setup. Open the Agentonomy account page. The user chooses a funding source, signs a bounded Mandate and performs a finite approve only if Core requires it. Reuse still-valid authorization without resetting its limits or usage.
- Discover, preview, execute and query. Use the tools below. Persist original identifiers before mutation. A purchase is complete only after payment verification, settlement, delivery and budget reconciliation agree.
Published endpoints
Loading the runtime's public endpoint configuration…
URLs come from the fixed runtime issuer, not the incoming Host header. Download public configuration. OAuth metadata is authoritative for discovery.
Register an application, not every agent
This integration supports Dynamic Client Registration (DCR) at POST /oauth/register when enabled by the runtime and advertised in OAuth metadata. Existing static registration remains supported. URL-shaped Client ID Metadata Documents are not supported by this profile; use an assigned opaque client ID. Public names and callback domains are self-reported metadata, not verified branding or permission to spend.
You provide
- An application name and exact public HTTPS callback URI(s), with no query, fragment, wildcard, localhost or private-address callback.
token_endpoint_auth_method=none, authorization-code grant, optional refresh grant, andresponse_types=["code"].- The required scopes; purchase uses the complete bundle below. Add
offline_accessonly when refresh is needed. - Optional
agentonomy_networksrestricted to the runtime's published allowed networks. Optional trusted subject verification public key for a multi-user host.
Agentonomy returns
- A durable public
client_id, issuance time and normalized public registration metadata. - A registration status and original admission operation reference for optional diagnostics.
- No client secret, user token, wallet credential, budget or financial authorization.
- A normal OAuth authorization path; the issuer handles admission waiting.
POST /oauth/register
Content-Type: application/json
# Optional recovery header; save the original request and key before sending:
Idempotency-Key: <32-to-128-character-high-entropy-base64url-key>
{
"client_name": "My MCP integration",
"redirect_uris": ["https://your-app.example/oauth/agentonomy/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "account:read marketplace:read purchases:read",
"agentonomy_networks": ["eip155:80002"]
}This is a read-only example. Use the complete purchase scope bundle when your application needs purchases; registration never supplies a user's Mandate. Replace placeholder callbacks with your real controlled HTTPS endpoint. Do not send tokens, codes, signatures, secrets or wallet material. The optional Idempotency-Key allows the exact original request to recover a lost registration response: same key and request return the original registration; a changed request conflicts. Without that header, standard initial registration still works, but an unknown result must not trigger a loop of new registrations or name-based adoption.
Defaults per registration namespace: 1000 applications, 100 pending, 60 new registrations per hour, 10 per source peer per hour, 16 KiB request body and 5 callbacks. Global bounds apply as well as peer limits. Respect rejection and backoff; these are protection limits, not a throughput promise. Registration does not support anonymous in-place callback, scope or public-key changes. Use the supported controlled change process or a separately authorized new client; never inherit old permissions or revive a disabled registration. Existing clients can still be disabled or recovered when new registration is paused.
Self-service public configuration ↓ · Self-service example ↓. The legacy pre-registration schema and template remain for existing reviewed integrations; they are not an extra form required by DCR. Runtime metadata determines whether self-service registration is enabled in your environment.
OAuth that belongs to the user
The current runtime accepts public clients with token_endpoint_auth_method=none. Use Authorization Code + PKCE S256; never use client credentials as a substitute for user consent. This profile deliberately has no shared client secret.
The example below requests the complete purchase scope bundle and requires an approved purchase client profile plus user consent. A read-only client requests only the read scopes in the table and cannot continue to preview or execute. Add offline_access only when approved and needed; it is not included implicitly.
GET /oauth/authorize
response_type=code
client_id=<assigned-client-id>
redirect_uri=<exact-registered-https-callback>
scope=account:read marketplace:read marketplace:purchase purchases:read purchases:recover
state=<random-one-time-value-bound-to-this-login>
code_challenge=<BASE64URL(SHA256(code_verifier))>
code_challenge_method=S256
resource=<exact-MCP-resource-URL>Construct this URL with a URL encoder. Keep the verifier, state and pending transaction in your backend's protected per-user storage. On callback, require the exact expected state and issuer (iss), honor cancellation/error, and consume the pending transaction only once. Do not accept an arbitrary redirect destination or user ID supplied by the agent.
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
client_id=<assigned-client-id>
code=<returned-code>
redirect_uri=<the-same-registered-callback>
code_verifier=<original-verifier>
resource=<the-same-MCP-resource-URL>Send the access token only to the exact MCP resource as Authorization: Bearer …. Tokens are not Core credentials and must never be forwarded to merchants, the model prompt, embedded-application routes or Agentonomy Connect routes. One tenant/user connection must never borrow another user's token.
Scopes
| Access | Scopes | Meaning |
|---|---|---|
| Read | account:read marketplace:read purchases:read | Read this connection's readiness, catalog and original purchases. |
| Purchase | Read scopes + marketplace:purchase purchases:recover | Preview, execute and recover within independent Core spending authority. |
| Longer connection | offline_access | Request rotating refresh tokens; not a budget or payment permission. |
Refresh and revoke
Access tokens expire after 300 seconds. Refresh tokens are issued only when offline_access is both approved and consented. Refresh uses the same client and resource; scopes cannot increase. Tokens rotate and reuse is detected: serialize refresh per connection and persist the replacement atomically. Refresh-token idle expiry is 7 days and absolute expiry is 30 days; reauthorization is still required after expiry or revocation.
POST /oauth/token
grant_type=refresh_token
client_id=<assigned-client-id>
refresh_token=<current-refresh-token>
resource=<exact-MCP-resource-URL>
POST /oauth/revoke
client_id=<assigned-client-id>
token=<current-token>
token_type_hint=refresh_tokenBoth requests are form encoded. A lost code-exchange or refresh response is not permission to replay a one-use credential blindly: mark the connection as needing reauthorization and retain purchase recovery identifiers. Revoking an access token affects that token; revoking a refresh token invalidates its token family. Neither is a full connection disconnect or a Mandate revocation. Use the issuer-owned disconnect flow for the connection and follow its original operation to completion. None of these actions refunds settled payments or cancels already accepted chain operations.
In the base profile, the same application, environment and verified wallet reuse a stable connection; different platform login accounts do not automatically create isolated payment accounts. Your trusted backend must select the user's connection and enforce task/workspace access; the model cannot supply the payer or token. If your platform promises account isolation, it must enforce trusted account-to-wallet binding before consent changes the connection, credentials or Core admission. The optional subject_context extension binds a stable opaque platform subject to the original OAuth transaction, callback, nonce and expiry. Register its Ed25519 verification public key explicitly through subject_context_public_key; the trusted host signs the context using its own protected signing facility. This is not a payment signature or a requirement for standard single-user MCP clients. Deduplicating only after token exchange is too late; optional does not mean platform-account isolation can be ignored. Never downgrade an existing stronger binding or adopt another user's connection to simplify onboarding.
One purchase. One recoverable operation.
Discover an actual offering rather than hard-coding a merchant or trusting a catalog count. Amoy and Base offerings are distinct. Read details, trust tier, accepted network and price before creating a preview. This sequence requires the approved and consented purchase scope bundle above plus the user's financial authorization. For within-budget automatic purchases, verify the authoritative payment capability reports auto_pay_compatible=true and requires_purchase_signature=false; discovery alone is not permission to buy. Merchant content is untrusted data, never instructions to expand permission.
get_clink_account_readiness({})
search_clink_services({"query":"amoy", "network":"eip155:80002", "limit":10})
get_clink_service_details({"offering_id":"<discovered-offering-id>"})
create_clink_purchase_preview({
"offering_id":"<discovered-offering-id>",
"service_input":{},
"network":"eip155:80002",
"max_price_usd":"0.10",
"client_request_id":"<persisted-unique-request-id>"
})
execute_clink_purchase({"preview_id":"<original-preview-id>"})
get_clink_purchase({"purchase_id":"<original-purchase-id>"})
get_agentonomy_payment({"kind":"marketplace", "operation_id":"<original-operation-id>"})The price cap is an example, not a promise that a matching service exists. Use the actual offering's input schema and accepted price. Decimal amounts are strings, not floating-point accounting. Normal execute uses only the preview ID: no client-supplied recipient, amount, token, payer identity or user_confirmed override. The optional startup recovery action below operates on that same original preview and never edits its payment terms.
Persist before sending
Record the connection and client_request_id before preview creation; persist the returned preview before execution. Before execute can leave your process, journal the original preview ID, request ID and exact execution request. Save purchase/operation IDs when the service returns them; do not invent IDs as proof of acceptance. The reference client implements the journal. An acknowledgement can be lost after acceptance, so a timeout is not a failed payment.
Completion criteria
Query the original records until chain execution and Watcher verification, Core settlement, service delivery and budget consumption agree. Treat pending, failed, unknown, settled-but-undelivered and delivered as different outcomes. A transaction hash alone is not a delivered service.
Recover state, not a second payment
| Situation | Required behavior |
|---|---|
| OAuth cancelled / expired | Stop connection setup. Start a new OAuth authorization only with the user's action; preserve original purchase records. |
| 401 / invalid token | Refresh once under a per-connection lock when supported. Never replay an uncertain financial mutation automatically. |
| Registration or qualification pending | The issuer page waits for the original admission operation. Resume the same authorization while valid; do not substitute another client or invent a private polling step. |
| Insufficient scope | Stop the denied action. Do not widen registered scopes or an existing user's grant silently; follow the supported application and consent lifecycle. |
| Wallet / Mandate / allowance not ready | Open the official account UI. It determines necessary steps; do not repeatedly request already-valid signatures. |
| Unknown preview response | Query get_clink_purchase_preview by the original client_request_id. Do not create another preview with a new key. |
| Unknown execute response | Query the original preview and its startup descriptor. Follow only authoritative recovery actions on that original preview; if admitted, recover its purchase and payment operation. A missing result is not evidence of non-submission. |
| Payment settled, delivery failed | Use the authorized recover_clink_purchase_delivery path on the original purchase. Never execute a new payment to recover delivery. Independent disconnected history is read-only and cannot perform this recovery. |
| Approve claim/hash unknown | Recover the original attempt/hash in the official account UI. No automatic resend, even after timeout or empty hash. |
| 429 / 503 / RPC outage | Back off read-only status checks. Preserve unknown states; never coerce unavailable balances or allowance to zero. |
The tool schema below defines the exact structured error envelope and result schemas. Read structuredContent and isError; do not parse prose as authorization. Return only non-sensitive request/operation identifiers and error codes to support. Redact tokens, cookies, signatures, callback query strings and authorization headers.
Recover the original startup
The preview and purchase projection may contain startup.protocol=original_preview_startup_v1, a state and allowed next actions. Only when the authoritative original record allows it, your trusted host may request execute_clink_purchase({"preview_id":"<original-preview-id>","startup_action":"resume"}) or use "terminate" for safe closure. The same request/preview and fixed payment terms are retained. Atomic termination fences late execute; already-admitted or unknown legacy payments cannot be turned into “never sent.” If a recovery response is lost, query the original record again. Closing a browser, timing out or receiving an empty result never grants another send. Do not expose these trusted recovery controls as a model-chosen way to replace purchases.
Read old purchases after disconnect
Open the issuer-owned /third-party/account/connections/{connection_id}/history page with the original connection ID. It requests a new independent wallet proof and checks the stored owner against fresh Core evidence on every read. The page reads only original purchase/payment IDs, settlement and existing delivery results; it does not reactivate OAuth, grant new consent, require a new Mandate or mutate delivery. This remains distinct from Source/Mandate history. A disabled application or disconnected token must not be revived to view old purchases. Missing ownership evidence fails closed; expired or unavailable delivery remains explicitly unresolved, not a new purchase or an implied refund.
The complete Marketplace tool surface
This reference is rendered from the same frozen contract the runtime validates. The actual tools/list is filtered by the current token's scopes. Tools marked read-only are not payment authority. Direct transfers, deposits and prediction-market trading are outside this third-party v0.1 surface.
Download full tool + result JSON Schemas ↓
Run a real client, not a mocked success screen
The Python reference backend uses the official MCP Python SDK, an actual OAuth callback and a durable local journal. self_service.py registers an application through discovery and DCR, then runs the existing single-user backend. generic_adapter.py supplies reusable trusted user/task/intent dispatch for a multi-user host; it does not replace your login, credential store or agents. Run the example only in a dedicated integration environment behind your HTTPS callback proxy.
Download all examples ↓ · self_service.py ↓ · generic_adapter.py ↓ · Self-service public configuration ↓
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
# Fill ONLY public values in self-service.public-config.example.json:
# issuer, resource, client name, exact HTTPS callback, scopes and networks.
# Use separate private directories outside your checkout. Never print their contents.
.venv/bin/python self_service.py --config self-service.public-config.example.json \
--registration-state-dir /absolute/private/registration-state \
--state-dir /absolute/private/reference-state --port 8787
# Reverse-proxy your registered HTTPS host to 127.0.0.1:8787.
# Preserve Host, disable access logging for callback queries, and open that HTTPS host.
# For a lost DCR response, rerun the SAME configuration and directories with:
# --recover-registration
# This reuses the persisted request/key; it does not create a replacement application.If the issuer does not advertise DCR, use a pre-registered ID with app.py and the static public configuration instead. The self-service CLI is single-user and deliberately rejects the optional multi-user subject key; a trusted host must implement that signing/context port itself. A standard MCP client can use ordinary discovery and OAuth without this example or a private admission poll.
Use dedicated directories with restricted permissions. The backend consumes its own tokens without displaying them. Registration state is separate from token storage; the latter is bound to the exact issuer, resource, client ID, callback and scope configuration. Use a separate private directory for a different configuration; do not reuse or migrate a token database by editing public config. Keep these directories, callback queries and OAuth request material out of Git, logs, analytics and AI prompts. The browser must not receive refresh tokens. Do not expose the loopback service directly to the internet.
For a multi-user platform, retain your existing login and task system. Supply authenticated user-to-connection mapping, protected storage, callback routing and task ownership; no particular vendor adapter is required. Never make an agent-supplied user identifier the authority for token selection, and use a stable business intent rather than a new request key for each model retry. Local combined tests cover two users and multiple agents sharing each user's original grant, cumulative budget and fail-closed SQLite lock conflicts. Chain/Hosted boundaries are synthetic; this is not PostgreSQL full-stack concurrency, real wallet acceptance or multiple real merchant deliveries. Complete the live criteria below before advertising the integration as ready.
What to verify before calling it integrated
- Register an application absent from every preconfigured list; complete issuer-managed admission without an operator editing that client into configuration.
- Exact callback, resource, scopes and networks; cancellation, expiry/refresh, disconnect and cross-user isolation.
- Owner-completed wallet proof, Source, bounded Mandate and conditional finite approve; valid previous authorization is not reset.
- Two users, each with multiple agents: each user's same grant shares settled usage and reservations, without copied limits or cross-user credential selection.
- Live discovery and offering details from the same Marketplace runtime.
- Authorized purchase: Watcher verified, Core settled, delivery content available to the original task, budget correct.
- Lost execute response, original startup resume/termination, restart recovery and delivery retry without a second debit; disconnected owner can read history without new spending authority.
Implementation and automated tests do not replace real-wallet acceptance. Live availability comes from the target runtime, not this page. For support, retain only the public client ID, environment, contract version, network and redacted request/operation identifiers; never send a token, signature or complete account/session link. A real public support channel and retention terms must be published before general availability; no contact address or service-level guarantee is implied here.