Skip to main content

Overview

This guide walks you through integrating the Camino Treasury API to programmatically manage wallets, track transactions, prepare deposits and withdrawals, estimate yield, and configure webhooks.

Authentication

The Camino Treasury API uses API key authentication. Include your key in the x-api-key header on every request.
API keys are scoped to a single organization. All data returned is isolated to that organization.

Base URL

All API requests should be made to:
https://api.caminotreasury.com/v1

Common Response Codes

CodeDescription
200Success
201Created
400Bad Request - Validation error
401Unauthorized - Missing or invalid API key
404Not Found
409Conflict - Resource already exists
429Too Many Requests - Rate limit exceeded
500Internal Server Error

Getting Started

1. Fetch Your Wallets

Start by fetching all wallets in your organization:
const response = await fetch('https://api.caminotreasury.com/v1/wallets', {
  headers: { 'x-api-key': 'your-api-key' }
});

const { data: wallets, count } = await response.json();

2. Get Balances

Fetch token balances for a specific wallet on a chain:
const chainId = 43114; // Avalanche
const address = '0x742d35cc6634c0532925a3b844bc454e4438f44e';

const response = await fetch(
  `https://api.caminotreasury.com/v1/${chainId}/balances/${address}`,
  { headers: { 'x-api-key': 'your-api-key' } }
);

const { data: balances, count } = await response.json();

// balances is an array of token balances:
// [
//   {
//     "token": "0xa0b8...49dc",
//     "name": "USDC",
//     "symbol": "USDC",
//     "raw": "10000500000",
//     "decimals": 6
//   },
//   {
//     "token": "0xdac1...1ec7",
//     "name": "USDT",
//     "symbol": "USDT",
//     "raw": "5000000000",
//     "decimals": 6
//   }
// ]

3. Submit a Transaction for Tracking

Record a transaction that was submitted on-chain:
const chainId = 43114;

const response = await fetch(
  `https://api.caminotreasury.com/v1/${chainId}/transactions`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': 'your-api-key'
    },
    body: JSON.stringify({
      hash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
      walletId: 1,
      type: 'deposit',
      from: '0x742d35cc6634c0532925a3b844bc454e4438f44e',
      token: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
      amount: '1000000000',
      contract: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
    })
  }
);

const { transaction } = await response.json();
// { hash: "0x1234...", chainId: 43114, status: "pending" }

4. Get a Transaction with Receipt

Retrieve a transaction along with its on-chain receipt:
const chainId = 43114;
const hash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';

const response = await fetch(
  `https://api.caminotreasury.com/v1/${chainId}/transactions/${hash}`,
  { headers: { 'x-api-key': 'your-api-key' } }
);

const { transaction, receipt } = await response.json();
// receipt is null if the transaction has not been confirmed yet

5. Prepare a Deposit

Get the transaction steps to deposit USDC into C0:
const chainId = 43114;

const response = await fetch(
  `https://api.caminotreasury.com/v1/${chainId}/deposit/prepare`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': 'your-api-key'
    },
    body: JSON.stringify({
      token: 'USDC',
      amount: '1000.00',
      from: '0x742d35cc6634c0532925a3b844bc454e4438f44e',
      recipient: '0x742d35cc6634c0532925a3b844bc454e4438f44e'
    })
  }
);

const { steps, summary } = await response.json();
// steps: [{ type: "approve", description: "...", transaction: { to, data, value } }, ...]
// summary: { tokenIn: "USDC", tokenOut: "C0", amountIn: "1000.00", amountInRaw: "1000000000" }

6. Estimate Yield

Get yield projection for a wallet’s C0 balance:
const chainId = 43114;
const address = '0x742d35cc6634c0532925a3b844bc454e4438f44e';

const response = await fetch(
  `https://api.caminotreasury.com/v1/${chainId}/yield/estimate?address=${address}`,
  { headers: { 'x-api-key': 'your-api-key' } }
);

const { earning, decimals, rate, dailyYield, monthlyYield, annualYield } =
  await response.json();
// rate.apy: 0.045 (4.5% net APY)

Example: Complete Integration

Here’s a complete TypeScript client for the Camino Treasury API:
class CaminoTreasuryClient {
  private baseURL = 'https://api.caminotreasury.com/v1';
  private apiKey: string;

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }

  private headers(json = false): Record<string, string> {
    const h: Record<string, string> = { 'x-api-key': this.apiKey };
    if (json) h['Content-Type'] = 'application/json';
    return h;
  }

  // Wallets

  async listWallets(): Promise<{ data: Wallet[]; count: number }> {
    const res = await fetch(`${this.baseURL}/wallets`, {
      headers: this.headers()
    });
    if (!res.ok) throw new Error(`Failed to fetch wallets: ${res.statusText}`);
    return res.json();
  }

  async createWallet(input: { address: string; label: string }): Promise<Wallet> {
    const res = await fetch(`${this.baseURL}/wallets`, {
      method: 'POST',
      headers: this.headers(true),
      body: JSON.stringify(input)
    });
    if (!res.ok) {
      const err = await res.json();
      throw new Error(err.error || 'Failed to create wallet');
    }
    const { wallet } = await res.json();
    return wallet;
  }

  async deleteWallet(address: string): Promise<void> {
    const res = await fetch(`${this.baseURL}/wallets/${address}`, {
      method: 'DELETE',
      headers: this.headers()
    });
    if (!res.ok) throw new Error(`Failed to delete wallet: ${res.statusText}`);
  }

  // Balances

  async getBalances(chainId: number, address: string): Promise<{ data: TokenBalance[]; count: number }> {
    const res = await fetch(
      `${this.baseURL}/${chainId}/balances/${address}`,
      { headers: this.headers() }
    );
    if (!res.ok) throw new Error(`Failed to fetch balances: ${res.statusText}`);
    return res.json();
  }

  // Transactions

  async listTransactions(chainId: number, params?: {
    status?: 'pending' | 'confirmed' | 'failed';
    type?: 'deposit' | 'withdrawal' | 'yield' | 'approval' | 'other';
    limit?: number;
    cursor?: string;
  }): Promise<{ data: Transaction[]; count: number; pagination: Pagination }> {
    const url = new URL(`${this.baseURL}/${chainId}/transactions`);
    if (params) {
      Object.entries(params).forEach(([key, value]) => {
        if (value !== undefined) url.searchParams.set(key, String(value));
      });
    }
    const res = await fetch(url.toString(), { headers: this.headers() });
    if (!res.ok) throw new Error(`Failed to fetch transactions: ${res.statusText}`);
    return res.json();
  }

  async createTransaction(chainId: number, input: {
    hash: string;
    walletId: number;
    type: 'deposit' | 'withdrawal' | 'yield' | 'approval' | 'other';
    from: string;
    token: string;
    amount: string;
    contract: string;
  }): Promise<{ hash: string; chainId: number; status: string }> {
    const res = await fetch(`${this.baseURL}/${chainId}/transactions`, {
      method: 'POST',
      headers: this.headers(true),
      body: JSON.stringify(input)
    });
    if (!res.ok) {
      const err = await res.json();
      throw new Error(err.error || 'Failed to create transaction');
    }
    const { transaction } = await res.json();
    return transaction;
  }

  async getTransaction(chainId: number, hash: string): Promise<{
    transaction: Transaction;
    receipt: Receipt | null;
  }> {
    const res = await fetch(
      `${this.baseURL}/${chainId}/transactions/${hash}`,
      { headers: this.headers() }
    );
    if (!res.ok) throw new Error(`Failed to fetch transaction: ${res.statusText}`);
    return res.json();
  }

  // Deposit & Withdraw

  async prepareDeposit(chainId: number, input: PrepareSwapInput): Promise<PrepareSwapResult> {
    const res = await fetch(`${this.baseURL}/${chainId}/deposit/prepare`, {
      method: 'POST',
      headers: this.headers(true),
      body: JSON.stringify(input)
    });
    if (!res.ok) throw new Error(`Failed to prepare deposit: ${res.statusText}`);
    return res.json();
  }

  async prepareWithdraw(chainId: number, input: PrepareSwapInput): Promise<PrepareSwapResult> {
    const res = await fetch(`${this.baseURL}/${chainId}/withdraw/prepare`, {
      method: 'POST',
      headers: this.headers(true),
      body: JSON.stringify(input)
    });
    if (!res.ok) throw new Error(`Failed to prepare withdrawal: ${res.statusText}`);
    return res.json();
  }

  // Yield

  async estimateYield(chainId: number, address: string): Promise<YieldEstimate> {
    const res = await fetch(
      `${this.baseURL}/${chainId}/yield/estimate?address=${address}`,
      { headers: this.headers() }
    );
    if (!res.ok) throw new Error(`Failed to estimate yield: ${res.statusText}`);
    return res.json();
  }

  // Webhooks

  async listWebhooks(): Promise<{ data: WebhookListItem[]; count: number }> {
    const res = await fetch(`${this.baseURL}/webhooks`, {
      headers: this.headers()
    });
    if (!res.ok) throw new Error(`Failed to fetch webhooks: ${res.statusText}`);
    return res.json();
  }

  async createWebhook(input: {
    url: string;
    events: ('transaction.confirmed' | 'transaction.failed')[];
    wallets?: string[];
  }): Promise<Webhook> {
    const res = await fetch(`${this.baseURL}/webhooks`, {
      method: 'POST',
      headers: this.headers(true),
      body: JSON.stringify(input)
    });
    if (!res.ok) {
      const err = await res.json();
      throw new Error(err.error || 'Failed to create webhook');
    }
    const { webhook } = await res.json();
    return webhook;
  }

  async deleteWebhook(id: number): Promise<void> {
    const res = await fetch(`${this.baseURL}/webhooks/${id}`, {
      method: 'DELETE',
      headers: this.headers()
    });
    if (!res.ok) throw new Error(`Failed to delete webhook: ${res.statusText}`);
  }
}

// Types

interface Wallet {
  id: number;
  address: string;
  label: string;
  createdAt: string;
}

interface TokenBalance {
  token: string;
  name: string;
  symbol: string;
  raw: string;
  decimals: number;
}

interface Transaction {
  hash: string;
  chainId: number;
  status: 'pending' | 'confirmed' | 'failed';
  type: 'deposit' | 'withdrawal' | 'yield' | 'approval' | 'other';
  from: string;
  contract: string;
  token: string;
  amount: string;
  organizationId: string;
  walletId: number;
  createdAt: string;
  updatedAt: string;
}

interface Receipt {
  chainId: number;
  hash: string;
  from: string;
  to: string | null;
  transactionIndex: number;
  blockHash: string;
  blockNumber: number;
  type: number | null;
  contractAddress: string | null;
  status: number | null;
  root: string | null;
  createdAt: string;
  updatedAt: string;
}

interface Pagination {
  hasMore: boolean;
  nextCursor: string | null;
}

interface PrepareSwapInput {
  token: 'USDC' | 'USDT';
  amount: string;
  from: string;
  recipient: string;
}

interface PrepareSwapResult {
  steps: {
    type: 'reset-approval' | 'approve' | 'swap';
    description: string;
    transaction: { to: string; data: string; value: string };
  }[];
  summary: {
    tokenIn: string;
    tokenOut: string;
    amountIn: string;
    amountInRaw: string;
  };
}

interface YieldEstimate {
  earning: string;
  decimals: number;
  rate: { apy: number };
  dailyYield: string;
  monthlyYield: string;
  annualYield: string;
}

interface Webhook {
  id: number;
  url: string;
  events: string[];
  wallets: string[] | null;
  secret: string;
  createdAt: string;
}

interface WebhookListItem {
  id: number;
  url: string;
  events: string[];
  wallets: string[] | null;
  createdAt: string;
}

// Usage
const client = new CaminoTreasuryClient('your-api-key');

const { data: wallets } = await client.listWallets();
const { data: balances } = await client.getBalances(43114, wallets[0].address);

const { data: transactions, pagination } = await client.listTransactions(43114, {
  limit: 10,
  status: 'confirmed'
});

// Paginate
if (pagination.hasMore && pagination.nextCursor) {
  const page2 = await client.listTransactions(43114, {
    cursor: pagination.nextCursor
  });
}

Error Handling

Always handle errors appropriately:
try {
  const response = await fetch('https://api.caminotreasury.com/v1/wallets', {
    headers: { 'x-api-key': 'your-api-key' }
  });

  if (!response.ok) {
    const error = await response.json();

    switch (response.status) {
      case 401:
        // Invalid or expired API key
        console.error('Authentication failed');
        break;
      case 429:
        // Rate limited - check Retry-After header
        const retryAfter = response.headers.get('Retry-After');
        console.error(`Rate limited. Retry after ${retryAfter}s`);
        break;
      default:
        console.error('API error:', error);
    }
    return;
  }

  const { data: wallets } = await response.json();
} catch (error) {
  console.error('Network error:', error);
}

Best Practices

Define interfaces for your API responses to catch errors at compile time. See the complete integration example above for the full type definitions.
The API enforces 100 requests per 60-second window. Implement retry logic with exponential backoff using the Retry-After header for production applications.
Transaction listing uses cursor-based pagination. Always check pagination.hasMore and pass pagination.nextCursor to fetch subsequent pages.
Always validate user input before sending to the API. Ethereum addresses must match the pattern 0x[a-fA-F0-9]{40} and transaction hashes must match 0x[a-fA-F0-9]{64}.
When using deposit/prepare or withdraw/prepare, the returned steps must be signed and submitted in order. Each step may depend on the previous one (e.g. approval before swap).

Next Steps