Crypto payouts
Send crypto payouts with balance checks, fees, and status tracking.
Last updated
Was this helpful?
Send crypto payouts with balance checks, fees, and status tracking.
Last updated
Was this helpful?
Was this helpful?
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.