# Payment API

> สร้างและจัดการเซสชันการชำระเงินด้วยคริปโตเคอร์เรนซีผ่าน Payment API ของ 2328.io

Payment API ให้คุณสร้างเซสชันการชำระเงิน นำลูกค้าไปยังหน้า checkout ที่โฮสต์ไว้ และติดตามสถานะการชำระเงินได้

## สร้างการชำระเงิน

สร้างเซสชันการชำระเงินและคืน URL สำหรับให้ลูกค้าชำระเงิน

### พารามิเตอร์ของคำขอ

| Field | Type | Required | Description | Values |
|-------|------|----------|-------------|--------|
| `amount` | decimal | yes | จำนวนเงินที่ชำระในสกุลเงินนั้น เช่น `100.00` |  |
| `currency` | string | yes | สกุลเงิน fiat (USD, EUR, RUB, …) หรือคริปโตเคอร์เรนซี (USDT, TRX, BTC, …) | `USD`, `EUR`, `RUB`, `KZT`, `UAH`, `UZS`, `USDT`, `USDC`, `BTC`, `ETH`, `GRAM`, `SOL`, `TRX`, `BNB`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `order_id` | string | yes | order ID ของคุณ เช่น `ORDER-12345` (สูงสุด 128 ตัวอักษร) |  |
| `to_currency` | string | no | คริปโตเคอร์เรนซีที่เลือกไว้ล่วงหน้า | `USDT`, `USDC`, `BTC`, `ETH`, `GRAM`, `SOL`, `TRX`, `BNB`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `network` | string | no\* | รหัสเครือข่าย (ต้องระบุเมื่อตั้งค่า `to_currency` หรือ `currency` เป็นคริปโตเคอร์เรนซี) | `TRX-TRC20`, `ETH-ERC20`, `BASE`, `BSC-BEP20`, `AVAX-C`, `POL-MATIC`, `TON`, `SOL`, `BTC`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `url_return` | string | no | URL redirect หลังการชำระเงิน เช่น `https://your-site.com/return` |  |
| `url_success` | string | no | ทางเลือกแทน `url_return` |  |
| `url_callback` | string | yes | URL สำหรับการแจ้งเตือน Webhook เช่น `https://your-site.com/webhook` |  |
| `invite_code` | string | no | โค้ดผู้แนะนำ |  |
| `fee_split` | decimal | no | สัดส่วนค่าธรรมเนียมผู้ค้าที่ส่งต่อให้ผู้ชำระ 0–100 (%) 0 = ผู้ค้าจ่ายเต็ม, 100 = ผู้ชำระจ่ายเต็ม ค่านี้จะลบล้างการตั้งค่าระดับโปรเจกต์ **ตัวอย่าง: `30`** (ผู้ชำระรับภาระ 30% ของค่าธรรมเนียม) |  |
| `price_markup` | decimal | no | บวกเพิ่มหรือส่วนลดบนยอดใบแจ้งหนี้ −99 ถึง 100 (%) ค่านี้จะลบล้างการตั้งค่าระดับโปรเจกต์ **ตัวอย่าง: `5`** (+5%) หรือ `-10` (ส่วนลด 10%) |  |
| `description` | string | no | คำอธิบายใบแจ้งหนี้ (สูงสุด 200 ตัวอักษร) แสดงให้ผู้ชำระเห็นบนหน้าชำระเงิน **ตัวอย่าง: `Premium plan — Order #12345`** |  |
| `ttl_seconds` | int | no | อายุของใบแจ้งหนี้เป็นวินาที ตั้งแต่ `300` (5 นาที) ถึง `86400` (24 ชั่วโมง) เมื่อพ้นเวลานี้ใบแจ้งหนี้จะหมดอายุและชำระไม่ได้อีก ค่าเริ่มต้น: `3600` (1 ชั่วโมง) **ตัวอย่าง: `3600`** |  |

### การตอบกลับ

```json
{
  "state": 0,
  "result": {
    "uuid": "abc123-def456-...",
    "order_id": "ORDER-12345",
    "amount": "100.00",
    "currency": "USD",
    "amount_usd": "100.00",
    "exchange_rate": null,
    "url": "https://2328.io/pay/abc123-def456-...",
    "tg_deeplink": "https://t.me/my2328bot?start=pay_abc123-def456-...",
    "expires_at": "2026-01-11T21:00:00Z",
    "created_at": "2026-01-11T20:00:00Z",
    "payer_currency": "USDT",
    "payer_amount": "100.50",
    "network": "TRX-TRC20",
    "address": "TXYZabc123...",
    "payment_status": "check",
    "txid": null,
    "payment_amount": null,
    "qr": "data:image/png;base64,iVBORw0..."
  }
}
```

- นำลูกค้าไปยัง `result.url` เพื่อดำเนินการชำระเงินให้เสร็จสมบูรณ์
- `tg_deeplink` — ดีพลิงก์บอท Telegram สำหรับชำระเงินผ่าน Telegram MiniApp
- `qr` — QR code ที่เข้ารหัส base64 (data URI) ของที่อยู่ฝากเงิน จะปรากฏเมื่อมีการกำหนดที่อยู่แล้ว (เมื่อตั้งค่า `network` ร่วมกับ `to_currency` หรือเมื่อ `currency` เป็นคริปโตเคอร์เรนซี); ในกรณีอื่นจะเป็น `null`
- `txid`, `payment_amount` — เป็น `null` จนกว่าลูกค้าจะชำระเงิน จะถูกเติมค่าเมื่อระบบตรวจพบธุรกรรมบนเชน รับฟัง Webhook `payment_status: paid` เพื่อรู้เวลา
- `exchange_rate` — เป็น `null` หากยังใช้การแปลงสกุลไม่ได้ (เช่น ยังไม่ล็อกอัตรา fiat → crypto) จะถูกเติมค่าเมื่อเลือกสกุลเงินผู้ชำระแล้ว

> Use your project UUID and the endpoint-appropriate API key from the merchant dashboard.

#### Interactive request: `POST /v1/payment`
  - `amount` (decimal, required)
  - `currency` (enum, required): USD,EUR,RUB,KZT,UAH,UZS,USDT,USDC,BTC,ETH,GRAM,SOL,TRX,BNB,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `order_id` (string, required)
  - `to_currency` (enum): USDT,USDC,BTC,ETH,GRAM,SOL,TRX,BNB,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `network` (enum): TRX-TRC20,ETH-ERC20,BASE,BSC-BEP20,AVAX-C,POL-MATIC,TON,SOL,BTC,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `url_return` (string)
  - `url_success` (string)
  - `url_callback` (string, required)
  - `invite_code` (string)
  - `fee_split` (decimal)
  - `price_markup` (decimal)
  - `description` (string)
  - `ttl_seconds` (integer)

## การชำระเงินแบบโฮสต์, H2H, และจำนวนคริปโตที่แน่นอน

จุดเชื่อมต่อเดียวกันรองรับรูปแบบใบแจ้งหนี้สามแบบ เลือกแบบใดแบบหนึ่งอย่างตั้งใจ; อย่าผสมความหมายของจำนวนเงิน

### การชำระเงินแบบโฮสต์ที่ผู้จ่ายเลือกได้

ส่ง `amount`, `currency`, `order_id`, และ `url_callback` แต่เว้น `to_currency` และ `network` การตอบกลับมี `result.url`; `address`, `qr`, และบางครั้งฟิลด์ของผู้จ่ายจะยังคง `null` จนกว่าผู้จ่ายจะเลือกทิศทางบนหน้าที่โฮสต์

```json
{
  "amount": "125.00",
  "currency": "EUR",
  "order_id": "ORDER-2026-1042",
  "url_callback": "https://merchant.example/webhooks/2328",
  "url_return": "https://merchant.example/orders/ORDER-2026-1042"
}
```

### ใบแจ้งหนี้ H2H แบบที่อยู่ตรง

ส่งทั้ง `to_currency` และ `network` 2328.io สร้างอินวอยซ์บนบล็อกเชนในระหว่างการเรียก API ดังนั้นการตอบสนองที่สำเร็จสามารถแสดงภายในหน้าเช็คเอาท์ของคุณโดยไม่ต้องเปลี่ยนเส้นทางลูกค้า

```json
{
  "amount": "100.00",
  "currency": "USD",
  "to_currency": "USDT",
  "network": "TRX-TRC20",
  "order_id": "ORDER-2026-1043",
  "url_callback": "https://merchant.example/webhooks/2328"
}
```

แสดงค่าต่าง ๆ เหล่านี้ตามที่ส่งกลับมาโดยตรง:

- `payer_amount` และ `payer_currency` — คำสั่งชำระเงิน;
- `network` และ `address` — จุดหมายปลายทางเดียวสำหรับอินวอยซ์นี้;
- `qr` — URI ของข้อมูลสำหรับที่อยู่เดียวกัน;
- `expires_at` — กำหนดเวลาสำหรับอินวอยซ์;
- `url` — สำรองที่โฮสต์ที่เป็นประโยชน์เมื่อตัวเช็คเอาท์แบบกำหนดเองไม่สามารถทำงานได้

> **DANGER:** อย่าสร้างหรือแทนที่ที่อยู่, ใช้ที่อยู่จากใบแจ้งหนี้อื่นซ้ำ, หรือคำนวณ `payer_amount` จากราคาสปอตสาธารณะ การตอบกลับของ API เป็นข้อกำหนดที่เชื่อถือได้

### ใบแจ้งหนี้สำหรับจำนวนคริปโตที่แน่นอน

วางสกุลเงินคริปโตใน `currency` เมื่อใบแจ้งหนี้นั้นเองมีหน่วยเป็นคริปโต:

```json
{
  "amount": "25.000000",
  "currency": "USDT",
  "network": "TRX-TRC20",
  "order_id": "ORDER-2026-1044",
  "url_callback": "https://merchant.example/webhooks/2328"
}
```

มูลค่าคริปโตที่ร้องขอถูกเก็บไว้ใน `payer_currency` / `payer_amount` บริการยังสามารถรักษามูลค่าเป็น USD ภายในสำหรับการบัญชีและช่องอัตรา; อย่าแทนคำสั่งคริปโตที่แน่นอนด้วยมูลค่านั้น เก็บสตริงทศนิยมที่ส่งกลับ รวมถึงความแม่นยำปลายทศนิยม

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

## Idempotency และการลองใหม่

`order_id` จะถูกจำกัดอยู่ที่โครงการพ่อค้า (merchant) ที่ผ่านการตรวจสอบสิทธิ์และทำหน้าที่เป็นคีย์ idempotency ของการสร้าง หากมีการชำระเงินอยู่แล้ว API จะส่งคืน session นั้นพร้อมกับ `state: 0`

> **WARNING:** การลองใหม่ด้วย `order_id` เดิม **not** หมายถึง “อัปเดตใบแจ้งหนี้นี้” จำนวนเงิน สกุลเงิน การเรียกกลับ (callback) การตั้ง markup ระยะเวลา (TTL) หรือทิศทางที่เปลี่ยนแปลงอาจถูกละเว้นเพราะ session ที่มีอยู่ถูกส่งคืน เก็บคำขอครั้งแรกไว้และปฏิเสธการลองใหม่ที่ขัดแย้งในแอปพลิเคชันของคุณเอง

อัลกอริทึมการสร้างที่แนะนำ:

1. แทรกความพยายามชำระเงินภายในท้องถิ่นและ `order_id` ที่ไม่ซ้ำกันของคุณในธุรกรรมฐานข้อมูลเดียว
2. ส่งคำขอ API ที่ลงนามแล้ว
3. บันทึก `uuid` ที่ส่งกลับและการตอบกลับทั้งหมด
4. หากผลลัพธ์ HTTP สูญหาย ให้ลองทำคำขอเดียวกันอีกครั้ง หรือสอบถาม `/v1/payment/info` ผ่าน `order_id`
5. อย่าสร้างคำสั่งซื้อท้องถิ่นที่สองเพียงเพราะคำขอข้างต้นหมดเวลา

## กรณีขอบเขตการชำระเงิน

| สถานการณ์ | การจัดการที่ถูกต้อง |
|-----------|------------------|
| `address` / `qr` คือ `null` | ทิศทางของผู้จ่ายเงินยังไม่ได้รับการเริ่มต้น ให้เปลี่ยนเส้นทางไปยัง `url` หรือสร้างใบแจ้งหนี้ H2H ที่ระบุอย่างถูกต้องใหม่พร้อม `order_id` ใหม่ |
| ข้อผิดพลาดการตรวจสอบ HTTP `400` | อ่านระดับฟิลด์ `errors`; อย่าลองใหม่โดยใช้ข้อมูลเดิม |
| HTTP `429` | ลองใหม่ด้วยการหน่วงเวลากำลังสองแบบสุ่มและใช้ `order_id` เดิม |
| HTTP `503` / `direction_disabled` | รีเฟรช `/v1/directions`; ซ่อนทิศทางชั่วคราวหรือลองใหม่ในภายหลัง |
| คำขอของลูกค้าหมดเวลา | พิจารณาผลลัพธ์เป็นไม่ทราบ สอบถามโดยใช้ `order_id` ก่อนสร้างสิ่งอื่นใด |
| `underpaid_check` | เก็บเหตุการณ์บางส่วนและรอการเติมเงินหรือสถานะภายหลัง อย่าบันทึกเครดิตซ้ำเมื่อมี txids เพิ่มเข้ามา |
| `underpaid` | สถานะการชำระเงินไม่ครบถ้วนสุดท้าย ใช้นโยบายการปฏิบัติ/ตรวจสอบด้วยตนเองที่คุณตั้งค่าไว้กับจำนวนเงินที่ถูกบันทึกจริง |
| `overpaid` | การชำระเงินสำเร็จพร้อมเงินเกิน ปฏิบัติอย่างไม่ซ้ำซ้อนและเก็บจำนวนเงินจริงสำหรับนโยบายการปรับบัญชี/คืนเงิน |
| `aml_lock` | อย่าปฏิบัติหรือตัดเงินโดยอัตโนมัติ ส่งไปยังเวิร์กโฟลว์การปฏิบัติตาม/ฝ่ายสนับสนุน |
| `cancel` | ใบแจ้งหนี้หมดอายุหรือถูกยกเลิก อย่าสรุปว่าการโอนบนเชนช้าเป็นไปไม่ได้ ปรับบัญชีเหตุการณ์ใด ๆ ที่เกิดขึ้นในภายหลังร่วมกับฝ่ายสนับสนุน |

URL ที่ส่งกลับจากเบราว์เซอร์เป็นเพียงการนำทางเท่านั้น ลูกค้าสามารถเปิดมันโดยไม่ต้องจ่ายเงิน ปิดมันหลังจากชำระเงิน หรือเล่นซ้ำในภายหลัง ได้ก็ต่อเมื่อมีสถานะ API/webhook ที่ได้รับการยืนยันเท่านั้นที่จะสามารถชำระคำสั่งซื้อของร้านค้าได้

## ข้อมูลการชำระเงิน

ดูสถานะการชำระเงินปัจจุบันด้วย `uuid` หรือ `order_id`

### พารามิเตอร์ของคำขอ

| Field | Type | Required | Description | Values |
|-------|------|----------|-------------|--------|
| `uuid` | string | yes\* | UUID ของการชำระเงิน (จาก `result.uuid` ตอนสร้าง) |  |
| `order_id` | string | yes\* | order ID ของคุณ |  |

> **INFO:** ต้องระบุ `uuid` หรือ `order_id` อย่างน้อยหนึ่งค่า

#### Interactive request: `POST /v1/payment/info`
  - `uuid` (string)
  - `order_id` (string)

## รายการการชำระเงิน

ดูรายการการชำระเงินทั้งหมดพร้อมการกรองและแบ่งหน้า

### พารามิเตอร์ของคำขอ

| Field | Type | Required | Description | Values |
|-------|------|----------|-------------|--------|
| `status` | string | no | กรองตามสถานะการชำระเงิน (ดู [References](/docs/references)) | `pending`, `check`, `paid`, `underpaid_check`, `underpaid`, `overpaid`, `cancel` |
| `date_from` | date | no | วันที่เริ่มต้น (YYYY-MM-DD) เช่น `2026-01-01` |  |
| `date_to` | date | no | วันที่สิ้นสุด (YYYY-MM-DD) เช่น `2026-01-31` |  |
| `page` | int | no | หมายเลขหน้า ค่าเริ่มต้น `1` |  |
| `per_page` | int | no | จำนวนรายการต่อหน้า ค่าเริ่มต้น `15` สูงสุด `5000` |  |

#### Interactive request: `POST /v1/payment/list`
  - `status` (enum): pending,check,paid,underpaid_check,underpaid,overpaid,cancel
  - `date_from` (string)
  - `date_to` (string)
  - `page` (integer)
  - `per_page` (integer)