# CCPayment V2 API — Complete Reference

> **Source**: This document is a complete, structured reference compiled from the official CCPayment V2 API Documentation at https://ccpayment.com/api/doc. All information is faithful to the original source. The V1 API (docs.ccpayment.com) has been deprecated — always use the V2 API.

> **Base URL for all API endpoints**: `https://ccpayment.com/ccpayment/v2`

---

## Table of Contents

1. [Introduction](#1-introduction)
2. [Quick Guide — Credentials & Authentication](#2-quick-guide--credentials--authentication)
3. [Testnet](#3-testnet)
4. [Webhooks](#4-webhooks)
5. [Deposit APIs](#5-deposit-apis)
6. [Withdrawal APIs](#6-withdrawal-apis)
7. [Swap APIs](#7-swap-apis)
8. [Wallet System APIs (Create a Wallet System)](#8-wallet-system-apis)
9. [Common APIs](#9-common-apis)
10. [Support — FAQ](#10-support--faq)
11. [Status Codes & Error Codes](#11-status-codes--error-codes)
12. [Integration Flows (Quick Recipes)](#12-integration-flows)
13. [Best Practices](#13-best-practices)
14. [Links & Resources](#14-links--resources)

---

## 1. Introduction

CCPayment is a cryptocurrency payment platform allowing merchants to accept and pay out over 900+ cryptocurrencies across 100+ blockchain networks with the lowest fees in the industry (as low as 0.2%). It provides global payment solutions for industries such as gaming, e-commerce, and finance — with lightning-fast settlement, RSA encryption, and multi-layer risk control technologies.

**Core capabilities**:

- Accept crypto deposits (permanent addresses, order-based addresses, hosted invoice/checkout pages)
- Send crypto withdrawals to blockchain addresses or Cwallet accounts
- Swap between cryptocurrencies via API
- Build per-user wallet systems with independent balances, deposits, withdrawals, internal transfers, and swaps
- Real-time AML risk detection
- ETH Sepolia testnet for integration testing

**Compliance & Licenses**: Malta (EU) EMI, Malta VFA Class 4, UK API Payment, Australia Exchange, India Aggregated Payment, South Africa Exchange, USA MSB.

**Performance**: 90+ Countries | $20B+ Volume | 67K+ Partners | 99% Success Rate | ~1.8 min Avg Speed.

---

## 2. Quick Guide — Credentials & Authentication

### 2.1 How to Obtain Credentials

1. Go to the registration page of CCPayment and sign up using your email address: https://console.ccpayment.com
2. Log in and navigate to **Dashboard > Developer** to obtain your **"APP ID"** and **"APP Secret"**, which serve as your credentials to communicate with CCPayment.

Optionally, configure an IP whitelist at Dashboard > Developer for production security.

### 2.2 Rules for API Calls

| Rule | Description |
|------|-------------|
| Transfer Mode | HTTPS |
| Submit Mode | POST (may vary for different APIs) |
| Content-Type | Application/Json |
| Char Encoding | UTF-8 |
| Signature Algorithm | HmacSHA-256 (default) or RSA |

### 2.3 Signature Generation

All API calls require three custom headers:

| Header | Type | Required | Description |
|--------|------|----------|-------------|
| Appid | String | Yes | Your App ID from Dashboard > Developer |
| Timestamp | String | Yes | Current Unix timestamp in **seconds** (10-digit). Valid within 2 minutes. Example: `1677152720` |
| Sign | String | Yes | HMAC-SHA256 signature or RSA signature |

**HMAC Signature Algorithm (default)**:

```
Step 1: Prepare signText
  IF request body is non-empty:
    signText = {Appid} + {Timestamp} + {Payload in JSON format}
  ELSE:
    signText = {Appid} + {Timestamp}

Step 2: Compute signature
  sign = HMAC-SHA256(signText, appSecret).hexDigest()
```

The payload you sign must be exactly the same as the payload you send in the request.

**RSA Signature Algorithm (alternative)**:

```
Step 1: Prepare signText (same as HMAC)
  signText = {Appid} + {Timestamp} + {Payload in JSON format}

Step 2: Hash the signText using SHA-256

Step 3: Sign the hashed data with your RSA private key

Step 4: Convert the signature into a Base64-encoded string
```

**Before signing, ensure**:
- Your APP ID and APP Secret are correctly obtained from the dashboard
- Your merchant account is verified on the dashboard

### 2.4 Authentication Code Examples

**Node.js**:
```javascript
const crypto = require("crypto");

const appId = "YOUR_APP_ID";
const appSecret = "YOUR_APP_SECRET";

function callCCPaymentAPI(apiUrl, body = null) {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const bodyStr = body ? JSON.stringify(body) : "";

  let signText = appId + timestamp;
  if (bodyStr) signText += bodyStr;

  const sign = crypto
    .createHmac("sha256", appSecret)
    .update(signText)
    .digest("hex");

  const headers = {
    "Content-Type": "application/json",
    Appid: appId,
    Sign: sign,
    Timestamp: timestamp,
  };

  // Use your preferred HTTP client (axios, fetch, etc.)
  // POST to apiUrl with headers and bodyStr
}
```

**Python**:
```python
import hmac, hashlib, json, time, requests

APP_ID = "YOUR_APP_ID"
APP_SECRET = "YOUR_APP_SECRET"

def call_ccpayment_api(url, body=None):
    timestamp = str(int(time.time()))
    body_str = json.dumps(body) if body else ""

    sign_text = APP_ID + timestamp
    if body_str:
        sign_text += body_str

    sign = hmac.new(
        APP_SECRET.encode(), sign_text.encode(), hashlib.sha256
    ).hexdigest()

    headers = {
        "Content-Type": "application/json",
        "Appid": APP_ID,
        "Sign": sign,
        "Timestamp": timestamp,
    }

    resp = requests.post(url, headers=headers, data=body_str)
    return resp.json()
```

**Go**:
```go
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "strconv"
    "time"
)

func generateSign(appId, appSecret, bodyStr string) (string, string) {
    timestamp := strconv.FormatInt(time.Now().Unix(), 10)
    signText := appId + timestamp
    if bodyStr != "" {
        signText += bodyStr
    }
    mac := hmac.New(sha256.New, []byte(appSecret))
    mac.Write([]byte(signText))
    sign := hex.EncodeToString(mac.Sum(nil))
    return sign, timestamp
}
```

**PHP**:
```php
$appId = 'YOUR_APP_ID';
$appSecret = 'YOUR_APP_SECRET';
$timestamp = time();
$bodyStr = json_encode($body);

$signText = $appId . $timestamp;
if ($bodyStr) {
    $signText .= $bodyStr;
}

$sign = hash_hmac('sha256', $signText, $appSecret);

$headers = [
    'Content-Type: application/json',
    'Appid: ' . $appId,
    'Sign: ' . $sign,
    'Timestamp: ' . $timestamp,
];
```

**Java**:
```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

String appId = "YOUR_APP_ID";
String appSecret = "YOUR_APP_SECRET";
long timestamp = System.currentTimeMillis() / 1000;
String bodyStr = new ObjectMapper().writeValueAsString(body);

String signText = appId + timestamp;
if (bodyStr != null && !bodyStr.isEmpty()) {
    signText += bodyStr;
}

Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(appSecret.getBytes(), "HmacSHA256"));
byte[] hash = mac.doFinal(signText.getBytes());
String sign = bytesToHex(hash);
```

### 2.5 Request Limits

Check the specific API endpoint documentation for exact rate limit details. If you exceed the rate limit, you will receive error code `11004 (RateLimit)`. Implement exponential backoff when encountering this error.

---

## 3. Testnet

CCPayment supports testing on the ETH Sepolia testnet.

**How to enable**:
1. Go to Dashboard > Merchant Settings > ETH test network and turn it on.
2. Get free Sepolia ETH from faucets:
   - https://cloud.google.com/application/web3/faucet/ethereum/sepolia
   - https://sepolia-faucet.pk910.de
   - https://www.allthatnode.com/faucet/ethereum.dsrv
   - https://faucet.quicknode.com/drip
3. Verify transactions on the blockchain explorer: `https://sepolia.etherscan.io/`

**Important**: Testing Sepolia ETH has no real value. It is only for testing purposes. **Disable testnet when done** — switch back to mainnet before going live.

---

## 4. Webhooks

CCPayment notifies you of real-time transaction statuses by sending webhooks to your server. When your server receives a webhook, it can parse the payload and perform corresponding operations (e.g., updating order status, generating shipping notifications).

### 4.1 Webhook Setup

1. Configure tokens at **Dashboard > Settings > Tokens for your business**
2. Set your Webhook URL at **Dashboard > Developer > Webhook URL**
3. If your server has an IP whitelist, add these IPs: `54.150.123.157`, `35.72.150.75`, `18.176.186.244`

### 4.2 How to Handle Incoming Webhooks

**Step 1: Verify the Webhook Signature**

Always verify if the signature provided in the webhook matches the one you generate. The webhook request headers contain:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| Appid | String | Yes | Your CCPayment APP ID |
| Timestamp | String | Yes | 10-digit timestamp. Valid within 2 minutes |
| Sign | String | Yes | Signature to verify |

**HMAC Signature Verification**:
1. Use HMAC-SHA256 to generate the Sign value from the webhook payload (same algorithm as request signing).
2. Compare the generated sign value with the one sent in the request header.
3. If equal → verification success, proceed to handle the webhook. If not → verification failed, request may have been tampered with.

**RSA Signature Verification**:
1. Decode the Base64-encoded signature received in the request.
2. Use the RSA private key to decrypt the decoded signature.
3. The decrypted data should reveal a string composed of `{APP ID} + {Timestamp} + {Payload JSON object}`.
4. Compare the decrypted string with the expected concatenation. If match → success. If not → failed.

**Step 2: Parse the Payload**

**Step 3: Respond to CCPayment**

Your server **must** return HTTP 200 with the string `"Success"` in the response body. Otherwise, CCPayment will retry.

### 4.3 Retry Logic

If CCPayment does not receive HTTP 200 with "Success", it retries up to 6 times at these intervals:

| Retry | Interval |
|-------|----------|
| 1st | 30 seconds |
| 2nd | 1 minute 30 seconds |
| 3rd | 3 minutes 30 seconds |
| 4th | 7 minutes 30 seconds |
| 5th | 15 minutes 30 seconds |
| 6th | 31 minutes 30 seconds |

### 4.4 Idempotency (CRITICAL)

Merchants must implement idempotency to prevent multiple crediting for one payment. Always check `recordId` or `txId` before processing to prevent duplicate crediting:

```javascript
if (db.hasRecord(recordId)) {
  return res.status(200).send("Success"); // already processed
}
// process transaction, then save recordId to db
res.status(200).send("Success");
```

### 4.5 Webhook Types

| Type | Trigger |
|------|---------|
| `DirectDeposit` | Deposit to a permanent address |
| `ApiDeposit` | Deposit to an order-based address or invoice address |
| `ApiWithdrawal` | Merchant-level network withdrawal status change |
| `UserDeposit` | Deposit to a user wallet address |
| `UserWithdrawal` | User wallet network withdrawal status change |
| Risky Address | Address flagged as risky (special webhook) |

### 4.6 Transaction Statuses in Webhooks

| Status | Meaning |
|--------|---------|
| `Processing` | Blockchain is processing the transaction |
| `Success` | Transaction confirmed |
| `Failed` | Transaction failed |
| `WaitingApproval` | Withdrawal pending manual approval (if merchant enabled) |
| `Rejected` | Withdrawal rejected by merchant |

### 4.7 Risky Transactions

If `isFlaggedAsRisky` is `true`, funds are NOT auto-credited. Handle risky transactions at Dashboard > Transaction > Risky Transaction. **Never auto-credit risky transactions to users.**

### 4.8 Risky Address Webhook

When a deposit address is flagged as risky, CCPayment sends a special webhook:

| Parameter | Type | Description |
|-----------|------|-------------|
| chainId | String | Chain ID |
| address | String | The receiving address flagged as risky |
| riskAt | Integer | Timestamp when address was flagged |

Risky addresses are immediately disabled. Deposits to flagged addresses will not trigger automatic webhook notifications. You can manually send webhooks from the dashboard for those deposits.

### 4.9 Important Webhook Rule

**Webhooks are notifications only.** After receiving a webhook, always call the corresponding Get Record API to confirm the actual payment status. Do not treat webhook status as final — relying solely on webhooks may result in asset loss.

### 4.10 Webhook Payload Examples

**DirectDeposit**:
```json
{
  "type": "DirectDeposit",
  "msg": {
    "recordId": "20240313113108...",
    "referenceId": "user_12345",
    "coinId": 1329,
    "coinSymbol": "MATIC",
    "status": "Success",
    "isFlaggedAsRisky": false
  }
}
```

**ApiDeposit**:
```json
{
  "type": "ApiDeposit",
  "msg": {
    "recordId": "20240313121919...",
    "orderId": "order_001",
    "coinId": 1329,
    "coinSymbol": "POL",
    "status": "Success",
    "isFlaggedAsRisky": false
  }
}
```

**ApiWithdrawal**:
```json
{
  "type": "ApiWithdrawal",
  "msg": {
    "recordId": "20240313120722...",
    "orderId": "withdraw_001",
    "coinId": 1891,
    "coinSymbol": "TETH",
    "status": "Success"
  }
}
```

**UserDeposit**:
```json
{
  "type": "UserDeposit",
  "msg": {
    "recordId": "20240313093815...",
    "userId": "user_12345",
    "coinId": 1329,
    "coinSymbol": "MATIC",
    "amount": "0.1",
    "status": "Success",
    "isFlaggedAsRisky": false
  }
}
```

**UserWithdrawal**:
```json
{
  "type": "UserWithdrawal",
  "msg": {
    "recordId": "20240313120733...",
    "orderId": "user_wd_001",
    "userId": "user_12345",
    "coinId": 1891,
    "coinSymbol": "TETH",
    "status": "Success"
  }
}
```

### 4.11 View Webhook Logs and Resend Webhooks

View webhook notification logs and manually resend webhooks from: **Dashboard > Webhook**

### 4.12 Resend Webhook API

**Use case**: Resend failed or all webhooks for transactions within a time range.

**POST** `https://ccpayment.com/ccpayment/v2/webhook/resend`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordIds | Array[String] | No | Specific record IDs to resend (max 50 per batch) |
| startTimestamp | Integer | Yes | 10-digit start timestamp. Resend webhooks for all transactions created after this time |
| endTimestamp | Integer | No | 10-digit end timestamp (max 1 hour after start) |
| webhookResult | String | No | `Failed` (default — resend only failed) or `AllResult` (resend all) |
| transactionType | String | No | `AllType` (default), `ApiDeposit`, `DirectDeposit`, `ApiWithdrawal`, `UserDeposit`, `UserWithdrawal` |

**Response**:
```json
{
  "code": 10000,
  "msg": "Success",
  "data": { "resendCount": 1 }
}
```

---

## 5. Deposit APIs

### Which deposit type should I use?

| Use Case | Deposit Type | API |
|----------|-------------|-----|
| E-commerce / fixed-price orders, merchant specifies coin | Order-based (merchant-specified) | Create Deposit Order |
| E-commerce, customer picks coin on checkout page | Order-based (customer-selected) | Create Invoice Deposit |
| Gaming / streaming / social — user-linked deposits | Permanent address | Get Permanent Deposit Address |
| Building a wallet system with per-user accounts | User deposit | Create/Get User Deposit Address (see Section 8) |

---

### 5.1 Get Permanent Deposit Address

Assign persistent deposit addresses to users. Ideal for gaming, streaming, social platforms where deposits are linked to users, not orders.

**POST** `https://ccpayment.com/ccpayment/v2/getOrCreateAppDepositAddress`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| referenceId | String | Yes | 3–64 characters. Unique reference ID for the user in your system |
| chain | String | Yes | Chain symbol (e.g., `TRX`, `POLYGON`, `BSC`, `ETH`). Get from Get Token Information API |

**Address Handling Rules**:
- **Existing Address**: If a permanent address is already linked to the `referenceId + chain` combo, CCPayment returns the existing address.
- **New Address**: If no address is linked, CCPayment generates a new permanent deposit address.
- Max 1000 addresses per App ID. Contact customer service for higher limits.
- The address is permanent — the user can reuse it indefinitely.

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.address | String | The permanent deposit address |
| data.memo | String | For memo-required coins (XRP, XLM, TON, etc.), the payer must fill in the correct memo |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "address": "TAkmn3f8bgwMAwdVrGfUVSRg4W2XwqgHGc",
    "memo": ""
  }
}
```

**Webhook**: `DirectDeposit` — then call Get Deposit Record to confirm.

---

### 5.2 Create Deposit Order (Merchant-Specified Currency)

E-commerce with fixed-price orders where you specify which coin and chain the customer pays with.

**POST** `https://ccpayment.com/ccpayment/v2/createAppOrderDepositAddress`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | Yes | Coin ID of the payment coin (get from Get Token List) |
| chain | String | Yes | Symbol of the chain |
| price | String | Yes | Product price. If `fiatId` is set: fiat price (up to 2 decimal places). If `fiatId` is empty: crypto amount (up to 18 decimal places) |
| orderId | String | Yes | Your order ID, 3–64 characters, must be unique |
| fiatId | Integer | No | Fiat currency ID (get from Get Fiat List). If set, price is in fiat and auto-converted to crypto |
| expiredAt | Integer | No | 10-digit expiration timestamp. Default up to 10 days max. The rate will be locked before expiration |
| buyerEmail | String | No | Customer email for CCPayment payment notifications |
| generateCheckoutURL | Boolean | No | `true` = generate hosted checkout page URL; `false` (default) |
| product | String | No | Product name on checkout page (max 120 chars). Only when checkout URL enabled |
| returnUrl | String | No | Redirect URL after payment. Only when checkout URL enabled |
| closeUrl | String | No | Redirect URL when buyer clicks "leave page". Only when checkout URL enabled |

**Rules**:
- `expiredAt` tip: For volatile crypto markets, use a short expiration to prevent rate loss.
- After expiration, deposits to the address are still received for 7 days (labeled "Overdue").
- The exchange rate is locked from order creation until expiration.

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.address | String | Deposit address |
| data.amount | String | Crypto amount the customer needs to pay |
| data.memo | String | Memo for memo-required chains |
| data.checkoutUrl | String | Hosted checkout page URL (only if `generateCheckoutURL: true`) |
| data.confirmsNeeded | Integer | Block confirmations required |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "address": "0x9aBDDCE1EE18D1857C0653EB4a3Fa9d9E0dcd584",
    "amount": "10.008552",
    "memo": "",
    "checkoutUrl": "https://i.ccpayment.com/xxx",
    "confirmsNeeded": 50
  }
}
```

**Webhook**: `ApiDeposit` — then call Get Order Information to confirm.

---

### 5.3 Create Invoice Deposit (Customer-Selected Currency)

Create a checkout page where the customer selects which cryptocurrency to pay with from your configured token list.

**POST** `https://ccpayment.com/ccpayment/v2/createInvoiceUrl`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| orderId | String | Yes | Your order ID, 3–64 characters |
| price | String | Yes | Product price (fiat or crypto depending on which ID is passed) |
| priceFiatId | String | No | Fiat ID for the denominating currency (get from Get Fiat List) |
| priceCoinId | String | No | Coin ID for the denominating currency (get from Get Token List) |
| product | String | No | Product name on checkout page (max 120 chars) |
| returnUrl | String | No | Redirect URL after payment |
| closeUrl | String | No | Redirect URL when buyer clicks "leave page" |
| expiredAt | Integer | No | 10-digit expiration timestamp. Default 24 hours |
| buyerEmail | String | No | Customer email for notifications |

**Rules**:
- Pass **either** `priceFiatId` **or** `priceCoinId`, **not both**.
- Customers can pay with any coin from your "Tokens for your business" list.

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.invoiceUrl | String | Redirect customer to this URL to pay |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "invoiceUrl": "https://i.ccpayment.com/xxx"
  }
}
```

**Webhook**: `ApiDeposit` — then call Get Invoice Order Information to confirm.

---

### 5.4 Get Order Information (Merchant-Specified Currency Orders)

After receiving an `ApiDeposit` webhook for a merchant-specified order, confirm order status and all payment details.

**POST** `https://ccpayment.com/ccpayment/v2/getAppOrderInfo`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| orderId | String | Yes | Your order ID, 3–64 characters |

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.amountToPay | String | Total crypto amount to pay |
| data.coinId | Integer | Order payment coin ID |
| data.coinSymbol | String | Order payment coin symbol |
| data.chain | String | Chain symbol |
| data.toAddress | String | Deposit address |
| data.toMemo | String | Memo for memo-required chains |
| data.rate | String | Locked rate (fiat/crypto). Rate changes if paid after expiration |
| data.fiatId | Integer | Fiat ID (if fiat-priced order) |
| data.fiatSymbol | String | Fiat symbol |
| data.createAt | Integer | Order creation timestamp |
| data.expiredAt | Integer | Order expiration timestamp |
| data.checkoutUrl | String | Checkout URL if created |
| data.paidList | Array | All payments for this order |
| data.paidList[].recordId | String | CCPayment unique transaction ID |
| data.paidList[].fromAddress | String | Sender address (empty for UTXO type) |
| data.paidList[].amount | String | Received amount |
| data.paidList[].serviceFee | String | Service fee |
| data.paidList[].txid | String | On-chain transaction hash |
| data.paidList[].status | String | `Success`, `Processing`, `Failed` |
| data.paidList[].isFlaggedAsRisky | Boolean | Risky transaction flag |
| data.paidList[].arrivedAt | Integer | Deposit arrival timestamp |
| data.paidList[].rate | String | Rate at time of receipt |

**Best Practice**: Compare total paid amount vs `amountToPay` to determine: fully paid, partially paid, overpaid, or overdue.

---

### 5.5 Get Invoice Order Information (Customer-Selected Currency Orders)

Retrieve invoice order information and all deposit records associated with the provided Order ID.

**POST** `https://ccpayment.com/ccpayment/v2/getInvoiceOrderInfo`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| orderId | String | Yes | 3–64 characters. Unique ID for the order |

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.orderId | String | Order ID created by merchant |
| data.createAt | Integer | Order creation timestamp |
| data.product | String | Product name |
| data.price | String | Order price |
| data.priceFiatId | Integer | Fiat ID for denominating currency |
| data.priceSymbol | String | Price symbol |
| data.invoiceUrl | String | Invoice checkout URL |
| data.expiredAt | Integer | Order expiration timestamp |
| data.totalPaidValue | String | Total paid in denominating currency |
| data.paidList | Array | All payments for this order |
| data.paidList[].recordId | String | CCPayment unique transaction ID |
| data.paidList[].coinId | Integer | Payment coin ID |
| data.paidList[].coinSymbol | String | Payment coin symbol |
| data.paidList[].chain | String | Chain symbol |
| data.paidList[].fromAddress | String | Sender address |
| data.paidList[].toAddress | String | Receiving address |
| data.paidList[].paidAmount | String | Crypto amount paid |
| data.paidList[].serviceFee | String | Service fee |
| data.paidList[].rate | String | Rate: payment coin USD value / denominating currency USD value |
| data.paidList[].paidValue | String | Paid amount in denominating currency (paidAmount × rate) |
| data.paidList[].txid | String | On-chain transaction hash |
| data.paidList[].status | String | `Success`, `Processing`, `Failed` |
| data.paidList[].isFlaggedAsRisky | Boolean | Risk flag |
| data.paidList[].arrivedAt | Integer | Arrival timestamp |

---

### 5.6 Address Unbinding

Unbind a deposit address from a user/referenceId, typically when the address is flagged as risky.

**POST** `https://ccpayment.com/ccpayment/v2/addressUnbinding`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| chain | String | Yes | Chain symbol of the address |
| address | String | Yes | Address to unbind |

**Rules**:
- If the address is on an EVM-compatible chain (ETH, BSC, Polygon), corresponding addresses on other EVM chains are also auto-unbound.
- After unbinding, payments to the old address are still credited to your merchant account.
- Call Get Permanent Deposit Address again to get a new address for the same user.

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "unbound": [
      { "chain": "POLYGON", "address": "0xa9a363..." }
    ],
    "unboundAt": 1741783734,
    "userID": "",
    "referenceID": "user_12345"
  }
}
```

---

### 5.7 Get Deposit Record

Get full details of a specific deposit transaction by its record ID. Essential for confirming transaction status after webhook.

**POST** `https://ccpayment.com/ccpayment/v2/getAppDepositRecord`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordId | String | Yes | CCPayment unique transaction ID (from webhook) |

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.record.recordId | String | CCPayment unique transaction ID |
| data.record.coinId | Integer | Deposit coin ID |
| data.record.coinSymbol | String | Deposit coin symbol |
| data.record.chain | String | Chain symbol |
| data.record.contract | String | Token contract address |
| data.record.coinUSDPrice | String | Coin USD price at receipt time |
| data.record.fromAddress | String | Sender address (empty for UTXO type) |
| data.record.toAddress | String | Receiving address |
| data.record.toMemo | String | Memo |
| data.record.amount | String | Received amount |
| data.record.serviceFee | String | Service fee charged |
| data.record.txId | String | On-chain transaction hash |
| data.record.status | String | `Success`, `Processing`, `Failed` |
| data.record.isFlaggedAsRisky | Boolean | Risk flag |
| data.record.arrivedAt | Integer | Arrival timestamp |
| data.record.referenceId | String | Your reference ID (if applicable) |
| data.record.orderId | String | Your order ID (if applicable) |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "record": {
      "recordId": "20250116073333231508600365121536",
      "orderId": "1737011983",
      "coinId": 1482,
      "coinSymbol": "TRX",
      "chain": "TRX",
      "contract": "TRX",
      "coinUSDPrice": "0.23717",
      "fromAddress": "TRPKg7eGMy9aZS2RumSPeWoyVkDqTVwLgL",
      "toAddress": "TAkmn3f8bgwMAwdVrGfUVSRg4W2XwqgHGc",
      "toMemo": "",
      "amount": "0.5",
      "serviceFee": "0.0025",
      "txId": "f39abf3275607fe2...",
      "status": "Success",
      "arrivedAt": 1737012813,
      "isFlaggedAsRisky": false,
      "referenceId": "user_12345"
    }
  }
}
```

---

### 5.8 Get Deposit Record List

Query multiple deposit records with filters.

**POST** `https://ccpayment.com/ccpayment/v2/getAppDepositRecordList`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | No | Filter by coin ID |
| referenceId | String | No | Filter by reference ID (3–64 chars) |
| orderId | String | No | Filter by order ID. Do not pass both `orderId` and `referenceId` |
| chain | String | No | Filter by chain symbol |
| startAt | Integer | No | 10-digit start timestamp |
| endAt | Integer | No | 10-digit end timestamp |
| nextId | String | No | Pagination cursor |

**Pagination**: Results return max 20 records. If more exist, `data.nextId` is returned — pass it in the next request with the same filters.

**Response**: Same fields as Get Deposit Record but returns `data.records[]` array and `data.nextId`.

---

## 6. Withdrawal APIs

### 6.1 Create Network Withdrawal Order

Send crypto from your merchant balance to any blockchain address.

**POST** `https://ccpayment.com/ccpayment/v2/applyAppWithdrawToNetwork`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | Yes | Coin ID |
| chain | String | Yes | Chain symbol |
| address | String | Yes | Destination blockchain address |
| memo | String | No | Memo for memo-required chains (XRP, XLM, TON) |
| orderId | String | Yes | Your withdrawal order ID, 3–64 characters |
| amount | String | Yes | Withdrawal amount |
| merchantPayNetworkFee | Boolean | No | `true`: merchant pays fee (recipient gets full amount). `false` (default): fee deducted from amount |

**Pre-withdrawal checklist**:
1. Check balance with Get Balance List
2. Validate address with Check Withdrawal Address Validity
3. Check network fee with Get Withdrawal Network Fee

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "recordId": "202403120909501767478092588126208"
  }
}
```

**Webhook**: `ApiWithdrawal` with statuses: `Processing` → `Success` (or `Failed`). If manual approval enabled: `WaitingApproval` → `Processing` → `Success`.

**Important**: In rare cases of network jitter, you may not receive a response. Call Get Withdrawal Record to confirm status. If no webhook after 2 hours, proactively call Get Withdrawal Record.

---

### 6.2 Withdrawal to Cwallet Account

Instant transfer to a Cwallet user. Zero network fee.

**POST** `https://ccpayment.com/ccpayment/v2/applyAppWithdrawToCwallet`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | Yes | Coin ID |
| cwalletUser | String | Yes | Cwallet ID or email address |
| amount | String | Yes | Amount (min 0.001 USD equivalent) |
| orderId | String | Yes | Your order ID, 3–64 characters |

**Rules**:
- **No webhook** for Cwallet transfers — call Get Withdrawal Record to confirm.
- Validate Cwallet user with Get Cwallet User Information first.

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "recordId": "202403120913091767478929213362176"
  }
}
```

---

### 6.3 Get Withdrawal Record

Confirm withdrawal status and details.

**POST** `https://ccpayment.com/ccpayment/v2/getAppWithdrawRecord`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordId | String | No | CCPayment transaction ID |
| orderId | String | No | Your order ID |

**Rules**: Pass either `recordId` or `orderId`, not both empty.

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.record.recordId | String | CCPayment unique transaction ID |
| data.record.withdrawType | String | `Network` or `Cwallet` |
| data.record.coinId | Integer | Coin ID |
| data.record.coinSymbol | String | Coin symbol |
| data.record.chain | String | Chain symbol |
| data.record.fromAddress | String | From address |
| data.record.toAddress | String | Destination address (blockchain withdrawals) |
| data.record.cwalletUser | String | Cwallet user ID (Cwallet withdrawals only) |
| data.record.toMemo | String | Memo (blockchain withdrawals) |
| data.record.txId | String | On-chain hash (network withdrawals only) |
| data.record.orderId | String | Your order ID |
| data.record.status | String | `Processing`, `Success`, `Failed`, `WaitingApproval`, `Rejected` |
| data.record.amount | String | Withdrawal amount |
| data.record.fee | Object | Network fee details (network withdrawals only) |
| data.record.fee.coinId | Integer | Fee coin ID |
| data.record.fee.coinSymbol | String | Fee coin symbol |
| data.record.fee.amount | String | Fee amount |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "record": {
      "recordId": "202403120909501767478092588126208",
      "withdrawType": "Network",
      "coinId": 1891,
      "coinSymbol": "TETH",
      "chain": "POLYGON",
      "fromAddress": "0x1AE2828c...",
      "toAddress": "0xBb9C4e7F...",
      "orderId": "1710234589577",
      "txId": "0xb55bb282...",
      "toMemo": "",
      "status": "Success",
      "amount": "0.004",
      "fee": {
        "coinId": 1891,
        "coinSymbol": "TETH",
        "amount": "0.001"
      }
    }
  }
}
```

---

### 6.4 Get Withdrawal Record List

**POST** `https://ccpayment.com/ccpayment/v2/getAppWithdrawRecordList`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | No | Filter by coin |
| orderIds | Array[String] | No | Filter by order IDs (max 20) |
| chain | String | No | Filter by chain |
| startAt | Integer | No | 10-digit start timestamp |
| endAt | Integer | No | 10-digit end timestamp |
| nextId | String | No | Pagination cursor |

**Pagination**: Max 20 records per page. Use `nextId` for next page.

---

## 7. Swap APIs

### 7.1 Get Swap Quote

Preview swap output before executing. This endpoint is shared for both merchant-level and user-level swap quotes.

**POST** `https://ccpayment.com/ccpayment/v2/estimate`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinIdIn | Integer | Yes | Input coin ID |
| amountIn | String | Yes | Input amount |
| coinIdOut | Integer | Yes | Output coin ID |
| extraFeeRate | String | No | **User swap only.** Percentage rate you want to charge as your service fee. E.g., `"0.01"` = 1%. Charged from user's output |

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.coinIdIn | Integer | Input coin ID |
| data.coinIdOut | Integer | Output coin ID |
| data.amountOut | String | Gross output amount |
| data.netAmountOut | String | Net output. For merchant: `amountOut - fee`. For user: `amountOut - fee - extraFee` |
| data.amountIn | String | Input amount |
| data.swapRate | String | `amountIn / amountOut` |
| data.feeRate | String | CCPayment service fee rate |
| data.fee | String | Fee amount (`feeRate × amountOut`). Minimum 0.1 USDT equivalent |
| data.extraFee | String | Extra fee amount (user swap only, `extraFeeRate × amountOut`) |
| data.extraFeeRate | String | Extra fee rate (user swap only) |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "coinIdIn": 1280,
    "coinIdOut": 1329,
    "amountOut": "194.09158706508187",
    "amountIn": "100",
    "swapRate": "1.9409158706508187",
    "feeRate": "0.005",
    "fee": "0.97045793532540935",
    "netAmountOut": "193.12112912975646065"
  }
}
```

---

### 7.2 Create Swap Order (Merchant-Level)

Execute a swap between two cryptocurrencies from merchant balance.

**POST** `https://ccpayment.com/ccpayment/v2/swap`

**Parameters**:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| orderId | String | Yes | Your swap order ID, 3–64 chars |
| coinIdIn | Integer | Yes | Input coin ID |
| amountIn | String | Yes | Input amount |
| coinIdOut | Integer | Yes | Output coin ID |
| amountOutMinimum | String | No | Slippage protection — swap fails if output < this value |

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.recordId | String | CCPayment unique transaction ID |
| data.orderId | String | Order ID |
| data.coinIdIn | Integer | Input coin ID |
| data.coinIdOut | Integer | Output coin ID |
| data.amountOut | String | Output amount |
| data.netAmountOut | String | Net output (`amountOut - fee`) |
| data.amountIn | String | Input amount |
| data.feeRate | String | Fee rate |
| data.fee | String | Fee amount. Minimum 0.1 USDT equivalent |
| data.swapRate | String | `amountIn / amountOut` |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "recordId": "20240719085639165937311982694400",
    "orderId": "swap_001",
    "coinIdIn": 1280,
    "coinIdOut": 1329,
    "amountOut": "1.9428459962937677",
    "amountIn": "1",
    "swapRate": "1.9428459962937677",
    "fee": "0.1950648590656393",
    "feeRate": "0.1004016064257028",
    "netAmountOut": "1.7477811372281284"
  }
}
```

---

### 7.3 Get Swap Record

**POST** `https://ccpayment.com/ccpayment/v2/getSwapRecord`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordId | String | No | CCPayment transaction ID |
| orderId | String | No | Your order ID |

**Rules**: Pass either `recordId` or `orderId`, not both.

---

### 7.4 Get Swap Record List

**POST** `https://ccpayment.com/ccpayment/v2/getSwapRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordIds | Array[String] | No | Filter by record IDs |
| orderIds | Array[String] | No | Filter by order IDs |
| coinIdIn | Integer | No | Filter by input coin |
| coinIdOut | Integer | No | Filter by output coin |
| startAt | Integer | No | 10-digit start timestamp |
| endAt | Integer | No | 10-digit end timestamp (max 3 months from startAt) |
| nextId | String | No | Pagination cursor |

---

## 8. Wallet System APIs

Build a wallet system where each user has an independent account with deposits, withdrawals, swaps, and internal transfers.

**User ID Rules**:
- String, 5–64 characters
- Cannot start with `"sys"`
- The merchant's own App ID is reserved as the merchant account user ID — do **not** assign it to users

---

### 8.1 User Balance

#### Get User Balance List

**POST** `https://ccpayment.com/ccpayment/v2/getUserCoinAssetList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID (5–64 chars, not starting with "sys") |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "userId": "user_12345",
    "assets": [
      { "coinId": 1280, "coinSymbol": "USDT", "available": "100.5" },
      { "coinId": 1482, "coinSymbol": "TRX", "available": "250.0" }
    ]
  }
}
```

#### Get Coin Balance of User

**POST** `https://ccpayment.com/ccpayment/v2/getUserCoinAsset`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID |
| coinId | Integer | Yes | Coin ID |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "userId": "user_12345",
    "asset": { "coinId": 1280, "coinSymbol": "USDT", "available": "100.5" }
  }
}
```

---

### 8.2 User Deposit

#### Create or Get User Deposit Address

**POST** `https://ccpayment.com/ccpayment/v2/getOrCreateUserDepositAddress`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID (5–64 chars). Note: The user ID for merchant accounts is APP ID. Do not assign APP ID to your users. |
| chain | String | Yes | Chain symbol |

**Rules**: Max 1000 user addresses per App ID.

**Response**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": { "address": "0x...", "memo": "" }
}
```

**Webhook**: `UserDeposit` — then call Get User Deposit Record to confirm.

#### Webhook for User Deposit

| Parameter | Type | Description |
|-----------|------|-------------|
| type | String | `UserDeposit` |
| msg.recordId | String | CCPayment unique transaction ID |
| msg.userId | String | User ID |
| msg.coinId | Integer | Coin ID |
| msg.coinSymbol | String | Coin symbol |
| msg.status | String | `Processing`, `Success`, `Failed` |
| msg.isFlaggedAsRisky | Boolean | Risk flag |

#### Get User Deposit Record

**POST** `https://ccpayment.com/ccpayment/v2/getUserDepositRecord`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordId | String | Yes | CCPayment transaction ID |

**Response**: Same structure as merchant Get Deposit Record, plus `data.record.userId`.

#### Get User Deposit Record List

**POST** `https://ccpayment.com/ccpayment/v2/getUserDepositRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID |
| coinId | Integer | No | Filter by coin |
| chain | String | No | Filter by chain |
| startAt | Integer | No | 10-digit timestamp |
| endAt | Integer | No | 10-digit timestamp |
| nextId | String | No | Pagination cursor |

---

### 8.3 User Withdrawal

#### User Withdrawal to Blockchain Address

**POST** `https://ccpayment.com/ccpayment/v2/applyUserWithdrawToNetwork`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID |
| coinId | Integer | Yes | Coin ID |
| chain | String | Yes | Chain symbol |
| address | String | Yes | Destination address |
| memo | String | No | Memo for memo-required chains |
| orderId | String | Yes | Your order ID, 3–64 chars |
| amount | String | Yes | Withdrawal amount |

**Webhook**: `UserWithdrawal` — then call Get User Withdrawal Record.

**Tip**: If no `Success` webhook after 2 hours, proactively call Get User Withdrawal Record.

#### User Withdrawal to Cwallet

**POST** `https://ccpayment.com/ccpayment/v2/applyUserWithdrawToCwallet`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID |
| coinId | Integer | Yes | Coin ID |
| cwalletUser | String | Yes | Cwallet ID or email |
| amount | String | Yes | Amount (min 0.001 USD equivalent) |
| orderId | String | Yes | Your order ID, 3–64 chars |

**No webhook** — call Get User Withdrawal Record to confirm.

#### Get User Withdrawal Record

**POST** `https://ccpayment.com/ccpayment/v2/getUserWithdrawRecord`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordId | String | No | CCPayment transaction ID |
| orderId | String | No | Your order ID |

**Rules**: Pass either `recordId` or `orderId`, not both empty.

**Response Parameters**: Same structure as merchant withdrawal record, plus `data.record.userId`, `data.record.cwalletUser` (for Cwallet withdrawals), `data.record.toAddress` and `data.record.toMemo` (for blockchain withdrawals), `data.record.txId` (for blockchain withdrawals).

| Parameter | Type | Description |
|-----------|------|-------------|
| data.record.status | String | `Processing`, `Success`, `Failed`, `WaitingApproval`, `Rejected` |
| data.record.fee | Object | Network fee. Only withdrawals to blockchain address have fee info |
| data.record.fee.coinId | Integer | Fee coin ID |
| data.record.fee.coinSymbol | String | Fee coin symbol |
| data.record.fee.amount | String | Fee amount |

#### Get User Withdrawal Record List

**POST** `https://ccpayment.com/ccpayment/v2/getUserWithdrawRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | Yes | User ID |
| coinId | Integer | No | Filter by coin |
| toAddress | String | No | Filter by destination address |
| chain | String | No | Filter by chain |
| startAt | Integer | No | 10-digit timestamp |
| endAt | Integer | No | 10-digit timestamp |
| nextId | String | No | Pagination cursor |

---

### 8.4 User Internal Transaction

Transfer funds between users within your merchant wallet system (e.g., tipping, marketplace payouts). Also used to sweep user funds to the merchant account.

#### Create Internal Transaction

**POST** `https://ccpayment.com/ccpayment/v2/userTransfer`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| fromUserId | String | Yes | Source user ID (5–64 chars) |
| toUserId | String | Yes | Destination user ID. Use your App ID to transfer to merchant account |
| coinId | Integer | Yes | Coin ID |
| amount | String | Yes | Amount (min 0.001 USD equivalent) |
| orderId | String | Yes | Your order ID, 3–64 chars |
| remark | String | No | Transaction note (max 255 chars) |

**Rules**:
- **No webhook** for internal transactions.
- If response `code` is `10000`, the transfer is immediately successful.
- Instant and zero-fee.

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": { "recordId": "202403220335..." }
}
```

#### Get User Internal Transaction Record

**POST** `https://ccpayment.com/ccpayment/v2/getUserTransferRecord`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| recordId | String | No | CCPayment transaction ID |
| orderId | String | No | Your order ID |

**Rules**: Pass either, not both empty.

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "record": {
      "recordId": "20240322033752...",
      "coinId": 1329,
      "coinSymbol": "MATIC",
      "orderId": "internal_001",
      "fromUserId": "user_12345",
      "toUserId": "user_67890",
      "amount": "0.002",
      "status": "Success",
      "remark": "tip"
    }
  }
}
```

#### Get User Internal Transaction Record List

**POST** `https://ccpayment.com/ccpayment/v2/getUserTransferRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| fromUserId | String | Yes | Source user ID |
| toUserId | String | Yes | Destination user ID |
| coinId | Integer | No | Filter by coin |
| startAt | Integer | No | 10-digit timestamp |
| endAt | Integer | No | 10-digit timestamp |
| nextId | String | No | Pagination cursor |

---

### 8.5 User Swap

#### User Get Swap Quote

Uses the same endpoint as merchant swap quote, with the additional `extraFeeRate` parameter.

**POST** `https://ccpayment.com/ccpayment/v2/estimate`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinIdIn | Integer | Yes | Input coin ID |
| amountIn | String | Yes | Input amount |
| coinIdOut | Integer | Yes | Output coin ID |
| extraFeeRate | String | No | Your markup fee rate (e.g., `"0.01"` = 1%). Charged from user's output |

**Response**: Includes `amountOut`, `netAmountOut`, `fee`, `extraFee`, `swapRate`, `extraFeeRate`.

`netAmountOut = amountOut - fee - extraFee`

#### Create User Swap Order

**POST** `https://ccpayment.com/ccpayment/v2/userSwap`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| orderId | String | Yes | Your order ID, 3–64 chars |
| userId | String | Yes | User ID |
| coinIdIn | Integer | Yes | Input coin ID |
| amountIn | String | Yes | Input amount |
| coinIdOut | Integer | Yes | Output coin ID |
| extraFeeRate | String | No | Your markup fee rate |
| amountOutMinimum | String | No | Slippage protection |

#### Get User Swap Record

**POST** `https://ccpayment.com/ccpayment/v2/getUserSwapRecord`

Pass `recordId` or `orderId` (not both empty).

Response includes additional `userId`, `extraFee`, `extraFeeRate` fields compared to merchant swap record.

#### Get User Swap Record List

**POST** `https://ccpayment.com/ccpayment/v2/getUserSwapRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | String | No | User ID |
| recordIds | Array[String] | No | Filter by record IDs |
| orderIds | Array[String] | No | Filter by order IDs |
| coinIdIn | Integer | No | Filter by input coin |
| coinIdOut | Integer | No | Filter by output coin |
| startAt | Integer | No | 10-digit timestamp |
| endAt | Integer | No | 10-digit timestamp |
| nextId | String | No | Pagination cursor |

---

## 9. Common APIs

### 9.1 Get Token List

Retrieve all tokens enabled in your merchant "Tokens for your business" config with full network details.

**POST** `https://ccpayment.com/ccpayment/v2/getCoinList`

**Parameters**: None required.

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.coins | Array | List of token objects |
| data.coins[].coinId | Integer | Coin ID. Use this ID in deposit/withdrawal/swap APIs |
| data.coins[].symbol | String | Coin symbol |
| data.coins[].coinFullName | String | Coin full name |
| data.coins[].logoUrl | String | Coin logo URL |
| data.coins[].status | String | `Normal` (active), `Maintain` (withdrawal paused), `Pre-delisting` (deposit paused), `Delisted` (all paused) |
| data.coins[].networks | Object | Map of supported networks for this coin |
| data.coins[].networks[chain].chain | String | Chain symbol. Use this in `chain` parameter of APIs |
| data.coins[].networks[chain].chainFullName | String | Full name of the chain |
| data.coins[].networks[chain].contract | String | Token contract address |
| data.coins[].networks[chain].precision | Integer | Token decimal precision |
| data.coins[].networks[chain].canDeposit | Boolean | Whether deposit is available on this chain |
| data.coins[].networks[chain].canWithdraw | Boolean | Whether withdrawal is available on this chain |
| data.coins[].networks[chain].minimumDepositAmount | String | Minimum deposit amount |
| data.coins[].networks[chain].minimumWithdrawAmount | String | Minimum withdrawal amount |
| data.coins[].networks[chain].maximumWithdrawAmount | String | Maximum withdrawal amount (0 = no maximum) |
| data.coins[].networks[chain].isSupportMemo | Boolean | If true, memo is required for this chain |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "coins": [
      {
        "coinId": 1207,
        "symbol": "LINK",
        "coinFullName": "ChainLink Token",
        "logoUrl": "https://resource.ccpayment.com/token/icon/link.png",
        "status": "Normal",
        "networks": {
          "BSC": {
            "chain": "BSC",
            "chainFullName": "Binance Smart Chain",
            "contract": "0xf8a0bf9cf54bb92f17374d9e9a321e6a111a51bd",
            "precision": 18,
            "canDeposit": true,
            "canWithdraw": true,
            "minimumDepositAmount": "0",
            "minimumWithdrawAmount": "0.025",
            "maximumWithdrawAmount": "0",
            "isSupportMemo": false
          }
        }
      }
    ]
  }
}
```

---

### 9.2 Get Token Information

Get detailed info for a specific token.

**POST** `https://ccpayment.com/ccpayment/v2/getCoin`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | Yes | Coin ID |

**Response**: Same structure as a single coin in Get Token List.

---

### 9.3 Get Token Price

Get current USD-equivalent prices for tokens.

**POST** `https://ccpayment.com/ccpayment/v2/getCoinUSDTPrice`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinIds | Array[Integer] | Yes | Array of coin IDs |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "prices": {
      "1329": "1.1683",
      "1280": "1.0001"
    }
  }
}
```

Prices are in USDT equivalent.

---

### 9.4 Get Balance List (Merchant)

Get all balances in your merchant account.

**POST** `https://ccpayment.com/ccpayment/v2/getAppCoinAssetList`

**Parameters**: None required.

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "assets": [
      { "coinId": 1280, "coinSymbol": "USDT", "available": "1523.45" }
    ]
  }
}
```

---

### 9.5 Get Coin Balance (Merchant)

**POST** `https://ccpayment.com/ccpayment/v2/getAppCoinAsset`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | Yes | Coin ID |

---

### 9.6 Rescan Lost Transaction

User confirms on-chain success but funds not credited. Trigger a manual rescan.

**POST** `https://ccpayment.com/ccpayment/v2/rescanLostTransaction`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| chain | String | Yes | Chain symbol |
| toAddress | String | Yes | Receiving deposit address |
| memo | String | No | Memo (for XRP, XLM, TON) |
| txId | String | Yes | On-chain transaction hash |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "description": "The deposit has been rescanned. Please wait for the transaction to be credited."
  }
}
```

---

### 9.7 Get Cwallet User Information

Validate a Cwallet user before sending a Cwallet withdrawal.

**POST** `https://ccpayment.com/ccpayment/v2/getCwalletUserId`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| cwalletUserId | String | Yes | Cwallet user ID |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "cwalletUserId": "35255142",
    "cwalletUserName": "j***@proton.me"
  }
}
```

---

### 9.8 Check Withdrawal Address Validity

Validate an address before creating a withdrawal.

**POST** `https://ccpayment.com/ccpayment/v2/checkWithdrawalAddressValidity`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| chain | String | Yes | Chain symbol |
| address | String | Yes | Address to validate |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": { "addrIsValid": true }
}
```

---

### 9.9 Get Withdrawal Network Fee

Get real-time network fee before creating a withdrawal.

**POST** `https://ccpayment.com/ccpayment/v2/getWithdrawFee`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | Yes | Coin ID |
| chain | String | Yes | Chain symbol |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "fee": {
      "coinId": 1329,
      "coinSymbol": "MATIC",
      "amount": "0.0213814"
    }
  }
}
```

---

### 9.10 Get Fiat List

Get supported fiat currencies for pricing orders.

**POST** `https://ccpayment.com/ccpayment/v2/getFiatList`

**Parameters**: None.

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "fiats": [
      {
        "fiatId": 1033,
        "symbol": "USD",
        "logoUrl": "https://resource.ccpayment.com/fiat/USD.png",
        "mark": "US",
        "usdRate": "1"
      }
    ]
  }
}
```

Use `fiatId` in deposit order APIs.

---

### 9.11 Get Swap Coin List

Get coins available for swap.

**POST** `https://ccpayment.com/ccpayment/v2/getSwapCoinList`

**Parameters**: None.

**Note**: Only returns coins from your "Tokens for your business" list that are swappable.

---

### 9.12 Get Chain List

Get all supported chains with status and configuration details.

**POST** `https://ccpayment.com/ccpayment/v2/getChainList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| chains | Array[String] | No | Filter by specific chains (e.g., `["ETH", "POLYGON"]`) |

**Response Parameters**:

| Parameter | Type | Description |
|-----------|------|-------------|
| data.chains[].chain | String | Chain symbol (e.g., `BSC`) |
| data.chains[].chainFullName | String | Full name of the chain |
| data.chains[].explorer | String | Blockchain explorer URL |
| data.chains[].baseUrl | String | Base URL for transaction query. Append txId: `baseUrl.replace('%s', txId)` |
| data.chains[].confirmations | Integer | Required block confirmations |
| data.chains[].isEVM | Boolean | Whether chain is EVM-compatible |
| data.chains[].supportMemo | Boolean | Whether memo/tag is required |
| data.chains[].logoUrl | String | Chain logo URL |
| data.chains[].status | String | `Normal` (operating normally) or `Maintenance` (deposits/withdrawals may be delayed) |

**Response Example**:
```json
{
  "code": 10000,
  "msg": "success",
  "data": {
    "chains": [
      {
        "chain": "ETH",
        "chainFullName": "Ethereum",
        "explorer": "https://etherscan.io/",
        "baseUrl": "https://etherscan.io/tx/%s",
        "confirmations": 2,
        "isEVM": true,
        "supportMemo": false,
        "logoUrl": "https://resource.ccpayment.com/token/icon/ETH.png",
        "status": "Normal"
      }
    ]
  }
}
```

---

### 9.13 Get Auto-Withdrawal Record List

Retrieve a list of auto-withdrawal records.

**POST** `https://ccpayment.com/ccpayment/v2/getAutoWithdrawRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | No | Filter by coin |
| recordIds | Array[String] | No | Filter by record IDs |
| chain | String | No | Filter by chain |
| startAt | Integer | No | 10-digit timestamp |
| endAt | Integer | No | 10-digit timestamp |
| nextId | String | No | Pagination cursor |

---

### 9.14 Get Risk Refund Record List

**POST** `https://ccpayment.com/ccpayment/v2/getRiskyRefundRecordList`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| coinId | Integer | No | Filter by coin |
| chain | String | No | Filter by chain |
| toAddress | String | No | Filter by refund address |
| startAt | Integer | No | 10-digit timestamp |
| endAt | Integer | No | 10-digit timestamp |
| nextId | String | No | Pagination cursor |

**Note**: When a risk refund succeeds, the system deducts the risk refund fee and the corresponding service fee from the merchant's account.

---

## 10. Support — FAQ

### Which deposit interface should I use for my business?

**Option 1: Deposit by orders**
- **Industry**: E-commerce, product-related businesses
- Deposits are linked to orders with a fixed amount requirement
- The deposit address has a valid time. After expiration, the merchant still receives deposits to this address for 7 days
- Use: Create Deposit Order (Section 5.2) or Create Invoice Deposit (Section 5.3)

**Option 2: Deposit by permanent addresses**
- **Industry**: Gaming, streaming, social platforms
- Deposits are linked to users with no fixed amount requirement
- The deposit address is permanently assigned to one user. Users can save the address and pay anytime. The merchant's server receives a notification for every payment
- Use: Get Permanent Deposit Address (Section 5.1)
- Contact your account manager for higher address limits

---

## 11. Status Codes & Error Codes

### Response Format

All API responses use this structure:
```json
{
  "code": 10000,
  "msg": "success",
  "data": { ... }
}
```

### Status Codes

| Code | Tip | Description |
|------|-----|-------------|
| 10000 | Success | The request has been successfully processed |
| 10001 | Failed | Request failed. See `msg` for error detail |

### Common Errors

| Code | Tip | Description |
|------|-----|-------------|
| 11000 | InvalidArgument | Invalid parameter |
| 11001 | HeaderInvalidArgument | Invalid header parameter |
| 11002 | Internal | Server error — retry later or contact support |
| 11003 | NotFound | Data does not exist |
| 11004 | RateLimit | Rate limit reached — reduce request frequency |
| 11005 | VerifySignFailed | HMAC signature verification failed — check sign algorithm |
| 11006 | ReqExpired | Request timestamp too old — check server clock |
| 11007 | RepeatedSubmit | Duplicate/repeated submission |
| 11008 | QueryDurationTooMax | Query time range too large |
| 11009 | ReqDailyLimit | Daily request limit exceeded |
| 11010 | QueryNumMax | Query result too large (max 100) |
| 11011 | OrderDuplicate | Order ID already exists |
| 11012 | ExpiredAtTooMax | Expiration exceeds 10-day maximum |
| 11013 | NoSupportVersion | Account restricted to V1 API only |
| 11014 | MaliciousReq | Malicious request — IP banned |
| 11015 | UserIdNotFound | User ID does not exist |

### Account Errors

| Code | Tip | Description |
|------|-----|-------------|
| 12000 | MerchantDisabled | Merchant account disabled |
| 12001 | MerchantNotFound | Merchant does not exist |
| 12002 | IpNotInWhitelist | IP not in whitelist — update at Dashboard > Developer |
| 12003 | MerchantApiDisabled | Complete website verification on dashboard |

### Token Errors

| Code | Tip | Description |
|------|-----|-------------|
| 13000 | InvalidCoin | Unsupported coin |
| 13001 | InvalidChain | Unsupported network for this token |
| 13002 | AbnormalCoinPrice | Abnormal coin price — retry later |
| 13003 | AbnormalCoinPriceNotSupportMode | Price error, only merchant-pay-fee mode available |
| 13004 | UnstableBlockchain | Blockchain unstable — withdrawal unavailable |

### Withdrawal Errors

| Code | Tip | Description |
|------|-----|-------------|
| 14000 | BalanceInsufficient | Not enough balance |
| 14001 | WithdrawFeeTooLow | Network fee too low — check real-time fee |
| 14002 | AddressNotActive | Invalid/inactive address |
| 14003 | AddressEmptyMemo | Memo required for this chain |
| 14004 | ChainStopWithdraw | Withdrawals suspended on this chain |
| 14005 | WithdrawValueLessThanLimit | Below minimum withdrawal amount |
| 14006 | WithdrawValueMoreThanLimit | Exceeds maximum withdrawal amount |
| 14007 | WithdrawAddrFormat | Incorrect address format |
| 14008 | WithdrawCannotSelf | Cannot withdraw to own CCPayment address |
| 14009 | CoinNoSupportMemo | This coin does not support memo |
| 14010 | NoSupportCoin | Coin not in merchant's supported tokens |
| 14011 | WithdrawFeeBalanceNotEnough | Insufficient native token for network fee |
| 14012 | NotSupportMerchantTransfer | Merchant transfer only between main/sub accounts |
| 14013 | CoinPrecisionLimit | Exceeded coin precision limit |
| 14014 | NotFinishCollection | Unpaid asset aggregation fees — check dashboard |
| 14015 | WithdrawToContractAddress | Cannot withdraw to contract addresses |
| 14016 | WithdrawInvalidAddressType | Wrong address type (only data accounts supported) |

### Deposit Errors

| Code | Tip | Description |
|------|-----|-------------|
| 15000 | GenerateAddressFailed | Failed to generate address — retry |
| 15001 | PaymentAddressNumTooMuch | Address limit reached (1000 per App ID) |
| 15003 | ChainStopDeposit | Deposits suspended on this chain |

---

## 12. Integration Flows

### Flow 1: E-commerce Payment (Fixed Price, Merchant-Specified Currency)

```
1. Call Get Token List (getCoinList) → find coinId and chain for accepted currencies
2. Call Create Deposit Order (createAppOrderDepositAddress) with coinId, chain, price, orderId
   → Get address + amount (+ optional checkoutUrl)
3. Display address/amount to customer (or redirect to checkoutUrl)
4. Receive ApiDeposit webhook
5. Call Get Order Information (getAppOrderInfo) with orderId → confirm actual payment
6. Compare paid amount vs expected → fulfill order
```

### Flow 2: E-commerce Payment (Customer Chooses Crypto)

```
1. Call Get Fiat List (getFiatList) → find fiatId for your currency
2. Call Create Invoice Deposit (createInvoiceUrl) with orderId, price, priceFiatId
   → Get invoiceUrl
3. Redirect customer to invoiceUrl
4. Receive ApiDeposit webhook
5. Call Get Invoice Order Information (getInvoiceOrderInfo) with orderId → confirm payment
6. Check totalPaidValue vs price → fulfill order
```

### Flow 3: Permanent Address Deposits (Gaming/Social)

```
1. Call Get Permanent Deposit Address (getOrCreateAppDepositAddress) with referenceId + chain
   → Get address (+ memo for XRP/XLM/TON)
2. Display address to user (save in your DB)
3. Receive DirectDeposit webhook
4. Call Get Deposit Record (getAppDepositRecord) with recordId → confirm amount & status
5. Credit user in your system
```

### Flow 4: Send Withdrawal

```
1. Call Check Withdrawal Address Validity (checkWithdrawalAddressValidity) → verify address
2. Call Get Withdrawal Network Fee (getWithdrawFee) → show fee to user
3. Call Get Coin Balance (getAppCoinAsset) → verify sufficient balance
4. Call Create Network Withdrawal (applyAppWithdrawToNetwork)
5. Receive ApiWithdrawal webhook (Processing → Success)
6. Call Get Withdrawal Record (getAppWithdrawRecord) → confirm final status
```

### Flow 5: User Wallet System

```
1. Call Create/Get User Deposit Address (getOrCreateUserDepositAddress) for each user
2. Receive UserDeposit webhook → call Get User Deposit Record (getUserDepositRecord)
3. User balances: Get User Balance List (getUserCoinAssetList)
4. User-to-user transfers: Create Internal Transaction (userTransfer)
5. User withdrawals: User Withdrawal to Blockchain (applyUserWithdrawToNetwork)
6. User swaps: Create User Swap Order (userSwap)
```

---

## 13. Best Practices

### Security
- **Never expose** `appSecret` in client-side code or public repos.
- Use **IP whitelisting** on Dashboard > Developer for production.
- Always **verify webhook signatures** by checking the HMAC or RSA signature against CCPayment's webhook IPs.
- Always **call Get Record APIs** to confirm transaction status — never trust webhooks alone.

### Reliability
- Implement **idempotency** using `recordId` to prevent double-crediting.
- Handle **webhook retries** gracefully — the same event may arrive multiple times.
- For withdrawals, if no response due to network issues, call **Get Withdrawal Record** to check status.
- Set reasonable **timeouts** with retry logic for API calls.

### Performance
- **Cache** token lists and fiat lists — they don't change frequently.
- Use **pagination** (`nextId`) for record list queries.
- Respect **rate limits** — implement exponential backoff on `11004` errors.

### Money Safety
- Never auto-credit **risky transactions** (`isFlaggedAsRisky: true`).
- For order-based deposits, compare **total paid vs expected** amount to handle partial/overpayments.
- Use **amountOutMinimum** in swap orders for slippage protection.
- Check **canDeposit / canWithdraw** flags before showing options to users.

### Testnet
- **Always test on Sepolia first** before going live.
- Remember to **disable testnet** when switching to production.

---

## 14. Links & Resources

| Resource | URL |
|----------|-----|
| CCPayment Website | https://ccpayment.com |
| API Documentation (V2) | https://ccpayment.com/api/doc |
| Merchant Dashboard | https://console.ccpayment.com |
| Developer Config (APP ID & Secret) | https://console.ccpayment.com/developer/config |
| Merchant Settings | https://console.ccpayment.com/merchatsetting/menu/settings |
| Webhook Logs | https://console.ccpayment.com/webhook/index |
| Risky Transactions | https://console.ccpayment.com/transaction/list/risk-list |
| Telegram Support Bot | https://t.me/CCPaymentSupportBot |
| Telegram Community | https://t.me/ccpayment_com |
| Support Email | support@ccpayment.com |
| Partnership Email | partner@ccpayment.com |
| Support Center | https://ccpayment.com/support-center |
| Referral Program | https://ccpayment.com/en/referral |
| X / Twitter | https://x.com/CCPaymentX |
| LinkedIn | https://www.linkedin.com/company/ccpayment |
| Medium Blog | https://ccpayment.medium.com |

---

## Complete API Endpoint Reference (Quick Lookup)

| # | API Name | Endpoint URL |
|---|----------|-------------|
| 1 | Get Permanent Deposit Address | `POST /v2/getOrCreateAppDepositAddress` |
| 2 | Create Deposit Order (Merchant-Specified) | `POST /v2/createAppOrderDepositAddress` |
| 3 | Create Invoice Deposit (Customer-Selected) | `POST /v2/createInvoiceUrl` |
| 4 | Get Order Information (Merchant-Specified) | `POST /v2/getAppOrderInfo` |
| 5 | Get Invoice Order Information (Customer-Selected) | `POST /v2/getInvoiceOrderInfo` |
| 6 | Address Unbinding | `POST /v2/addressUnbinding` |
| 7 | Get Deposit Record | `POST /v2/getAppDepositRecord` |
| 8 | Get Deposit Record List | `POST /v2/getAppDepositRecordList` |
| 9 | Create Network Withdrawal | `POST /v2/applyAppWithdrawToNetwork` |
| 10 | Withdrawal to Cwallet | `POST /v2/applyAppWithdrawToCwallet` |
| 11 | Get Withdrawal Record | `POST /v2/getAppWithdrawRecord` |
| 12 | Get Withdrawal Record List | `POST /v2/getAppWithdrawRecordList` |
| 13 | Get Swap Quote (Merchant & User) | `POST /v2/estimate` |
| 14 | Create Swap Order (Merchant) | `POST /v2/swap` |
| 15 | Get Swap Record | `POST /v2/getSwapRecord` |
| 16 | Get Swap Record List | `POST /v2/getSwapRecordList` |
| 17 | Get User Balance List | `POST /v2/getUserCoinAssetList` |
| 18 | Get User Coin Balance | `POST /v2/getUserCoinAsset` |
| 19 | Create/Get User Deposit Address | `POST /v2/getOrCreateUserDepositAddress` |
| 20 | Get User Deposit Record | `POST /v2/getUserDepositRecord` |
| 21 | Get User Deposit Record List | `POST /v2/getUserDepositRecordList` |
| 22 | User Withdraw to Network | `POST /v2/applyUserWithdrawToNetwork` |
| 23 | User Withdraw to Cwallet | `POST /v2/applyUserWithdrawToCwallet` |
| 24 | Get User Withdrawal Record | `POST /v2/getUserWithdrawRecord` |
| 25 | Get User Withdrawal Record List | `POST /v2/getUserWithdrawRecordList` |
| 26 | User Internal Transfer | `POST /v2/userTransfer` |
| 27 | Get User Transfer Record | `POST /v2/getUserTransferRecord` |
| 28 | Get User Transfer Record List | `POST /v2/getUserTransferRecordList` |
| 29 | Create User Swap Order | `POST /v2/userSwap` |
| 30 | Get User Swap Record | `POST /v2/getUserSwapRecord` |
| 31 | Get User Swap Record List | `POST /v2/getUserSwapRecordList` |
| 32 | Get Token List | `POST /v2/getCoinList` |
| 33 | Get Token Information | `POST /v2/getCoin` |
| 34 | Get Token Price | `POST /v2/getCoinUSDTPrice` |
| 35 | Get Merchant Balance List | `POST /v2/getAppCoinAssetList` |
| 36 | Get Merchant Coin Balance | `POST /v2/getAppCoinAsset` |
| 37 | Rescan Lost Transaction | `POST /v2/rescanLostTransaction` |
| 38 | Get Cwallet User Information | `POST /v2/getCwalletUserId` |
| 39 | Check Withdrawal Address Validity | `POST /v2/checkWithdrawalAddressValidity` |
| 40 | Get Withdrawal Network Fee | `POST /v2/getWithdrawFee` |
| 41 | Get Fiat List | `POST /v2/getFiatList` |
| 42 | Get Swap Coin List | `POST /v2/getSwapCoinList` |
| 43 | Get Chain List | `POST /v2/getChainList` |
| 44 | Get Auto-Withdrawal Record List | `POST /v2/getAutoWithdrawRecordList` |
| 45 | Get Risk Refund Record List | `POST /v2/getRiskyRefundRecordList` |
| 46 | Resend Webhook | `POST /v2/webhook/resend` |

All endpoints use base URL: `https://ccpayment.com/ccpayment`
