# API ที่เข้ากันได้กับ Cryptomus ของ blockwallets

> API ที่เข้ากันได้กับ Cryptomus ของ blockwallets: ใบแจ้งหนี้และกระเป๋าคงที่ การเซ็น Webhook และการตรวจสอบ โหมดทดสอบ เครือข่าย ข้อผิดพลาด และการย้ายจาก Cryptomus ด้วยการเปลี่ยนโดเมน
>
> HTML: https://blockwallets.io/docs/cryptomus?lang=th · English: https://blockwallets.io/docs/cryptomus.md?lang=en

## API ที่เข้ากันได้กับ Cryptomus

blockwallets ให้คุณรับ USDT และ USDC รวมถึง BTC, LTC, DOGE, BCH และเหรียญประจำเครือข่าย (บันทึกเป็นดอลลาร์สหรัฐด้วยอัตราที่ล็อกไว้): ลูกค้าจ่าย เรายืนยันบนเชน แล้วแจ้งคุณ API ลายเซ็น และ Webhook เหมือน **Cryptomus** ทุกประการ หากคุณเคยเชื่อมต่อ Cryptomus แค่เปลี่ยนโดเมนก็เสร็จ เริ่มจากหลักการทำงานก่อน แล้วจึงถึง API

### สองวิธีรับเงิน

ทั้งสองวิธีรับ**จำนวนเท่าไรก็ได้**: คำสั่งซื้อราคาคงที่ และการเติมเงินที่ลูกค้าพิมพ์จำนวนเอง เมื่อชำระแล้ว คุณจัดส่งหรือเพิ่มยอดคงเหลือของลูกค้า ความต่างเดียวคือ**ทุกการชำระได้ที่อยู่ใหม่หรือไม่**

แนะนำ · เหมาะกับการเชื่อมต่อส่วนใหญ่**ใบแจ้งหนี้**
ลูกค้าเลือกสินค้าหรือใส่จำนวนเงินบนหน้าของคุณ คุณสร้างใบแจ้งหนี้ แล้วลูกค้าโอนตามจำนวนที่หน้าชำระเงินแสดง ใบแจ้งหนี้แต่ละใบมีที่อยู่ใหม่และตัวนับถอยหลัง เมื่อเงินเข้า เราแจ้งคุณพร้อมจำนวนที่ได้รับจริง

`POST /v1/payment` → webhook `type: payment`

ตัวเลือก**กระเป๋าคงที่**
ไม่ต้องระบุจำนวนล่วงหน้า: ลูกค้าแต่ละคนได้ที่อยู่ถาวรต่อหนึ่งเครือข่าย เก็บไว้ในกระเป๋าของตนและโอนเข้าเมื่อไรก็ได้ ทุกการโอนทำให้เกิด Webhook ของตัวเอง

`POST /v1/wallet` → webhook `type: wallet`

หากไม่แน่ใจ ให้ใช้ใบแจ้งหนี้ หากไม่เขียนโค้ด[ลิงก์ชำระเงิน](https://blockwallets.io/docs/cryptomus?lang=th#links)ในแดชบอร์ดคือใบแจ้งหนี้ที่สร้างให้คุณ ยังไม่ได้เป็นร้านค้า? ขอใช้งานที่[หน้าแรก](https://blockwallets.io/?lang=th#join) เมื่ออนุมัติแล้ว เข้าสู่ระบบ[แดชบอร์ดร้านค้า](https://blockwallets.io/dashboard)และเริ่มจาก “ลองรับเงินหนึ่งรายการ” ที่หน้าแรกของแดชบอร์ดด้วยจำนวนเล็กน้อยก่อน (เงินเข้ายอดคงเหลือของคุณเอง)

### ใบแจ้งหนี้ทำงานอย่างไร

การชำระเงินมีสี่ฝ่าย: ลูกค้า เว็บไซต์ของคุณ blockwallets และบล็อกเชน แผนภาพไล่จากบนลงล่างตามเวลา คอลัมน์ขวาคือสถานะของใบแจ้งหนี้ในแต่ละขั้น

สรุปห้าขั้นตอน:

- คุณสร้างใบแจ้งหนี้ (ลิงก์ชำระเงินสร้างให้ หรือเซิร์ฟเวอร์ของคุณเรียก `/v1/payment`) ได้ `url` ของหน้าชำระเงิน แล้วส่งลูกค้าไปที่นั่น

- ที่หน้าชำระเงิน ลูกค้าเลือกเหรียญและเครือข่าย ได้ที่อยู่และจำนวนเงินเฉพาะ แล้วจ่ายจากกระเป๋าหรือกระดานเทรด

- เราเห็นการโอนบนเชน รอการยืนยันให้พอ แล้วตรวจไขว้กับผู้ให้บริการโหนดรายที่สอง (โหนดหนึ่งจึงปลอมไม่ได้)

- ใบแจ้งหนี้เป็น `paid` และเราส่ง POST Webhook ที่เซ็นแล้วไปที่ `url_callback` ของคุณทันที อีกไม่กี่วินาที หน้าชำระเงินส่งลูกค้ากลับไปที่ `url_success` ของคุณ

- เงินถูกบันทึกเข้ายอดคงเหลือของคุณ ถอนเข้ากระเป๋าของคุณเองได้จากแดชบอร์ดร้านค้า

#### สถานะใบแจ้งหนี้

| status | ความหมาย | สิ่งที่คุณทำ |
| --- | --- | --- |
| `check` | รอการชำระ | — |
| `confirm_check` | พบการโอนแล้ว รอการยืนยัน | — |
| `wrong_amount_waiting` | ได้รับแล้วแต่ไม่ครบ ลูกค้าเติมเข้าที่อยู่เดิมได้ (เมื่อ `is_payment_multiple` เป็น true แจ้งหนึ่งครั้ง) | — (คุณจะได้ `paid` เมื่อเติมครบ) |
| `paid` | ชำระแล้ว | จัดส่ง / เพิ่มยอดตาม `payment_amount_usd` |
| `paid_over` | ชำระแล้ว และจ่ายเกิน | เหมือนกัน (`payment_amount_usd` คือยอดที่ได้รับ) |
| `wrong_amount` | หมดอายุโดยได้รับไม่ครบ (เมื่อ `is_payment_multiple` เป็น false: การโอนที่ไม่ครบครั้งแรก) | ธุรกิจเติมเงินบันทึกยอด `payment_amount_usd` ที่ได้รับได้ ร้านค้าขอให้ลูกค้าจ่ายส่วนที่เหลือ |
| `cancel` | หมดอายุโดยไม่ได้รับเงินเลย | — (เงินที่เข้ามาทีหลังยังถูกบันทึกและแจ้งให้ทราบ) |

เมื่อ `is_final` เป็น `true` สถานะจะไม่เปลี่ยนอีก (ยกเว้นการชำระที่มาช้า)

### ลิงก์ชำระเงิน (ไม่ต้องเขียนโค้ด)

แดชบอร์ดร้านค้า → “การรับเงิน › ลิงก์รับชำระ” → ใส่คำอธิบายและจำนวนเงิน (กำหนดเครือข่ายหรือให้ลูกค้าเลือก) → สร้าง แต่ละลิงก์มี URL และคิวอาร์โค้ด

- ทุกครั้งที่มีคนเปิดลิงก์ จะสร้างใบแจ้งหนี้ใหม่ ลิงก์เดียวจึงใช้ซ้ำได้ (เช่น “สมาชิก $99”)

- ทุกการชำระปรากฏใน “การรับเงิน › รายการรับเงิน” ถอนเข้ากระเป๋าของคุณได้จาก “เงิน › ยอดคงเหลือและการถอน”

- หากคุณสร้างข้อมูลรับรองและ URL Webhook ใน “นักพัฒนา › การเชื่อมต่อและคีย์” ไว้แล้ว การชำระผ่านลิงก์จะแจ้งในรูปแบบด้านล่างด้วย

- หากไม่ต้องการรับอีก กด “ปิดใช้งาน” ลิงก์จะหยุดทำงานทันที

### การเชื่อมต่อ API

#### 1. ข้อมูลรับรองและการเซ็น

แดชบอร์ดร้านค้า → “นักพัฒนา › การเชื่อมต่อและคีย์” → สร้าง **merchant** (UUID) และ **API key** มีหนึ่งชุดสำหรับ Live และหนึ่งชุดสำหรับ Test: Live รับเงินจริง Test รันบนเทสต์เน็ต และเพิ่ม**โดเมนเว็บไซต์**ของคุณด้วย: `url_callback`, `url_return` และ `url_success` ต้องอยู่ในโดเมนเหล่านี้ API key แสดงเพียงครั้งเดียว เก็บให้ดีและเก็บไว้เฉพาะบนเซิร์ฟเวอร์ของคุณ

Base URL `https://blockwallets.io` ทุก endpoint เป็น `POST` + JSON พร้อมเฮดเดอร์เหล่านี้:

- `merchant`: UUID ของ merchant ของคุณ (ตัวนี้กำหนดว่า Live หรือ Test)

- `sign`: `md5(base64(เนื้อหาคำขอ) + API key)` โดยเนื้อหาคือสตริง JSON ที่ส่งจริงทุกตัวอักษร

สำเร็จจะคืน `{"state": 0, "result": {…}}` ล้มเหลวจะคืน `{"state": 1, "message": "…"}` (ดู[ข้อผิดพลาด](https://blockwallets.io/docs/cryptomus?lang=th#errors))

endpoint หลักด้านล่างมีแผง “ลองเลย”: ใส่ merchant และ API key ของ Test แล้วหน้านี้จะเซ็นคำขอในเบราว์เซอร์ของคุณ เรียก endpoint และแสดงคำขอกับการตอบกลับครบถ้วน (ข้อมูลรับรองอยู่ในหน่วยความจำของหน้านี้เท่านั้น) เมื่อลายเซ็นไม่ตรง ให้เทียบทีละขั้นกับ[ตัวตรวจลายเซ็น](https://blockwallets.io/docs/sign?lang=th)

```nodejs
import crypto from "node:crypto";

async function call(path, data) {
  const body = JSON.stringify(data);
  const sign = crypto.createHash("md5").update(Buffer.from(body).toString("base64") + process.env.BW_API_KEY).digest("hex");
  const res = await fetch("https://blockwallets.io" + path, {
    method: "POST",
    headers: { merchant: process.env.BW_MERCHANT, sign, "Content-Type": "application/json" },
    body,
  });
  return res.json();
}
```

```php
function bw_call(string $path, array $data): array {
    $body = json_encode($data, JSON_UNESCAPED_UNICODE);
    $sign = md5(base64_encode($body) . getenv('BW_API_KEY'));
    $ch = curl_init('https://blockwallets.io' . $path);
    curl_setopt_array($ch, [
        CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['merchant: ' . getenv('BW_MERCHANT'), 'sign: ' . $sign, 'Content-Type: application/json'],
    ]);
    return json_decode(curl_exec($ch), true);
}
```

```python
import base64, hashlib, json, os, requests

def bw_call(path: str, data: dict) -> dict:
    body = json.dumps(data, separators=(",", ":"), ensure_ascii=False)
    sign = hashlib.md5((base64.b64encode(body.encode()).decode() + os.environ["BW_API_KEY"]).encode()).hexdigest()
    headers = {"merchant": os.environ["BW_MERCHANT"], "sign": sign, "Content-Type": "application/json"}
    return requests.post("https://blockwallets.io" + path, data=body.encode(), headers=headers).json()
```

#### 2. สร้างใบแจ้งหนี้ POST /v1/payment

เมื่อลูกค้าสั่งซื้อ หรือใส่จำนวนเงินในหน้าเติมเงินของคุณ ให้เรียก `https://blockwallets.io/v1/payment` แล้วส่งลูกค้าไปที่ `result.url` ที่ได้รับ

```json
{
  "amount": "42.00",
  "currency": "USD",
  "order_id": "order_1042",
  "url_callback": "https://shop.example/webhooks/crypto",
  "url_return": "https://shop.example/cart",
  "url_success": "https://shop.example/thanks?order=1042"
}
```

| พารามิเตอร์ | จำเป็น | คำอธิบาย |
| --- | --- | --- |
| `amount` | ใช่ | จำนวนเงินเป็นสตริง ทศนิยมไม่เกินสองตำแหน่ง: `"42.00"` ราคาของคุณหรือตัวเลขที่ลูกค้าใส่ ต้องไม่ต่ำกว่าขั้นต่ำของเครือข่ายที่เลือก (ดู[เครือข่าย](https://blockwallets.io/docs/cryptomus?lang=th#networks)) |
| `currency` | ใช่ | `USD`, `USDT` หรือ `USDC` ทั้งหมด 1:1 |
| `order_id` | ใช่ | เลขคำสั่งซื้อของคุณ: ตัวอักษร ตัวเลข `-`, `_` ไม่เกิน 100 ตัวอักษร การเรียกซ้ำด้วย order_id เดิมจะคืนใบแจ้งหนี้เดิม (ไม่มีคำสั่งซื้อซ้ำ) |
| `url_callback` | ไม่ | URL Webhook หากไม่ใส่จะไม่ส่ง Webhook |
| `url_return` | ไม่ | ที่ที่ “ย้อนกลับ” ไปก่อนชำระ |
| `url_success` | ไม่ | ที่ที่ลูกค้าไปหลังชำระ |
| `network` | ไม่ | เลือกเครือข่ายล่วงหน้า: `tron` / `bsc` / `eth` / `base` / `polygon` / `arbitrum` / `optimism` / `avalanche` / `xlayer` / `btc` / `ltc` / `doge` / `bch` / `sol` / `ton` หากไม่ใส่ ลูกค้าเลือกที่หน้าชำระเงิน |
| `to_currency` | ไม่ | เหรียญบนเครือข่ายนั้น: `USDT` / `USDC` ส่วน `btc` / `ltc` / `doge` / `bch` เป็น `BTC` / `LTC` / `DOGE` / `BCH` (ไม่บังคับ) |
| `lifetime` | ไม่ | อายุของใบแจ้งหนี้เป็นวินาที 300 – 43200 ค่าเริ่มต้น 3600 ค่าที่ต่ำกว่า 600 นับเป็น 600 |
| `accuracy_payment_percent` | ไม่ | จ่ายขาดได้เท่าไรที่ยังนับว่าชำระแล้ว 0 – 5 ค่าเริ่มต้น 0 `100` = รับเท่าไรก็ได้ที่เข้ามา: เป็น `paid` ทันทีที่ยืนยัน (`paid_over` หากเกิน) บันทึกยอดตาม `payment_amount_usd` ใน Webhook เหมาะกับการเติมเงิน หากไม่ใส่ จะใช้ “กฎยอดรับเงิน” ใน “ตั้งค่า › กฎการรับเงินและอัตราค่าธรรมเนียม” ของแดชบอร์ด: “บันทึกตามที่เข้ามา” หมายถึง 100 |
| `subtract` | ไม่ | สัดส่วนค่าธรรมเนียมแพลตฟอร์มที่ลูกค้าจ่าย 0 – 100 บวกเข้า `payer_amount` (ค่าธรรมเนียมแพลตฟอร์มคือ 1% ลดลงเมื่อยอดสูงขึ้น ที่ 1% หากใส่ 100 ใบแจ้งหนี้ $100 ลูกค้าจ่าย $101.00 ดู[ราคา](https://blockwallets.io/pricing?lang=th)) หากไม่ใส่ จะใช้การตั้งค่า “ค่าธรรมเนียมและการจ่ายไม่ครบ” ใน “ตั้งค่า › กฎการรับเงินและอัตราค่าธรรมเนียม” ของแดชบอร์ด (ค่าเริ่มต้น 0) |
| `is_payment_multiple` | ไม่ | จ่ายไม่ครบเติมต่อได้หรือไม่ ค่าเริ่มต้น true: สถานะ `wrong_amount_waiting` จ่ายส่วนที่เหลือเข้าที่อยู่เดิมแล้วเป็น `paid` (หากเหลือเวลาน้อยกว่า 30 นาทีตอนจ่ายไม่ครบครั้งแรก กำหนดเวลาจะเลื่อนเป็นอีก 30 นาที) false: การโอนที่ไม่ครบครั้งแรกทำให้เป็น `wrong_amount` หากไม่ใส่ จะใช้การตั้งค่าของแดชบอร์ด |
| `additional_data` | ไม่ | สตริงใดก็ได้ (≤ 255) ส่งกลับตามที่เป็นในการค้นสถานะและ Webhook |

```json
{
  "state": 0,
  "result": {
    "uuid": "6f1c2a7e-…",
    "order_id": "order_1042",
    "amount": "42.00",
    "currency": "USD",
    "network": null,
    "address": null,
    "payer_amount": null,
    "payment_amount": null,
    "url": "https://blockwallets.io/pay/inv_01J8…",
    "expired_at": 1760965200,
    "status": "check",
    "is_final": false
  }
}
```

`network`, `address` และ `payer_amount` จะถูกกรอกเมื่อลูกค้าเลือกเครือข่าย

#### 3. ค้นสถานะใบแจ้งหนี้

- `POST /v1/payment/info` `{"order_id": "…"}` หรือ `{"uuid": "…"}`: ดึงใบแจ้งหนี้หนึ่งใบและตรวจเชนระหว่างทาง (อย่างมากหนึ่งครั้งต่อ 10 วินาที)

- `POST /v1/payment/list`: รายการ หน้าละ 15 รายการ มี `date_from` / `date_to` เป็นทางเลือก หน้าถัดไปใช้ `paginate.nextCursor` ที่ได้รับ (`?cursor=…`)

- `POST /v1/payment/services`: เครือข่ายที่ใช้ได้และจำนวนขั้นต่ำของแต่ละเครือข่าย

- `POST /v1/payment/resend` `{"order_id": "…"}`: ส่ง Webhook ของใบแจ้งหนี้ที่ชำระแล้ว / จ่ายขาดอีกครั้ง

Webhook คือช่องทางหลัก การค้นสถานะเป็นทางสำรอง (เช่น เซิร์ฟเวอร์ของคุณล่มและพลาด Webhook)

#### 4. กระเป๋าคงที่ POST /v1/wallet

เปิดที่อยู่ถาวรให้ลูกค้าหนึ่งคนบนหนึ่งเครือข่าย `order_id` เดียวกัน (มักเป็น user id ของคุณ) + เครือข่ายเดียวกัน ได้ที่อยู่เดิมเสมอ เชน EVM ทั้งหมด (BNB Chain, Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, X Layer) ใช้ที่อยู่เดียวกัน ส่วน TRON, BTC, LTC, DOGE, BCH, Solana และ TON มีที่อยู่ของตัวเอง ลูกค้าส่งมาเท่าไรก็บันทึกเท่านั้น และมี Webhook ต่อหนึ่งการโอน การโอน BTC / LTC / DOGE / BCH / TRX / BNB / ETH / POL / AVAX / OKB / SOL / TON แปลงเป็นดอลลาร์สหรัฐด้วยอัตราตอนที่เห็นแต่ละรายการ (`payment_amount_usd`)

```json
{
  "order_id": "user_42",
  "currency": "USDT",
  "network": "tron",
  "url_callback": "https://shop.example/webhooks/crypto"
}
```

```json
{
  "state": 0,
  "result": {
    "wallet_uuid": "0b9d…",
    "uuid": "5e2f…",
    "order_id": "user_42",
    "currency": "USDT",
    "network": "tron",
    "address": "TXy4…8kQ2",
    "url": "https://blockwallets.io/deposit/dac_01J8…"
  }
}
```

`result.url` คือหน้าฝากเงินที่เราโฮสต์ (ที่อยู่ + คิวอาร์โค้ด + รายการฝากล่าสุด) ที่คุณมอบให้ลูกค้าได้ การโอนที่ต่ำกว่าขั้นต่ำของเครือข่าย (ปกติ $1, BTC $5) จะไม่ถูกบันทึกยอดให้อัตโนมัติ ติดต่อเราเพื่อให้บันทึกยอดให้ ยังไม่รองรับการบล็อกที่อยู่ (`/v1/wallet/block-address`)

### Webhook

เมื่อสถานะของใบแจ้งหนี้เปลี่ยน (`paid`, `paid_over`, `wrong_amount_waiting`, `wrong_amount`, `cancel`) และทุกการโอนเข้ากระเป๋าคงที่ เราส่ง POST JSON ไปที่ `url_callback` การตอบ 2xx นับว่าส่งถึงแล้ว มิฉะนั้นเราลองใหม่หลัง 1 นาที, 5 นาที, 30 นาที, 2 ชั่วโมง, 12 ชั่วโมง, 24 ชั่วโมง และ 24 ชั่วโมง คุณส่งซ้ำได้จากแดชบอร์ดหรือด้วย `/v1/payment/resend`

```json
{
  "type": "payment",
  "uuid": "6f1c2a7e-…",
  "order_id": "order_1042",
  "amount": "42.00",
  "payment_amount": "42",
  "payment_amount_usd": "42.00",
  "merchant_amount": "41.58",
  "commission": "0.42",
  "is_final": true,
  "status": "paid",
  "from": "TQ8m…",
  "wallet_address_uuid": null,
  "network": "tron",
  "currency": "USD",
  "payer_currency": "USDT",
  "payer_amount": "42",
  "payer_amount_exchange_rate": "1",
  "additional_data": null,
  "txid": "9c1e…",
  "sign": "5f0c9b…"
}
```

| type | เมื่อ | การบันทึกยอด |
| --- | --- | --- |
| `payment` | สถานะของใบแจ้งหนี้เปลี่ยน ดู `status` | บันทึกยอด `payment_amount_usd` เมื่อ `paid` / `paid_over` กรองซ้ำด้วย `uuid` |
| `wallet` | มีการโอนเข้ากระเป๋าคงที่ (`status` เป็น `paid` เสมอ `order_id` คือค่าที่คุณใช้เปิดกระเป๋า) | บันทึกยอด `payment_amount_usd` ทุกการโอนมี `uuid` ของตัวเอง ให้กรองซ้ำด้วยค่านั้น |

#### ตรวจสอบลายเซ็น (จำเป็น)

ลายเซ็นคือฟิลด์ `sign` ในเนื้อหา Webhook: ตัด `sign` ออก แล้วเข้ารหัสส่วนที่เหลือใหม่แบบ PHP `json_encode` (กะทัดรัด, `/` ถูก escape เป็น `\/`, อักขระที่ไม่ใช่ ASCII ไม่ถูก escape) จากนั้น `md5(base64(ผลที่เข้ารหัส) + API key)` ต้องเท่ากับ `sign` ใช้ API key ของโหมดเดียวกัน Webhook เดียวกันอาจมาถึงมากกว่าหนึ่งครั้ง: กรองซ้ำด้วย `uuid` + `status`

หากการตรวจสอบล้มเหลว ให้วางเนื้อหา Webhook ดิบใน[ตัวตรวจลายเซ็น](https://blockwallets.io/docs/sign?lang=th): จะแสดงผลของทุกขั้นและทำเครื่องหมายจุดที่ของคุณต่าง (ทั้งหมดทำงานในเบราว์เซอร์ของคุณ ไม่มีการอัปโหลด API key) Webhook ทุกรายการใน “นักพัฒนา › บันทึก Webhook” ของแดชบอร์ดเปิดในตัวตรวจได้ในคลิกเดียว

```nodejs
import crypto from "node:crypto";

function verify(rawBody, apiKey) {
  const { sign, ...data } = JSON.parse(rawBody);
  const json = JSON.stringify(data).replaceAll("/", "\\/");
  const expected = crypto.createHash("md5").update(Buffer.from(json).toString("base64") + apiKey).digest("hex");
  return typeof sign === "string" && sign.length === expected.length && crypto.timingSafeEqual(Buffer.from(sign), Buffer.from(expected));
}
```

```php
$data = json_decode(file_get_contents('php://input'), true);
$sign = $data['sign'] ?? '';
unset($data['sign']);
$expected = md5(base64_encode(json_encode($data, JSON_UNESCAPED_UNICODE)) . $apiKey);
if (!hash_equals($expected, $sign)) {
    http_response_code(401); exit;
}
```

```python
import base64, hashlib, hmac, json

def verify(raw_body: bytes, api_key: str) -> bool:
    data = json.loads(raw_body)
    sign = data.pop("sign", "")
    encoded = json.dumps(data, separators=(",", ":"), ensure_ascii=False).replace("/", "\\/")
    expected = hashlib.md5((base64.b64encode(encoded.encode()).decode() + api_key).encode()).hexdigest()
    return hmac.compare_digest(expected, sign)
```

### โหมดทดสอบ

ใบแจ้งหนี้ที่สร้างด้วย merchant และ API key ของ Test รันบนเทสต์เน็ต ไม่เกี่ยวกับเงินจริง หน้าชำระเงินแสดงปุ่ม “จำลองการชำระเงิน” (เต็มจำนวน / ครึ่งหนึ่ง / จ่ายเกิน) คุณจึงเห็นการเปลี่ยนสถานะและ Webhook โดยไม่ต้องหาเหรียญเทสต์เน็ต

- `POST /v1/test-webhook/payment`, `/v1/test-webhook/wallet`: ส่ง Webhook ตัวอย่างที่เซ็นแล้วไปที่ `url_callback` (ต้องส่ง `url_callback` ที่อยู่ในโดเมนเว็บไซต์ที่คุณลงทะเบียนไว้ พร้อม `currency`, `network` และ `status`, `order_id` ได้ตามต้องการ) เพื่อดีบักโค้ดตรวจสอบของคุณ

- แดชบอร์ด “นักพัฒนา › การเชื่อมต่อและคีย์” → “ส่งการแจ้งทดสอบ”: ส่งตัวอย่างไปที่ URL Webhook ของคุณ

- แดชบอร์ด “นักพัฒนา › บันทึก Webhook”: ทุกครั้งที่พยายามส่งพร้อมเวลา URL ปลายทาง สถานะ HTTP ระยะเวลา เนื้อหาคำขอ และการตอบกลับของเซิร์ฟเวอร์คุณ (4 KB แรก) กรองตามคำสั่งซื้อหรือสถานะ และส่งซ้ำได้ในคลิกเดียว เก็บไว้ 30 วัน

### ย้ายจาก Cryptomus

- แดชบอร์ด “นักพัฒนา › การเชื่อมต่อและคีย์” → สร้าง merchant และ API key

- เปลี่ยน `https://api.cryptomus.com` ในโค้ดของคุณเป็น `https://blockwallets.io` และใช้ merchant กับ API key ใหม่

- เพิ่มโดเมนของคุณที่ “โดเมนเว็บไซต์” (`url_callback` / `url_return` / `url_success` รับเฉพาะโดเมนเหล่านี้)

รองรับ: `/v1/payment`, `/v1/payment/info`, `/v1/payment/list`, `/v1/payment/services`, `/v1/payment/resend`, `/v1/wallet`, `/v1/test-webhook/payment`, `/v1/test-webhook/wallet` ข้อแตกต่าง: ใบแจ้งหนี้กำหนดราคาเป็น USD / USDT / USDC เท่านั้น (ทั้งหมด 1:1 ไม่มีส่วนต่างอัตราแลกเปลี่ยน) `commission` คือค่าธรรมเนียมแพลตฟอร์มของเรา (ยอดที่ได้รับ × อัตราของร้านค้าตอนสร้างใบแจ้งหนี้ มาตรฐาน 1% ลดได้ถึง 0.5% ตามยอด ส่วนที่ลูกค้าจ่ายแทนจะไม่ถูกเก็บซ้ำ) และ `merchant_amount` = ยอดที่ได้รับ − `commission` เมื่อลูกค้าจ่ายเป็น BTC / LTC / DOGE / BCH / TRX / BNB / ETH / POL / AVAX / OKB / SOL / TON เราเสนอราคาด้วยค่ามัธยฐานจากหลายกระดานเทรด ล็อกไว้ 30 นาที — `payer_amount` คือจำนวนเหรียญที่ต้องส่ง `payer_amount_exchange_rate` คือมูลค่า USD ของหนึ่งเหรียญ และการชำระถูกแปลงเป็น `payment_amount_usd` ด้วยอัตราที่ล็อกไว้ (เหรียญอยู่กับเรา ไม่มีการสลับเหรียญ) เครือข่าย `tron` / `bsc` / `eth` / `base` / `polygon` / `arbitrum` / `optimism` / `avalanche` / `xlayer` / `btc` / `ltc` / `doge` / `bch` / `sol` / `ton` อายุใบแจ้งหนี้ขั้นต่ำ 10 นาที ไม่มี `is_refresh` และไม่มีการบล็อกกระเป๋าคงที่ โดยค่าเริ่มต้น Webhook มาจาก IP ที่เปลี่ยนไปเรื่อย ๆ หากคุณอนุญาตตาม IP ให้เปิด “Webhook จาก IP คงที่” ใน “นักพัฒนา › การเชื่อมต่อและคีย์” ของแดชบอร์ด แล้ว Webhook จะมาจาก `18.163.145.41` เท่านั้น — รายการอนุญาตเป็นเพียงชั้นเสริม ให้ตรวจ `sign` ต่อไป

มาจาก **NOWPayments** หรือ **Coinbase Commerce**? เรามี API ที่เข้ากันได้ทั้งสองแบบ — เปลี่ยน base URL และคีย์ ดู[คู่มือการย้ายระบบ](https://blockwallets.io/docs/migrate?lang=th)

### เครือข่ายและจำนวนเงิน

| เหรียญ | เครือข่าย | พารามิเตอร์ network | ขั้นต่ำ | เวลาที่ถึง |
| --- | --- | --- | --- | --- |
| USDT | TRON | `tron` | $1 | ~1 นาที |
| USDT | BNB Chain | `bsc` | $1 | ~1 นาที |
| USDC | BNB Chain | `bsc` | $1 | ~1 นาที |
| USDT | Ethereum | `eth` | $5 | ~1 นาที |
| USDC | Ethereum | `eth` | $5 | ~1 นาที |
| USDC | Base | `base` | $1 | ~1 นาที |
| USDT | Polygon | `polygon` | $1 | ~1 นาที |
| USDC | Polygon | `polygon` | $1 | ~1 นาที |
| USDT | Arbitrum | `arbitrum` | $1 | ~1 นาที |
| USDC | Arbitrum | `arbitrum` | $1 | ~1 นาที |
| USDT | Optimism | `optimism` | $1 | ~1 นาที |
| USDC | Optimism | `optimism` | $1 | ~1 นาที |
| USDT | Avalanche | `avalanche` | $1 | ~1 นาที |
| USDC | Avalanche | `avalanche` | $1 | ~1 นาที |
| USDT | X Layer | `xlayer` | $1 | ~1 นาที |
| USDC | X Layer | `xlayer` | $1 | ~1 นาที |
| USD1 | BNB Chain | `bsc` | $1 | ~1 นาที |
| FDUSD | BNB Chain | `bsc` | $1 | ~1 นาที |
| DAI | Ethereum | `eth` | $5 | ~1 นาที |
| DAI | Arbitrum | `arbitrum` | $1 | ~1 นาที |
| DAI | Base | `base` | $1 | ~1 นาที |
| BTC | Bitcoin | `btc` | $5 | ~10 นาที |
| LTC | Litecoin | `ltc` | $1 | ~3 นาที |
| DOGE | Dogecoin | `doge` | $1 | ~1 นาที |
| BCH | Bitcoin Cash | `bch` | $1 | ~10 นาที |
| TRX | TRON | `tron` | $1 | ~1 นาที |
| BNB | BNB Chain | `bsc` | $1 | ~1 นาที |
| ETH | Ethereum | `eth` | $5 | ~1 นาที |
| ETH | Base | `base` | $1 | ~1 นาที |
| ETH | Arbitrum | `arbitrum` | $1 | ~1 นาที |
| ETH | Optimism | `optimism` | $1 | ~1 นาที |
| POL | Polygon | `polygon` | $1 | ~1 นาที |
| AVAX | Avalanche | `avalanche` | $1 | ~1 นาที |
| OKB | X Layer | `xlayer` | $1 | ~1 นาที |
| USDT | Solana | `sol` | $1 | ~1 นาที |
| USDC | Solana | `sol` | $1 | ~1 นาที |
| SOL | Solana | `sol` | $1 | ~1 นาที |
| USDT | TON | `ton` | $1 | ~1 นาที |
| TON | TON | `ton` | $1 | ~1 นาที |

ค่าธรรมเนียม ERC-20 สูง ขั้นต่ำจึงเป็น $5 ค่าธรรมเนียม Bitcoin ก็ไม่ต่ำ ขั้นต่ำ $5 ที่เหลือทั้งหมด $1 ลูกค้าต้องโอนบนเครือข่ายที่หน้าชำระเงินแสดง — เงินที่โอนบนเครือข่ายอื่นจะไม่ถูกบันทึกอัตโนมัติ BTC / LTC / DOGE / BCH แสดง “ตรวจพบ” ทันทีที่อยู่ใน mempool และนับเมื่อได้รับการยืนยันครบ ธุรกรรมที่ถูกแทนที่ (RBF) หรือหลุดไปไม่นับ เหรียญประจำเครือข่าย (TRX, BNB, ETH, POL, AVAX, OKB, SOL, TON) เสนอราคาด้วยอัตราที่ล็อกไว้และบันทึกเป็นดอลลาร์สหรัฐเหมือน BTC / LTC / DOGE / BCH ให้ระบุทั้งเครือข่ายและเหรียญ: ใบแจ้งหนี้ `network: "bsc", to_currency: "BNB"` กระเป๋าคงที่ `network: "bsc", currency: "BNB"` หากระบุเพียงเครือข่าย ค่าเริ่มต้นคือ USDT บนเชนนั้น (USDC บน Base) การโอนที่ทำโดยสัญญา (multisig, การจ่ายออกเป็นชุด) ก็รับได้เช่นกัน บางเชนไม่มีแฮชธุรกรรมของมัน และ `txid` ใน Webhook เป็น `null`

### ข้อผิดพลาด

```json
{ "state": 1, "message": "amount must be a number like 10.28" }
```

| HTTP | สาเหตุที่พบบ่อย |
| --- | --- |
| 422 | พารามิเตอร์ขาดหรือรูปแบบผิด จำนวนเงินต่ำกว่าขั้นต่ำของเครือข่าย URL callback / เปลี่ยนเส้นทางไม่อยู่ในโดเมนที่คุณลงทะเบียน ระบุเหรียญ / เครือข่ายที่ไม่รองรับใน `/v1/payment` |
| 401 | merchant ผิด `sign` ผิด (`Invalid Sign.`) หรือ API key ถูกเปลี่ยนไปแล้ว |
| 404 | ไม่มีใบแจ้งหนี้นี้หรือไม่ใช่ของคุณ (`Payment not found`) หรือการจับคู่เหรียญ / เครือข่ายไม่รองรับใน `/v1/wallet` (`The service was not found`) |
| 503 | เครือข่ายใช้ไม่ได้ชั่วคราว — เลือกเครือข่ายอื่นหรืออย่าเลือกล่วงหน้า |

เมื่อลายเซ็นผิด (`Invalid Sign.`) การตอบกลับจะมีอ็อบเจกต์ `debug`: `body_base64` คือ base64 ของเนื้อหาคำขอที่เราได้รับ (เนื้อหาของคุณเอง ไม่มี API key) และ `body_bytes` คือความยาว เทียบกับ base64 ที่คุณเซ็น: หากต่างกัน เนื้อหาที่คุณส่งไม่ใช่สตริงที่คุณเซ็น (เฟรมเวิร์กของคุณ serialize ใหม่ พร็อกซีเปลี่ยนการเข้ารหัส มีบรรทัดใหม่ต่อท้าย) หากตรงกัน แสดงว่า API key ผิด วางใน[ตัวตรวจลายเซ็น](https://blockwallets.io/docs/sign?lang=th)เพื่อดูความต่างแรก

```json
{
  "state": 1,
  "message": "Invalid Sign.",
  "debug": {
    "body_base64": "eyJhbW91bnQiOiI0Mi4wMCIsImN1cnJlbmN5IjoiVVNEIiwi…",
    "body_bytes": 158,
    "sign_formula": "md5(body_base64 + API key)"
  }
}
```

### คำถามที่พบบ่อย

#### ลูกค้าเติมเงินจำนวนเท่าไรก็ได้ — ใช้วิธีไหน?

ใบแจ้งหนี้ ให้ลูกค้าใส่จำนวนเงินในหน้าเติมเงินของคุณ สร้างใบแจ้งหนี้ตามนั้น และบันทึกยอด `payment_amount_usd` เมื่อเงินเข้า ใช้กระเป๋าคงที่ก็ต่อเมื่อต้องการให้ลูกค้าเก็บที่อยู่เดียวและโอนเข้าซ้ำ ๆ

#### ถ้าลูกค้าจ่ายไม่ครบ?

ก่อนหมดอายุ ลูกค้าส่งส่วนที่ขาดที่หน้าชำระเงินได้ (หน้าแสดงว่ายังค้างเท่าไร สถานะ `wrong_amount_waiting` และหากเหลือเวลาน้อยกว่า 30 นาทีตอนจ่ายไม่ครบครั้งแรก กำหนดเวลาจะเลื่อนเป็นอีก 30 นาที) หากหมดอายุแล้วยังไม่ครบ ใบแจ้งหนี้เป็น `wrong_amount` และ `payment_amount_usd` ใน Webhook คือยอดที่ได้รับ ธุรกิจเติมเงินบันทึกยอดนั้นได้เลย

#### ถ้าลูกค้าจ่ายช้า หรือจ่ายสองครั้ง?

เงินที่เข้ามาหลังหมดอายุยังถูกบันทึกและแจ้งให้ทราบ เงินที่เข้ามาหลังใบแจ้งหนี้ชำระครบแล้วก็ถูกบันทึกเช่นกันและเห็นได้ในแดชบอร์ด

#### ถ้าลูกค้าโอนผิดเครือข่าย?

เช่น ใบแจ้งหนี้อยู่บน TRON แต่ลูกค้าส่งจาก BNB Chain: จะไม่ถูกบันทึกอัตโนมัติ — ติดต่อเรา แล้วเราจัดการด้วยมือ

#### มีค่าใช้จ่ายเท่าไร?

1% ของทุกการชำระที่ได้รับ ลดอัตโนมัติตามยอดของเดือนก่อน (0.9% ตั้งแต่ $50,000 0.8% ตั้งแต่ $100,000 0.7% ตั้งแต่ $250,000 0.6% ตั้งแต่ $500,000 และ0.5% ตั้งแต่ $1,000,000) ไม่มีค่ารายเดือนหรือค่าแรกเข้า ลูกค้าจ่ายค่าธรรมเนียมเครือข่ายตอนโอน หากต้องการผลักค่าธรรมเนียมให้ลูกค้า ตั้ง `subtract` ตอนสร้างใบแจ้งหนี้หรือเป็นค่าเริ่มต้นในแดชบอร์ด การถอนไม่มีค่าธรรมเนียมเพิ่ม ดู[ราคา](https://blockwallets.io/pricing?lang=th)

#### เงินถึงมือฉันเมื่อไร?

บันทึกเข้ายอดคงเหลือของคุณทันทีที่การชำระยืนยัน ขอถอนเข้ากระเป๋าของคุณเองที่ “เงิน › ยอดคงเหลือและการถอน” เมื่อเราอนุมัติแล้วเราจ่ายออก และธุรกรรมบนเชนปรากฏในประวัติการถอนของคุณ

คุณเปิดการถอนอัตโนมัติได้ด้วย: เมื่อยอดคงเหลือที่ใช้ได้ถึงจำนวนที่คุณตั้ง หรือวันละครั้งเวลา 00:00 UTC จะถอนยอดคงเหลือที่ใช้ได้ทั้งหมด การถอนอัตโนมัติตรวจสอบแบบเดียวกัน และทุกการเปลี่ยนการตั้งค่าจะส่งอีเมลแจ้งคุณ
