Documentation Index Fetch the complete documentation index at: https://conto.finance/docs/llms.txt
Use this file to discover all available pages before exploring further.
Connecting Agents via API
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.
SDK Authentication
All SDK endpoints require the agent’s SDK key in the Authorization header:
Authorization: Bearer conto_agent_xxxxx...
Set that key as CONTO_API_KEY. Do not use CONTO_ORG_API_KEY for these /api/sdk/* calls.
Choose Your Wallet Flow First
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 -> executeConto stays in the execution path and can block the spend External (EXTERNAL)You, your agent, or your wallet stack approve -> transfer -> confirmConto 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.
Register The Wallet The Right Way
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.
Framework Integrations
OpenAI Assistants
import OpenAI from 'openai' ;
const openai = new OpenAI ();
const CONTO_API_KEY = process . env . CONTO_API_KEY ;
// Define the payment tool for your assistant
const 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' ],
},
},
},
];
// Handle the payment tool call
async function handlePayment ( args : {
amount : number ;
recipientAddress : string ;
recipientName ?: string ;
purpose : string ;
}) {
// Step 1: Request payment authorization
const requestResponse = await fetch ( 'https://conto.finance/api/sdk/payments/request' , {
method: 'POST' ,
headers: {
Authorization: `Bearer ${ CONTO_API_KEY } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
amount: args . amount ,
recipientAddress: args . recipientAddress ,
recipientName: args . recipientName ,
purpose: args . purpose ,
category: 'OPERATIONS' ,
}),
});
const request = await requestResponse . json ();
if ( request . status === 'DENIED' ) {
return { success: false , error: request . reasons . join ( ', ' ) };
}
if ( request . status === 'REQUIRES_APPROVAL' ) {
return { success: false , pending: true , message: 'Payment requires manual approval' };
}
// Step 2: Execute the approved payment
const executeResponse = await fetch (
`https://conto.finance/api/sdk/payments/ ${ request . requestId } /execute` ,
{
method: 'POST' ,
headers: { Authorization: `Bearer ${ CONTO_API_KEY } ` },
}
);
const result = await executeResponse . json ();
return {
success: true ,
transactionHash: result . txHash ,
amount: result . amount ,
explorerUrl: result . explorerUrl ,
};
}
In your OpenAI chat loop, check for tool_calls in the response. When the model calls
make_payment, extract the arguments, call the Conto API, and send the result back as a tool
response message.
import Anthropic from '@anthropic-ai/sdk' ;
const anthropic = new Anthropic ();
const CONTO_API_KEY = process . env . CONTO_API_KEY ;
const tools = [
{
name: 'make_payment' ,
description: 'Make a payment to a recipient using Conto' ,
input_schema: {
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' ],
},
},
];
async function runAgent ( userMessage : string ) {
const response = await anthropic . messages . create ({
model: 'claude-opus-4-5-20251101' ,
max_tokens: 1024 ,
tools: tools ,
messages: [{ role: 'user' , content: userMessage }],
});
for ( const block of response . content ) {
if ( block . type === 'tool_use' && block . name === 'make_payment' ) {
const result = await executeContoPayment ( block . input );
// Continue conversation with tool result...
}
}
}
async function executeContoPayment ( input : any ) {
const request = await fetch ( 'https://conto.finance/api/sdk/payments/request' , {
method: 'POST' ,
headers: {
Authorization: `Bearer ${ CONTO_API_KEY } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( input ),
}). then (( r ) => r . json ());
if ( request . status !== 'APPROVED' ) {
return { error: request . reasons ?. join ( ', ' ) || 'Payment not approved' };
}
const result = await fetch (
`https://conto.finance/api/sdk/payments/ ${ request . requestId } /execute` ,
{
method: 'POST' ,
headers: { Authorization: `Bearer ${ CONTO_API_KEY } ` },
}
). then (( r ) => r . json ());
return result ;
}
LangChain
import { Tool } from '@langchain/core/tools' ;
const CONTO_API_KEY = process . env . CONTO_API_KEY ;
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 );
const request = await fetch ( 'https://conto.finance/api/sdk/payments/request' , {
method: 'POST' ,
headers: {
Authorization: `Bearer ${ CONTO_API_KEY } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
amount: params . amount ,
recipientAddress: params . recipientAddress ,
purpose: params . purpose ,
category: params . category || 'OPERATIONS' ,
}),
}). then (( r ) => r . json ());
if ( request . status === 'DENIED' ) {
return JSON . stringify ({ error: `Payment denied: ${ request . reasons . join ( ', ' ) } ` });
}
if ( request . status === 'REQUIRES_APPROVAL' ) {
return JSON . stringify ({
pending: true ,
message: 'Payment requires manual approval' ,
requestId: request . requestId ,
});
}
const result = await fetch (
`https://conto.finance/api/sdk/payments/ ${ request . requestId } /execute` ,
{
method: 'POST' ,
headers: { Authorization: `Bearer ${ CONTO_API_KEY } ` },
}
). then (( r ) => r . json ());
return JSON . stringify ({
success: true ,
transactionHash: result . txHash ,
amount: result . amount ,
explorerUrl: result . explorerUrl ,
});
}
}
Python (Any Framework)
import os
import requests
CONTO_API_KEY = os.environ.get( 'CONTO_API_KEY' )
CONTO_API_URL = 'https://conto.finance/api'
def make_payment ( amount : float , recipient_address : str , purpose : str , recipient_name : str = None ):
"""Make a payment via Conto API"""
headers = {
'Authorization' : f 'Bearer { CONTO_API_KEY } ' ,
'Content-Type' : 'application/json'
}
# Step 1: Request authorization
request_payload = {
'amount' : amount,
'recipientAddress' : recipient_address,
'purpose' : purpose,
'recipientName' : recipient_name,
'category' : 'OPERATIONS'
}
response = requests.post(
f ' { CONTO_API_URL } /sdk/payments/request' ,
headers = headers,
json = request_payload
)
request_data = response.json()
if request_data.get( 'status' ) == 'DENIED' :
return { 'success' : False , 'error' : ', ' .join(request_data.get( 'reasons' , []))}
if request_data.get( 'status' ) == 'REQUIRES_APPROVAL' :
return { 'success' : False , 'pending' : True , 'requestId' : request_data[ 'requestId' ]}
# Step 2: Execute the payment
execute_response = requests.post(
f ' { CONTO_API_URL } /sdk/payments/ { request_data[ "requestId" ] } /execute' ,
headers = headers
)
result = execute_response.json()
return {
'success' : True ,
'transactionHash' : result.get( 'txHash' ),
'amount' : result.get( 'amount' ),
'explorerUrl' : result.get( 'explorerUrl' )
}
Payment Endpoints Reference
Endpoint Method Description /api/sdk/payments/requestPOST Request payment authorization /api/sdk/payments/approvePOST Approve payment for external wallet /api/sdk/payments/{id}/executePOST Execute approved payment /api/sdk/payments/{id}/confirmPOST Confirm external wallet payment /api/sdk/payments/{id}GET Get payment status
Error Handling
Status Code Description 400 INVALID_INPUTInvalid request data 401 AUTH_FAILEDInvalid SDK key 403 AGENT_SUSPENDEDAgent is suspended 403 INSUFFICIENT_BALANCEWallet balance too low 403 SPEND_LIMIT_EXCEEDEDSpending limit reached 403 TIME_WINDOW_VIOLATIONOutside allowed hours 429 RATE_LIMITEDToo many requests
For full error handling patterns, see Error Handling .
Next Steps
Make Your First Payment Detailed payment flow walkthrough
SDK Reference Full SDK documentation
Examples Complete integration examples
Error Handling Handle errors gracefully