This guide shows how to connect different AI agent frameworks to Conto, enabling them to request,
approve, execute, and confirm payments depending on the wallet model you choose.
Before wiring up tool calls, decide whether your agent uses a managed wallet or an external wallet.
Wallet model
Who holds the keys
Endpoints
What Conto can stop
Managed (PRIVY, SPONGE)
The custody provider
request -> execute
Conto stays in the execution path and can block the spend
External (EXTERNAL)
You, your agent, or your wallet stack
approve -> transfer -> confirm
Conto can gate the Conto-routed flow, but cannot block a direct self-signed transfer outside Conto
The framework examples below assume a managed wallet and use request -> execute. If your agent
holds the signing keys, switch to approve -> transfer -> confirm instead. See
Custody Modes for the full breakdown.
If your integration already has a wallet, register that same wallet in Conto instead of creating a
second one.
For an existing Privy wallet, create the Conto wallet with custodyType=PRIVY,
externalWalletId, and address. Conto will attach or reuse the wallet record instead of
minting a new Privy wallet.
For a self-custodied wallet or MPC stack outside Conto, register it as custodyType=EXTERNAL
with its address.
Wallet registration is idempotent per externalWalletId + chainId or address + chainId, so
your backend can safely retry the request.
If the signer lives in a different Privy app than the one Conto is configured to use, do not use
the managed PRIVY attach path. Register that wallet as EXTERNAL and use the external
approve -> transfer -> confirm flow instead.
Every framework integration wraps the same two-call flow: request (policy check), then execute.
Define it once and reuse it from each framework’s tool handler:
import OpenAI from 'openai';const openai = new OpenAI();// Define the payment tool for your assistantconst tools = [ { type: 'function', function: { name: 'make_payment', description: 'Make a payment to a recipient', parameters: { type: 'object', properties: { amount: { type: 'number', description: 'Payment amount in USD' }, recipientAddress: { type: 'string', description: 'Recipient wallet address' }, recipientName: { type: 'string', description: 'Recipient name' }, purpose: { type: 'string', description: 'Payment purpose' }, }, required: ['amount', 'recipientAddress', 'purpose'], }, }, },];
In your OpenAI chat loop, check for tool_calls in the response. When the model calls
make_payment, parse the arguments, pass them to executeContoPayment, and send the result back
as a tool response message.
import { Tool } from '@langchain/core/tools';class ContoPaymentTool extends Tool { name = 'conto_payment'; description = 'Make a payment using Conto. Input should be JSON with amount, recipientAddress, and purpose.'; async _call(input: string): Promise<string> { const params = JSON.parse(input) as PaymentInput; return JSON.stringify(await executeContoPayment(params)); }}
Register make_payment (defined above) as a tool in your framework of choice (CrewAI, AutoGen,
or a custom loop) and return its dict result to the model as the tool output.
Policy denials are not HTTP errors. When a payment violates a policy (spend limit, time window,
counterparty rule), /api/sdk/payments/request returns 200 with status: "DENIED" and a
violations array describing each violation (for example DAILY_LIMIT or TIME_WINDOW).For full error handling patterns, see Error Handling.