> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daimo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Integration

> Build your own deposit UI with the API

Use the Daimo API directly to build a custom deposit experience. This works with any language or framework, no React required.

## Overview

The deposit flow has four steps:

1. **Create a session**: server-side, with your API key
2. **Choose a payment method**: client-side, with the client secret
3. **Wait for deposit**: show the deposit address, poll for status
4. **Handle completion**: process the result

## Step 1: Create a session

Create a session on your server. Never expose your API key to the client.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.daimo.com/v1/sessions \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "destination": {
        "type": "evm",
        "address": "0xYourAddress",
        "chainId": 8453,
        "tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "amountUnits": "10.00"
      },
      "display": {
        "title": "Deposit to Acme",
        "verb": "Deposit",
        "paymentOptions": ["AllFiat"]
      }
    }'
  ```

  ```typescript fetch theme={null}
  const response = await fetch("https://api.daimo.com/v1/sessions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.DAIMO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      destination: {
        type: "evm",
        address: "0xYourAddress",
        chainId: 8453,
        tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        amountUnits: "10.00",
      },
      display: {
        title: "Deposit to Acme",
        verb: "Deposit",
        paymentOptions: ["AllFiat"],
      },
    }),
  });

  const { session } = await response.json();
  ```
</CodeGroup>

To deliver to **Solana** (USDC only), use a Solana destination instead: set `type` to `"solana"`, use a base58 wallet `address` and the USDC mint as `tokenAddress`, and omit `chainId` and `calldata`. Everything else — payment methods, polling, webhooks — is identical.

```json theme={null}
"destination": {
  "type": "solana",
  "address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
  "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "amountUnits": "10.00"
}
```

Pass `session.clientSecret` and `session.sessionId` to your client.

## Step 2: Choose a payment method

On the client, call the payment methods endpoint. This transitions the session from `requires_payment_method` to `waiting_payment`.

**EVM deposit** (any EVM chain):

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.daimo.com/v1/sessions/{sessionId}/paymentMethods \
    -H "Content-Type: application/json" \
    -d '{
      "clientSecret": "SESSION_CLIENT_SECRET",
      "paymentMethod": { "type": "evm" }
    }'
  ```

  ```typescript SDK theme={null}
  import { createDaimoClient } from "@daimo/sdk/client";

  const daimo = createDaimoClient({ baseUrl: "https://api.daimo.com" });

  const result = await daimo.sessions.paymentMethods.create(sessionId, {
    clientSecret: "SESSION_CLIENT_SECRET",
    paymentMethod: { type: "evm" },
  });
  ```
</CodeGroup>

The response includes a `receiverAddress` in `result.session.paymentMethod`. Display this EVM address to the user - they send tokens to it from any supported chain.

```json theme={null}
{
  "session": {
    "status": "waiting_payment",
    "paymentMethod": {
      "type": "evm",
      "receiverAddress": "0x1a2B3c4D5e6F...",
      "createdAt": 1700000000
    }
  }
}
```

**Tron USDT deposit:**

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.daimo.com/v1/sessions/{sessionId}/paymentMethods \
    -H "Content-Type: application/json" \
    -d '{
      "clientSecret": "SESSION_CLIENT_SECRET",
      "paymentMethod": { "type": "tron", "amountUsd": 10.0 }
    }'
  ```

  ```typescript SDK theme={null}
  const result = await daimo.sessions.paymentMethods.create(sessionId, {
    clientSecret: "SESSION_CLIENT_SECRET",
    paymentMethod: { type: "tron", amountUsd: 10.0 },
  });
  ```
</CodeGroup>

The response includes a `tron.receiverAddress` in `result.session.paymentMethod`, a temporary Tron address. Display it to the user so they can send USDT to it. If `result.tron.deeplinks.trustWallet` is present, you can open that URL to send the same amount from Trust Wallet's USDT on Tron flow.

```json theme={null}
{
  "session": {
    "status": "waiting_payment",
    "paymentMethod": {
      "type": "tron",
      "receiverAddress": "TXyz1234...",
      "createdAt": 1700000000
    }
  }
}
```

**Solana deposit:**

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.daimo.com/v1/sessions/{sessionId}/paymentMethods \
    -H "Content-Type: application/json" \
    -d '{
      "clientSecret": "SESSION_CLIENT_SECRET",
      "paymentMethod": {
        "type": "solana",
        "walletAddress": "So1ana...",
        "inputTokenMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "amountUsd": 10.0
      }
    }'
  ```

  ```typescript SDK theme={null}
  const result = await daimo.sessions.paymentMethods.create(sessionId, {
    clientSecret: "SESSION_CLIENT_SECRET",
    paymentMethod: {
      type: "solana",
      walletAddress: "So1ana...",
      inputTokenMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      amountUsd: 10.0,
    },
  });
  ```
</CodeGroup>

The response includes `solana.serializedTx`, a hex-encoded serialized Solana transaction for the user's wallet to sign and submit.

This preserves a one-click wallet experience on Solana: swap, transfer, or bridge actions are bundled into one signed transaction. Unlike EVM and Tron, there is no `receiverAddress` for `type: "solana"`.

```json theme={null}
{
  "session": {
    "status": "waiting_payment",
    "paymentMethod": {
      "type": "solana",
      "createdAt": 1700000000
    }
  },
  "solana": {
    "serializedTx": "0xabc123..."
  }
}
```

**Fiat:**

The user pays in local currency via one of the fiat rails your org has enabled (e.g. Interac in Canada, ACH or Apple Pay in the US, or SEPA in Europe). Daimo hosts the payment and identity-verification flow at `fiat.hostedUrl`; open it in a [WebView](/guides/webview) or new browser tab. The session progresses through `waiting_payment` → `processing` → `succeeded` like any other payment method, and Daimo delivers the stablecoin to your destination once the fiat transfer settles.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.daimo.com/v1/sessions/{sessionId}/paymentMethods \
    -H "Content-Type: application/json" \
    -d '{
      "clientSecret": "SESSION_CLIENT_SECRET",
      "paymentMethod": { "type": "fiat", "fiatMethod": "interac" }
    }'
  ```

  ```typescript SDK theme={null}
  const result = await daimo.sessions.paymentMethods.create(sessionId, {
    clientSecret: "SESSION_CLIENT_SECRET",
    paymentMethod: { type: "fiat", fiatMethod: "interac" },
  });
  ```
</CodeGroup>

Pass `paymentMethod.fiatMethod` (one of `interac`, `ach`, `sepa`, `apple_pay`) to pin the hosted flow to one rail. If omitted, the hosted page shows every fiat method enabled for the org.

```json theme={null}
{
  "session": {
    "status": "waiting_payment",
    "paymentMethod": {
      "type": "fiat",
      "fiatMethod": "interac",
      "createdAt": 1700000000
    }
  },
  "fiat": {
    "hostedUrl": "https://daimo.com/webview?session=...&cs=...",
    "fiatMethod": "interac"
  }
}
```

The `hostedUrl` is returned only once from the `createPaymentMethod` call — store it on the client. It is not included when retrieving the session later. See the [WebView guide](/guides/webview) for how to load the hosted URL in iOS, Android, and React Native.

<Info>
  Fiat rails are enabled per-org. To request access, [contact
  us](mailto:support@daimo.com).
</Info>

## Step 3: Wait for session completion

Poll for status updates to the session after the user has paid.

<CodeGroup>
  ```bash curl theme={null}
  curl -X PUT https://api.daimo.com/v1/sessions/{sessionId}/check \
    -H "Content-Type: application/json" \
    -d '{ "clientSecret": "SESSION_CLIENT_SECRET" }'
  ```

  ```typescript SDK theme={null}
  const { session } = await daimo.sessions.check(sessionId, {
    clientSecret: "SESSION_CLIENT_SECRET",
  });

  console.log(session.status); // "waiting_payment", "processing", "succeeded"
  ```
</CodeGroup>

If you know the user's transaction hash, pass it as `txHash` to speed up detection.

## Step 4: Handle completion

Check for terminal statuses:

* `succeeded` - funds delivered
* `bounced` - delivery failed (e.g. contract call reverted). Funds returned to refund address.
* `expired` - session timed out

In the `succeeded` and `bounced` case, `destination.delivery.txHash` refers to the settlement transaction.
