APPROVED, and one
above them returns DENIED. The sandbox setup key lets you change those limits and add policies,
including merchant and category rules and a rule that holds a payment for human approval. If an
organization owner has already invited your agent,
register with their token
instead.
Sandbox signup creates a test-mode organization, one agent, one Tempo Testnet wallet, an agent SDK
key, a sandbox organization API key, and a sandbox setup key, with no email verification or human
approval. Settlement is simulated: no onchain transfer occurs, a test receipt is not an explorer
receipt, and you do not need to fund the wallet.
Discovery
Start from the agent manifest:
If your runtime skips manifests, use the endpoint directly:
environment, simulated-settlement semantics, the default wallet limits,
and a machine-readable workflow with setup, request, execute, status, human-claim, and
control-configuration actions. Each control action names the credential it needs. Use those links
instead of building route names from memory.
Create a sandbox
One command creates the sandbox, writes an owner-only.env.local, updates .gitignore, and adds
conto.config.json and a runnable example.mjs to the current directory:
.env.local holds the agent SDK key and the sandbox API key. The CLI writes the setup key to a
separate owner-only file, .conto/sandbox-setup.env, and adds .conto/ to .gitignore, so the
payment runtime that loads .env.local never receives it. The JSON result reports file locations
and environment-variable names (credentials.setupKeyStoredIn and credentials.setupKeyEnv) but
prints no secret. If the result has no setupKeyStoredIn, your CLI version predates setup keys.
Update the package, or create the sandbox with the API call below.
To test from Python 3.10+, run the CLI command above (it needs Node.js 20.19+), then use the Python
starter from the same directory. It calls Conto’s HTTP API and needs no Python dependencies.
- Download it:
curl -fsS https://conto.finance/examples/conto-sandbox.py -o conto-sandbox.py - Run
python3 conto-sandbox.pyto check setup. It prints the agent name and scopes and creates no payment. - Run
python3 conto-sandbox.py --executeto make one test payment. The script executes only in a CLI-created simulated sandbox. It creates one payment intent for0.01, prints its request ID, and executes only if the policy decision isAPPROVED. Success printsStatus: completedandSettlement mode: test. The test receipt records the workflow without transferring funds. - Each
--executerun creates a new intent. After a timeout, inspect the original request withpython3 conto-sandbox.py --status REQUEST_IDinstead of executing again. In production, store the request ID before executing.
Example extraction into one owner-only file per role:
agent.env in the payment agent’s runtime and setup.env only where you configure controls.
The commands below assume the relevant file is loaded, for example with set -a; . ./setup.env; set +a.
Credential roles
All keys are stored hashed and expire with the sandbox after 7 days. A human claim revokes the
setup key. From then on, the owner changes controls in Conto.
A coding assistant can apply the test configuration a person asked for with the setup key, then run
the payment agent with only the SDK key. The setup key never belongs in the agent’s environment,
prompt, or tool configuration.
Configure controls
The setup key works only on these routes, only for its own sandbox, and only until a human claims it. Other organization routes return403 with code: "SANDBOX_SETUP_SCOPE", and payment routes
reject it. An ID from another organization returns 404.
These are the same routes, validators, audit log, and policy history that account-backed
organizations use. See Policy rules for every rule type.
Change spend limits
spendLimitPerTx, spendLimitDaily, spendLimitWeekly,
spendLimitMonthly, allowedHoursStart, allowedHoursEnd, allowedDays, and timezone. Limits
accept 0 through 10000, or null for no limit on that window. Other fields, such as isActive
or delegationType, return 403. Wallet limits are hard limits: an approval rule cannot override
them.
Restrict merchants and categories
Create a policy and assign it to the agent:recipientAddress. Category rules match the category
the agent sends with the request. That value is agent-supplied, not a verified merchant category. A payment that omits category is denied by any category rule.
Require human approval
action defaults to ALLOW, so set REQUIRE_APPROVAL
explicitly. Keep the per-payment limit above the approval threshold, or the limit denies the
payment before review.
Change or turn off a policy
Replace a policy’s rules withPUT /api/policies/{policyId}/rules and a rules array, or turn
the policy off with PATCH /api/policies/{policyId} and { "isActive": false }. A change applies
to the next evaluation. Policy and rule changes are recorded in the policy’s history and the audit
log. Limit and assignment changes are recorded in the audit log.
Quotas and the simulated balance
A sandbox holds up to 25 policies with up to 50 rules each. Reaching a quota returns409 with
code: "SANDBOX_POLICY_QUOTA" or "SANDBOX_RULE_QUOTA". The wallet’s $100 test balance is fixed,
and the setup key cannot add to it. A payment larger than the remaining balance is denied with
the reason The available balance is insufficient for this payment., not a spending-limit
reason.
What the agent sees
The payment agent reads its effective controls with its own SDK key:GET /api/sdk/setup,
GET /api/sdk/spending-limits, and GET /api/sdk/policies. It cannot change them.
Inspect the setup
Use the SDK key returned by sandbox signup:diagnostics.environment.kind is
anonymous_sandbox, and the SANDBOX_UNCLAIMED issue tells you a person has not claimed it yet.
After a claim, the kind is claimed_sandbox. In a CLI-created project,
npx @conto_finance/create-conto-agent doctor --json prints the same diagnostics.
Run a policy-checked payment
Request a small test payment. Conto evaluates it and returns the decision instatus:
APPROVED, execute it:
"status": "completed" and receipt.settlementMode: "test".
The receipt includes a Conto transactionId and omits txHash and the explorer URL. Status and
transaction endpoints repeat the settlement mode. test never proves an onchain transfer.
GET /api/sdk/transactions includes the transaction, which counts against the configured spend
limits. With the default limits, a request over 25 in a day, returns DENIED with a
reason. A denied request never executes and never spends.
To make retries safe, send an idempotencyKey with each purchase. The same request with the same
key returns the original request. The same key with different input returns 409. Give a changed
purchase, including a retry after you change a control, a new key. If an execute call ends without
a response, check GET /api/sdk/payments/{requestId} before doing anything else. Do not execute
again blindly.
Human review
A payment that matches aREQUIRE_APPROVAL rule returns "status": "REQUIRES_APPROVAL" and an
approvalRequestId. It stays pending and does not execute. No machine credential can approve it:
the review routes refuse the SDK key, the setup key, and the sandbox API key.
To finish the review, a person claims the sandbox:
- Create a claim link with the handoff below and send
verificationUrlto the person. - The person signs in, claims the sandbox, switches to the sandbox organization in Conto, and opens Alerts & Approvals, then Approvals.
- The person approves or rejects the payment.
GET /api/sdk/payments/{requestId} with its SDK key. It does not call execute
while the payment waits.
- Approved. Conto rechecks the payment against the current controls and records a simulated
test payment. The agent sees
"status": "completed"and"settlementMode": "test". - Rejected. The agent sees
"status": "declined". Nothing is spent. - Controls changed while it waited. The recheck applies the current controls, so an approved
payment can still end as
declined. - No decision. The request expires after 24 hours.
Simulation boundary
Every payment executed in a sandbox is simulated, whatever wallet it uses. No custody provider is called, and receipts carrysettlementMode: "test" with no transaction hash or explorer link.
Spend counters and the test balance use the same reservation and accounting as live payments.
Claiming does not change this: a sandbox organization cannot create managed wallets, set up Conto
Pay, or change plans, and connected cards are not available in a sandbox. To use real funds, create
a Conto organization. The optional external signer flow below is separate: your own wallet signs
that transfer, and Conto never executes it.
Bring your own signer (optional)
If your agent controls a real Tempo Testnet wallet, callPOST /api/sdk/payments/approve with
amount, recipientAddress, your wallet as senderAddress, and chainId: 42431. An approved
response returns approvalToken and confirmUrl:
txHash and approvalToken to
confirmUrl:
Hand off to a person from a remote agent
Use this flow when your agent runs on a server, in CI, or on another device. It requires no localhost callback and never places the sandbox API key in a browser link. In a CLI-created project, one command creates the link and keeps the polling token in an owner-only file:verificationUrl to the person who will own the sandbox. Treat that URL and the returned
token as temporary secrets: keep them out of logs and public messages. The URL expires in at most
15 minutes. The person signs in, verifies their email, reviews the
sandbox name and ownership permission, and explicitly chooses Claim sandbox.
Poll statusUrl using the handoff token (not the SDK or sandbox key). Wait at least the returned
intervalSeconds between checks. Stop on claimed or on expiry. Do not repeatedly create grants.
status: "claimed" completes the handoff and revokes the setup key. It does not enable
production payments, fund a wallet, change spending limits, or extend the sandbox credentials. Delete the handoff file when done.
Review production readiness before using real funds.
Agent checklist
- Fetch
/.well-known/agent.json. - Read
machineReadable.agentSandboxQuickstartandmachineReadable.agentSandboxSignup. POST /api/agents/sandbox.- Store returned keys securely. They are shown once. Give the payment runtime only
credentials.sdkKey. Keepcredentials.setupKeywith the setup step. - Optionally configure limits and policies with the setup key.
- Call
GET /api/sdk/setupwithcredentials.sdkKey. POST /api/sdk/payments/requestwith anidempotencyKey, thenPOST /api/sdk/payments/{requestId}/executefor anAPPROVEDresult.- Verify
status: "completed"andreceipt.settlementMode: "test". Expect no hash or explorer URL in a new simulated receipt. - For
REQUIRES_APPROVAL, hand off to a person and poll the payment status. - Before the credentials expire,
POST /api/agents/sandbox/handoff, or runsandbox claimwith the CLI, and send the returnedverificationUrlto a person.
Next steps
Code examples
SDK, OpenAI, Anthropic, Python, and server examples
Payments API
Request, approve, execute, confirm, and inspect payment state
Custody modes
Choose managed execution or external-wallet approval flows
OpenAPI
Generate clients and inspect request and response schemas