> For the complete documentation index, see [llms.txt](https://developers.coincircuit.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.coincircuit.io/promp-library/crypto-payouts.md).

# Crypto payouts

Send crypto payouts with balance checks, fees, and status tracking.

Use this prompt to build merchant-balance payout flows for creators, vendors, rewards, or other external disbursements.

`Payouts` `Balance` `Webhooks`

### What this prompt covers

* Check available balance before payouts
* Save recipient wallet addresses
* Estimate fees and track payout status from webhooks

{% code title="crypto-payouts.prompt.md" expandable="true" collapsedlinecount="20" %}

````markdown
You are helping me add crypto payouts to my existing application using CoinCircuit. I have the CoinCircuit MCP server connected.

**If you have access to the CoinCircuit MCP server, call these tools for the most accurate and detailed schema outputs:**
- Call `get_endpoint` with method `get` and path `/api/v1/balance` in the CoinCircuit MCP for the balance response schema.
- Call `get_endpoint` with method `post` and path `/api/v1/crypto-addresses` for the address creation schema.
- Call `get_endpoint` with method `get` and path `/api/v1/payouts/fees` for the fee estimation schema.
- Call `get_endpoint` with method `post` and path `/api/v1/payouts` for the payout creation schema.
- Call `get_schema` with name `PayoutSuccessWebhookDto` for the payout.success webhook payload.
- Call `get_schema` with name `PayoutFailedWebhookDto` for the payout.failed webhook payload.

Use the live MCP data as your source of truth. The details below are a guide, but if the MCP returns something different, trust the MCP.

## API Basics

- **Base URL:** `https://api.coincircuit.io`
- **Auth:** `x-api-key` header on every request.

## Project Context

I have an application that needs to pay users in crypto (USDT) from my CoinCircuit merchant balance to their wallet addresses. Use cases: vendor payments, creator payouts, rewards, or any disbursement to external wallets.

## What I Need You to Implement

### 1. Check merchant balance

**Endpoint:** `GET /api/v1/balance`
*(Call `get_endpoint` with method `get`, path `/api/v1/balance` in the CoinCircuit MCP for the full response schema.)*

**Query params:**
- `currency` (optional) - `"NGN"` or `"USDT"`. If omitted, returns your default currency balance.

**Response (200):**
```json
{
  "success": true,
  "data": {
    "currency": "USDT",
    "totalBalance": "1750.50",
    "availableBalance": "1500.50",
    "pendingBalance": "250.00",
    "merchant": {
      "id": "uuid",
      "businessName": "My Company",
      "email": "me@company.com",
      "status": "active"
    }
  }
}
```

- `availableBalance` - funds you can use right now for payouts
- `pendingBalance` - funds awaiting blockchain confirmation
- `totalBalance` - available + pending

Always check `availableBalance >= payoutAmount + estimatedFee` before creating a payout.

### 2. Save recipient crypto addresses

Before you can send a payout, the recipient wallet address must be saved.

**Endpoint:** `POST /api/v1/crypto-addresses`
*(Call `get_endpoint` with method `post`, path `/api/v1/crypto-addresses` in the CoinCircuit MCP for the full request/response schema.)*

**Required fields:**
- `chain` (string) - `"bitcoin"`, `"ethereum"`, `"solana"`, `"bsc"`, `"tron"`, `"base"`, or `"arbitrum"`
- `address` (string) - the wallet address

**Optional fields:**
- `label` (string) - friendly name, e.g. "Alice's BSC wallet"
- `isDefault` (boolean) - set as default for this chain

**Response (201):** Returns the saved address with an `id` (UUID). You'll use this `id` as the `recipientId` when creating payouts.

**Errors:** 400 if the address format is invalid or the address already exists for that chain.

### 3. Estimate payout fees

**Endpoint:** `GET /api/v1/payouts/fees`
*(Call `get_endpoint` with method `get`, path `/api/v1/payouts/fees` in the CoinCircuit MCP for the full response schema with all fee breakdowns.)*

**Query params:**
- `currency` (required) - `"USDT"` or `"NGN"`

**Response (200):**
```json
{
  "success": true,
  "data": {
    "currency": "USDT",
    "fiat": {
      "BankTransfer": "50.00"
    },
    "crypto": {
      "USDT": {
        "tron": "1.00",
        "bsc": "0.50"
      },
      "USDC": {
        "base": "0.30"
      }
    }
  }
}
```

Display the relevant chain fee before the user confirms. For example, a USDT payout on Tron costs 1.00 USDT in fees.

### 4. Create crypto payout

**Endpoint:** `POST /api/v1/payouts`
*(Call `get_endpoint` with method `post`, path `/api/v1/payouts`, section `request` in the CoinCircuit MCP for the exact request body with all field validations.)*

**Required fields:**
- `method` (string) - `"crypto"` (or `"fiat"` for bank transfers)
- `currency` (string) - `"USDT"` or `"NGN"`
- `amount` (string) - amount to send as a string, e.g. `"100.00"`
- `recipientId` (string, UUID) - the saved crypto address ID from step 2

**Optional fields:**
- `narration` (string) - description, e.g. "Creator payout - March"
- `reference` (string) - your unique idempotency reference. **Duplicate references are rejected.** If omitted, CoinCircuit generates one.

**Example request body:**
```json
{
  "method": "crypto",
  "currency": "USDT",
  "amount": "100.00",
  "recipientId": "addr_123456789_abcdef",
  "narration": "Creator payout - March 2026",
  "reference": "PAYOUT-MARCH-ALICE-001"
}
```

**Response (201):** Returns the payout object:
- `data.id` - payout UUID
- `data.status` - starts as `"pending"`, transitions to `"processing"`, `"success"`, or `"failed"`
- `data.amount` - amount the recipient gets
- `data.fee` - fee charged
- `data.total` - total debited from your balance (amount + fee)
- `data.currency` - `"USDT"`
- `data.reference` - your reference or auto-generated
- `data.txHash` - blockchain transaction hash (populated after success)
- `data.recipient` - object with `type: "cryptoAddress"`, `address`, `chain`, `asset`
- `data.conversion` - if cross-currency, includes `from`, `to`, `rate`, `convertedAmount`. Null if same currency.
- `data.failureReason` - populated if failed

*(Call `get_endpoint` with method `post`, path `/api/v1/payouts`, section `success` in the CoinCircuit MCP for the complete response schema.)*

**Errors:** 400 (validation error, insufficient balance, daily limit exceeded), 404 (recipient address not found)

### 5. Track payout status via webhooks

Payouts are async. The API returns immediately with `"pending"` status. Wait for webhooks:

*(Call `get_schema` with name `PayoutSuccessWebhookDto` in the CoinCircuit MCP for the full payout.success webhook payload. Call `get_schema` with name `PayoutFailedWebhookDto` for the failure payload.)*

**Payout events** (envelope: `{ event: string, data: { payout: PayoutObject } }`):
- `payout.created` - payout submitted and processing
- `payout.success` - funds delivered on-chain. `data.payout.txHash` has the transaction hash, `data.payout.completedAt` has the timestamp.
- `payout.failed` - payout failed. `data.payout.failureReason` explains why. Funds are returned to your balance.

## Constraints

- Always check balance before initiating payouts
- `amount` is a string (e.g. `"100.00"`)
- Duplicate `reference` values are rejected. Use unique references for idempotency.
- Crypto payouts support USDT (on Tron, BSC) and USDC (on Base).
- Payouts are async. Never assume success from the API response. Always wait for webhooks.
- Fiat payouts go only to the merchant's own bank account. Use crypto payouts for third-party disbursements.
````

{% endcode %}
