Skip to main content

Overview

This guide will walk you through integrating the Conduit Treasury API into your application to programmatically manage your treasury operations.

Authentication

The Conduit Treasury API uses session-based authentication. You must be authenticated and have an active organization selected.
API requests are tied to your browser session. For programmatic access, ensure your application maintains an active session.

Base URL

All API requests should be made to:
https://app.conduit.io/api

Common Response Codes

CodeDescription
200Success
201Created
400Bad Request - Validation error
401Unauthorized - No valid session
403Forbidden - Insufficient permissions
404Not Found
409Conflict - Resource already exists
500Internal Server Error

Getting Started

1. Fetch Your Accounts

Start by fetching all accounts in your organization:
const response = await fetch('/api/accounts', {
  method: 'GET',
  credentials: 'include'
});

const { accounts } = await response.json();

2. Get Account Balances

Fetch USDC and USDT balances for all your accounts:
const response = await fetch('/api/accounts/balances', {
  method: 'GET',
  credentials: 'include'
});

const { balances } = await response.json();

// balances is an array:
// [
//   {
//     accountId: "...",
//     address: "0x...",
//     usdc: "1000.000000",
//     usdt: "500.000000"
//   }
// ]

3. Create a Transaction

Create a new transaction for approval:
const response = await fetch('/api/transactions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  credentials: 'include',
  body: JSON.stringify({
    accountId: 'account-id',
    type: 'transfer',
    amount: '1000.00',
    token: 'USDC',
    to: '0x...',
    description: 'Payment to vendor'
  })
});

const { transaction } = await response.json();

Working with Rules

Automation rules allow you to set up treasury operations that execute automatically based on conditions.

Create a Sweep Rule

Automatically sweep funds when a balance threshold is reached:
const response = await fetch('/api/rules', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  credentials: 'include',
  body: JSON.stringify({
    accountId: 'source-account-id',
    type: 'sweep',
    status: 'active',
    conditions: {
      trigger: 'balance_threshold',
      value: '10000'
    },
    actions: {
      type: 'transfer',
      params: {
        to: 'destination-account-id',
        token: 'USDC'
      }
    }
  })
});

const { rule } = await response.json();

Pause a Rule

Temporarily disable a rule:
const response = await fetch(`/api/rules/${ruleId}`, {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json'
  },
  credentials: 'include',
  body: JSON.stringify({
    status: 'paused'
  })
});

const { rule } = await response.json();

Transaction Workflow

Understanding the transaction lifecycle:
1

Create Transaction

Use POST /transactions to create a pending transaction
2

Review & Approve

Team members with appropriate permissions can approve via POST /transactions/{id}/approve
3

Execute

Once approved, execute the transaction on-chain and record the txHash via POST /transactions/{id}/execute

Example: Complete Integration

Here’s a complete example showing a typical integration pattern:
class ConduitTreasuryClient {
  private baseURL = 'https://app.conduit.io/api';

  async getAccounts() {
    const response = await fetch(`${this.baseURL}/accounts`, {
      credentials: 'include'
    });
    
    if (!response.ok) {
      throw new Error(`Failed to fetch accounts: ${response.statusText}`);
    }
    
    const { accounts } = await response.json();
    return accounts;
  }

  async getBalances() {
    const response = await fetch(`${this.baseURL}/accounts/balances`, {
      credentials: 'include'
    });
    
    const { balances } = await response.json();
    return balances;
  }

  async createTransaction(data: {
    accountId: string;
    type: 'transfer' | 'sweep' | 'strategy';
    amount: string;
    token: 'USDC' | 'USDT';
    to: string;
    description?: string;
  }) {
    const response = await fetch(`${this.baseURL}/transactions`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify(data)
    });
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error || 'Failed to create transaction');
    }
    
    const { transaction } = await response.json();
    return transaction;
  }

  async getTransactions(accountId?: string) {
    const url = new URL(`${this.baseURL}/transactions`);
    if (accountId) {
      url.searchParams.set('accountId', accountId);
    }
    
    const response = await fetch(url.toString(), {
      credentials: 'include'
    });
    
    const { transactions } = await response.json();
    return transactions;
  }

  async createRule(data: {
    accountId: string;
    type: 'sweep' | 'rebalance' | 'yield';
    status: 'active' | 'paused';
    conditions: any;
    actions: any;
  }) {
    const response = await fetch(`${this.baseURL}/rules`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify(data)
    });
    
    const { rule } = await response.json();
    return rule;
  }
}

// Usage
const client = new ConduitTreasuryClient();

// Get all accounts and their balances
const accounts = await client.getAccounts();
const balances = await client.getBalances();

// Create a transaction
const transaction = await client.createTransaction({
  accountId: accounts[0].id,
  type: 'transfer',
  amount: '1000.00',
  token: 'USDC',
  to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
});

Error Handling

Always handle errors appropriately:
try {
  const response = await fetch('/api/accounts', {
    credentials: 'include'
  });
  
  if (!response.ok) {
    const error = await response.json();
    
    if (response.status === 401) {
      // Handle unauthorized - redirect to login
      window.location.href = '/login';
    } else if (response.status === 403) {
      // Handle forbidden - show permission error
      alert(`Permission denied: ${error.error}`);
    } else {
      // Handle other errors
      console.error('API error:', error);
    }
    
    return;
  }
  
  const data = await response.json();
  // Process data
} catch (error) {
  console.error('Network error:', error);
}

Best Practices

Define interfaces for your API responses to catch errors at compile time:
interface Account {
  id: string;
  address: string;
  label: string;
  type: 'eoa' | 'safe';
}

interface Balance {
  accountId: string;
  address: string;
  usdc: string;
  usdt: string;
}
Implement retry logic with exponential backoff for production applications.
Balance data can change frequently, but account information is relatively static. Cache appropriately.
Always validate user input before sending to the API to provide better error messages.

Next Steps

Need Help?

View Full API Spec

Download the complete OpenAPI specification