Connecting Agents via API
This guide shows how to connect your AI agents to Conto programmatically, enabling them to request and execute payments through the Conto API.
Overview
The integration flow is:
1. Create Agent (Dashboard or API)
↓
2. Generate SDK Key
↓
3. Link Wallet with Spend Limits
↓
4. Agent Authenticates with SDK Key
↓
5. Agent Requests & Executes Payments
Step 1: Create an Agent
Via API
curl -X POST https://conto.finance/api/agents \
-H "Authorization: Bearer $CONTO_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Support Agent",
"agentType": "OPENAI_ASSISTANT",
"description": "Handles customer inquiries and refunds",
"externalId": "asst_abc123xyz"
}'
Response
{
"id" : "clx1234567890" ,
"name" : "Customer Support Agent" ,
"agentType" : "OPENAI_ASSISTANT" ,
"status" : "ACTIVE" ,
"publicKey" : "0x04a1b2c3..." ,
"description" : "Handles customer inquiries and refunds" ,
"externalId" : "asst_abc123xyz" ,
"createdAt" : "2024-01-15T10:00:00Z"
}
Agent Types
Type Use Case OPENAI_ASSISTANTOpenAI Assistants API ANTHROPIC_CLAUDEClaude via Anthropic API LANGCHAINLangChain agents AUTOGPTAutoGPT instances CUSTOMAny other AI framework
Step 2: Generate an SDK Key
SDK keys authenticate your agent when making payment requests.
curl -X POST https://conto.finance/api/agents/{agentId}/sdk-keys \
-H "Authorization: Bearer $CONTO_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"name": "Production Key",
"expiresInDays": 90
}'
Response
{
"id" : "key_abc123" ,
"key" : "conto_agent_a1b2c3d4e5f6g7h8i9j0..." ,
"name" : "Production Key" ,
"expiresAt" : "2024-04-15T00:00:00Z" ,
"message" : "Save this key now! It will not be shown again."
}
Save the SDK key immediately! It’s only shown once. Store it securely in environment variables.
Step 3: Link a Wallet
Agents need a linked wallet to make payments.
curl -X POST https://conto.finance/api/agents/{agentId}/wallets \
-H "Authorization: Bearer $CONTO_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"walletId": "wal_xyz789",
"spendLimitPerTx": 100,
"spendLimitDaily": 1000,
"spendLimitWeekly": 5000,
"spendLimitMonthly": 15000,
"allowedHoursStart": 9,
"allowedHoursEnd": 17,
"allowedDays": ["Mon", "Tue", "Wed", "Thu", "Fri"],
"timezone": "America/New_York"
}'
Step 4: Integrate with Your Agent
Now your agent can make payment requests using the SDK key.
OpenAI Assistants
import OpenAI from 'openai' ;
const openai = new OpenAI ();
const CONTO_SDK_KEY = process . env . CONTO_SDK_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_SDK_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_SDK_KEY } ` }
}
);
const result = await executeResponse . json ();
return {
success: true ,
transactionHash: result . txHash ,
amount: result . amount ,
explorerUrl: result . explorerUrl
};
}
import Anthropic from '@anthropic-ai/sdk' ;
const anthropic = new Anthropic ();
const CONTO_SDK_KEY = process . env . CONTO_SDK_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-sonnet-4-20250514" ,
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 ) {
// Request authorization
const request = await fetch ( 'https://conto.finance/api/sdk/payments/request' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ CONTO_SDK_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' };
}
// Execute payment
const result = await fetch (
`https://conto.finance/api/sdk/payments/ ${ request . requestId } /execute` ,
{
method: 'POST' ,
headers: { 'Authorization' : `Bearer ${ CONTO_SDK_KEY } ` }
}
). then ( r => r . json ());
return result ;
}
LangChain
import { Tool } from "@langchain/core/tools" ;
const CONTO_SDK_KEY = process . env . CONTO_SDK_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 );
// Request authorization
const request = await fetch ( 'https://conto.finance/api/sdk/payments/request' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ CONTO_SDK_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 });
}
// Execute the payment
const result = await fetch (
`https://conto.finance/api/sdk/payments/ ${ request . requestId } /execute` ,
{
method: 'POST' ,
headers: { 'Authorization' : `Bearer ${ CONTO_SDK_KEY } ` }
}
). then ( r => r . json ());
return JSON . stringify ({
success: true ,
transactionHash: result . txHash ,
amount: result . amount ,
explorerUrl: result . explorerUrl
});
}
}
// Use in your LangChain agent
const paymentTool = new ContoPaymentTool ();
Python (Any Framework)
import os
import requests
CONTO_SDK_KEY = os.environ.get( 'CONTO_SDK_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_SDK_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' )
}
API Endpoints Reference
SDK Authentication
All SDK endpoints require the agent’s SDK key:
Authorization: Bearer conto_agent_xxxxx...
Payment Endpoints
Endpoint Method Description /api/sdk/payments/requestPOST Request payment authorization /api/sdk/payments/{id}/executePOST Execute approved payment /api/sdk/payments/{id}GET Get payment status /api/sdk/payments/{id}/confirmGET Check transaction confirmation
Request Payment
curl -X POST https://conto.finance/api/sdk/payments/request \
-H "Authorization: Bearer $CONTO_SDK_KEY " \
-H "Content-Type: application/json" \
-d '{
"amount": 50.00,
"recipientAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
"recipientName": "OpenAI",
"purpose": "GPT-4 API credits",
"category": "AI_SERVICES"
}'
Request Body
Field Type Required Description amountnumber Yes Payment amount recipientAddressstring Yes Recipient wallet address (0x…) recipientNamestring No Human-readable recipient name purposestring No Payment purpose (for audit) categorystring No Spending category urgencystring No LOW, NORMAL, HIGH, CRITICALcontextobject No Additional metadata
Response
{
"requestId" : "clx1234567890" ,
"status" : "APPROVED" ,
"wallet" : {
"id" : "wal_xyz789" ,
"address" : "0x..." ,
"availableBalance" : 500
},
"expiresAt" : "2024-01-15T12:05:00Z" ,
"reasons" : [ "All spending policies satisfied" ]
}
Execute Payment
curl -X POST https://conto.finance/api/sdk/payments/{requestId}/execute \
-H "Authorization: Bearer $CONTO_SDK_KEY "
Response
{
"transactionId" : "tx_abc123" ,
"txHash" : "0x7a8b9c..." ,
"status" : "CONFIRMING" ,
"amount" : 50.00 ,
"currency" : "USD" ,
"recipient" : "0x742d35Cc..." ,
"recipientName" : "OpenAI" ,
"explorerUrl" : "https://basescan.org/tx/0x7a8b9c..."
}
Error Handling
Common Errors
Status Code Description Action 400 INVALID_INPUTInvalid request data Check request format 401 AUTH_FAILEDInvalid SDK key Verify key is correct 403 AGENT_SUSPENDEDAgent is suspended Contact admin 403 INSUFFICIENT_BALANCEWallet balance too low Fund the wallet 403 SPEND_LIMIT_EXCEEDEDSpending limit reached Wait for reset or increase limit 403 TIME_WINDOW_VIOLATIONOutside allowed hours Wait for allowed time 404 REQUEST_NOT_FOUNDRequest ID not found Check request ID 410 REQUEST_EXPIREDAuthorization expired Request new authorization
Example Error Response
{
"error" : "SPEND_LIMIT_EXCEEDED" ,
"message" : "Daily spending limit exceeded" ,
"details" : {
"limit" : 1000 ,
"spent" : 950 ,
"requested" : 100 ,
"resetsAt" : "2024-01-16T00:00:00Z"
}
}
Best Practices
Never hardcode SDK keys. Use environment variables: // Good
const key = process . env . CONTO_SDK_KEY ;
// Bad - never do this
const key = "conto_agent_abc123..." ;
Include meaningful purpose strings for better audit trails: await requestPayment ({
amount: 100 ,
recipientAddress: '0x...' ,
purpose: 'AWS EC2 instance for training job #1234' , // Specific
category: 'INFRASTRUCTURE'
});
Handle All Response States
Always handle APPROVED, DENIED, and REQUIRES_APPROVAL: switch ( request . status ) {
case 'APPROVED' :
// Execute payment
break ;
case 'DENIED' :
// Log reason, alert user
break ;
case 'REQUIRES_APPROVAL' :
// Notify approvers, wait
break ;
}
Add retry logic for transient failures: async function executeWithRetry ( requestId : string , maxRetries = 3 ) {
for ( let i = 0 ; i < maxRetries ; i ++ ) {
try {
return await executePayment ( requestId );
} catch ( error ) {
if ( i === maxRetries - 1 ) throw error ;
await sleep ( 1000 * Math . pow ( 2 , i )); // Exponential backoff
}
}
}
Testing Your Integration
Test your integration in demo mode before going live:
// Use the demo endpoint for testing
const CONTO_API_URL = process . env . NODE_ENV === 'production'
? 'https://conto.finance/api'
: 'https://conto.finance/api' ; // Same URL, demo mode via dashboard
// Test payment
const result = await requestPayment ({
amount: 10 ,
recipientAddress: '0x...' ,
purpose: 'Integration test'
});
console . log ( 'Test result:' , result );
Next Steps