Skip to main content

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

TypeUse 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.
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
  };
}

Anthropic Claude (Tool Use)

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

EndpointMethodDescription
/api/sdk/payments/requestPOSTRequest payment authorization
/api/sdk/payments/{id}/executePOSTExecute approved payment
/api/sdk/payments/{id}GETGet payment status
/api/sdk/payments/{id}/confirmGETCheck 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

FieldTypeRequiredDescription
amountnumberYesPayment amount
recipientAddressstringYesRecipient wallet address (0x…)
recipientNamestringNoHuman-readable recipient name
purposestringNoPayment purpose (for audit)
categorystringNoSpending category
urgencystringNoLOW, NORMAL, HIGH, CRITICAL
contextobjectNoAdditional 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

StatusCodeDescriptionAction
400INVALID_INPUTInvalid request dataCheck request format
401AUTH_FAILEDInvalid SDK keyVerify key is correct
403AGENT_SUSPENDEDAgent is suspendedContact admin
403INSUFFICIENT_BALANCEWallet balance too lowFund the wallet
403SPEND_LIMIT_EXCEEDEDSpending limit reachedWait for reset or increase limit
403TIME_WINDOW_VIOLATIONOutside allowed hoursWait for allowed time
404REQUEST_NOT_FOUNDRequest ID not foundCheck request ID
410REQUEST_EXPIREDAuthorization expiredRequest 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'
});
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