# Payment API

> Tạo và quản lý các phiên thanh toán tiền điện tử với Payment API của 2328.io.

Payment API cho phép bạn tạo phiên thanh toán, chuyển hướng khách hàng đến trang checkout được hosted và theo dõi trạng thái thanh toán.

## Tạo thanh toán

Tạo một phiên thanh toán và trả về URL để khách hàng thanh toán.

### Tham số yêu cầu

| Field | Type | Required | Description | Values |
|-------|------|----------|-------------|--------|
| `amount` | decimal | yes | Số tiền thanh toán theo đơn vị tiền tệ, ví dụ `100.00` |  |
| `currency` | string | yes | Tiền pháp định (USD, EUR, RUB, …) hoặc tiền điện tử (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 | ID đơn hàng của bạn, ví dụ `ORDER-12345` (tối đa 128 ký tự) |  |
| `to_currency` | string | no | Tiền điện tử được chọn trước | `USDT`, `USDC`, `BTC`, `ETH`, `GRAM`, `SOL`, `TRX`, `BNB`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `network` | string | no\* | Mã mạng (bắt buộc nếu `to_currency` được đặt hoặc `currency` là tiền điện tử) | `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 chuyển hướng sau khi thanh toán, ví dụ `https://your-site.com/return` |  |
| `url_success` | string | no | Phương án thay thế cho `url_return` |  |
| `url_callback` | string | yes | URL nhận thông báo webhook, ví dụ `https://your-site.com/webhook` |  |
| `invite_code` | string | no | Mã người giới thiệu |  |
| `fee_split` | decimal | no | Tỷ lệ phí merchant chuyển sang cho người trả, 0–100 (%). 0 = merchant trả toàn bộ, 100 = người trả gánh toàn bộ. Ghi đè cài đặt cấp project. **Ví dụ: `30`** (người trả gánh 30% phí). |  |
| `price_markup` | decimal | no | Phụ phí hoặc chiết khấu trên số tiền hóa đơn, −99 đến 100 (%). Ghi đè cài đặt cấp project. **Ví dụ: `5`** (+5%) hoặc `-10` (giảm 10%). |  |
| `description` | string | no | Mô tả hóa đơn tùy chọn (tối đa 200 ký tự). Hiển thị cho người trả trên trang thanh toán. **Ví dụ: `Premium plan — Order #12345`**. |  |
| `ttl_seconds` | int | no | Thời gian sống của hóa đơn tính bằng giây, từ `300` (5 phút) đến `86400` (24 giờ). Sau khoảng thời gian này hóa đơn hết hạn và không thể thanh toán được nữa. Mặc định: `3600` (1 giờ). **Ví dụ: `3600`**. |  |

### Phản hồi

```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..."
  }
}
```

- Chuyển hướng khách hàng đến `result.url` để hoàn tất thanh toán.
- `tg_deeplink` — deeplink Telegram bot để thanh toán qua Telegram MiniApp.
- `qr` — QR code mã hóa Base64 (data URI) của địa chỉ nạp tiền. Có giá trị khi địa chỉ đã được gán (khi `network` được đặt cùng với `to_currency`, hoặc khi `currency` là tiền điện tử); ngược lại là `null`.
- `txid`, `payment_amount` — `null` cho đến khi khách hàng trả tiền. Được điền vào sau khi giao dịch được phát hiện trên chuỗi. Lắng nghe webhook `payment_status: paid` để biết thời điểm.
- `exchange_rate` — `null` nếu việc quy đổi chưa áp dụng được (ví dụ tỷ giá fiat → crypto chưa được chốt). Được điền vào khi đã chọn được tiền của người trả.

> 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)

## Thanh toán được lưu trữ, H2H, và số lượng tiền điện tử chính xác

Cùng một điểm cuối hỗ trợ ba kiểu hóa đơn khác nhau. Chọn một cách có chủ đích; không trộn lẫn ngữ nghĩa số lượng của chúng.

### Thanh toán được lưu trữ với lựa chọn người thanh toán

Gửi `amount`, `currency`, `order_id`, và `url_callback`, nhưng bỏ qua `to_currency` và `network`. Phản hồi chứa `result.url`; `address`, `qr`, và đôi khi các trường người thanh toán vẫn `null` cho đến khi người thanh toán chọn hướng trên trang được lưu trữ.

```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"
}
```

### Hóa đơn H2H trực tiếp

Gửi cả `to_currency` và `network`. 2328.io tạo hóa đơn blockchain trong quá trình gọi API, vì vậy một phản hồi thành công có thể được hiển thị trong trang thanh toán của bạn mà không cần chuyển hướng khách hàng.

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

Hiển thị các giá trị này chính xác như được trả về:

- `payer_amount` và `payer_currency` — hướng dẫn thanh toán;
- `network` và `address` — điểm đến duy nhất cho hóa đơn này;
- `qr` — một URI dữ liệu cho cùng địa chỉ;
- `expires_at` — hạn chót của hóa đơn;
- `url` — một phương án dự phòng hữu ích được lưu trữ khi trang thanh toán tùy chỉnh không thể hoàn tất.

> **DANGER:** Không bao giờ tạo hoặc thay thế một địa chỉ, tái sử dụng địa chỉ từ hóa đơn khác, hoặc tính toán `payer_amount` từ giá công khai. Phản hồi API là có thẩm quyền.

### Hóa đơn cho một số tiền crypto chính xác

Đặt tiền điện tử vào `currency` khi chính hóa đơn được định giá bằng crypto:

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

Giá trị crypto yêu cầu được giữ nguyên trong `payer_currency` / `payer_amount`. Dịch vụ cũng có thể duy trì giá trị USD nội bộ cho mục kế toán và trường tỷ giá; không thay thế hướng dẫn crypto chính xác đó bằng giá trị này. Giữ nguyên chuỗi số thập phân trả về, bao gồm cả số thập phân cuối.

Đối với một loại tiền điện tử chỉ có một mạng được hỗ trợ, mạng có thể được chọn tự động. Vẫn nên cung cấp `network` một cách rõ ràng để có sự tích hợp xác định. Đối với các tài sản đa mạng như stablecoin, luôn luôn gửi nó.

## Tính đơn nhất và các lần thử lại

`order_id` áp dụng cho dự án thương gia đã xác thực và đóng vai trò như khóa đơn nhất khi tạo. Nếu một khoản thanh toán đã tồn tại, API sẽ trả về phiên đó cùng với `state: 0`.

> **WARNING:** Một lần thử lại với cùng `order_id` có **not** nghĩa là “cập nhật hóa đơn này.” Các trường thay đổi về số tiền, tiền tệ, callback, đánh dấu thêm, TTL hoặc hướng có thể bị bỏ qua vì phiên hiện tại được trả về. Lưu giữ yêu cầu đầu tiên và từ chối các lần thử lại xung đột trong ứng dụng của bạn.

Thuật toán tạo được khuyến nghị:

1. Chèn nỗ lực thanh toán cục bộ của bạn và `order_id` duy nhất vào một giao dịch cơ sở dữ liệu.
2. Gửi yêu cầu API đã ký.
3. Lưu lại `uuid` được trả về và phản hồi đầy đủ.
4. Nếu kết quả HTTP bị mất, thử lại yêu cầu giống hệt hoặc truy vấn `/v1/payment/info` bằng `order_id`.
5. Không bao giờ tạo đơn hàng cục bộ thứ hai chỉ vì yêu cầu từ phía trên bị hết thời gian.

## Các trường hợp thanh toán đặc biệt

| Tình huống | Xử lý chính xác |
|-----------|------------------|
| `address` / `qr` là `null` | Hướng người trả tiền chưa được khởi tạo. Chuyển hướng đến `url`, hoặc tạo hóa đơn H2H mới được chỉ định chính xác với một `order_id` mới. |
| Lỗi xác thực HTTP `400` | Đọc trường cấp `errors`; không thử lại với dữ liệu đầu vào không thay đổi. |
| HTTP `429` | Thử lại với độ trễ lũy thừa kèm nhiễu (jittered exponential backoff) và giữ nguyên `order_id`. |
| HTTP `503` / `direction_disabled` | Làm mới `/v1/directions`; tạm thời ẩn hướng hoặc thử lại sau. |
| Yêu cầu của client hết thời gian chờ | Xem kết quả là không xác định. Tra cứu bằng `order_id` trước khi tạo bất cứ thứ gì khác. |
| `underpaid_check` | Lưu sự kiện một phần và chờ nạp thêm hoặc trạng thái sau. Không ghi có hai lần khi có thêm txid. |
| `underpaid` | Trạng thái thanh toán thiếu cuối cùng. Áp dụng chính sách hoàn thành/kiểm tra thủ công đã cấu hình cho số tiền thực tế được ghi có. |
| `overpaid` | Thanh toán thành công với số dư dư thừa. Thực hiện một cách idempotent và giữ số tiền thực tế để đối chiếu/chính sách hoàn trả. |
| `aml_lock` | Không thực hiện hoặc giải phóng tiền tự động; chuyển hướng đến quy trình tuân thủ/hỗ trợ. |
| `cancel` | Hóa đơn đã hết hạn hoặc bị hủy. Không suy luận rằng việc chuyển khoản chậm trên chuỗi là không thể; đối chiếu bất kỳ sự kiện sau này nào với bộ phận hỗ trợ. |

URL trả về của trình duyệt chỉ để điều hướng. Khách hàng có thể mở nó mà không cần thanh toán, đóng nó sau khi thanh toán, hoặc phát lại sau. Chỉ trạng thái API/webhook đã được xác minh mới có thể xử lý đơn hàng của thương nhân.

## Thông tin thanh toán

Lấy trạng thái thanh toán hiện tại theo `uuid` hoặc `order_id`.

### Tham số yêu cầu

| Field | Type | Required | Description | Values |
|-------|------|----------|-------------|--------|
| `uuid` | string | yes\* | UUID của thanh toán (lấy từ `result.uuid` khi tạo) |  |
| `order_id` | string | yes\* | ID đơn hàng của bạn |  |

> **INFO:** Phải cung cấp ít nhất một trong `uuid` hoặc `order_id`.

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

## Danh sách thanh toán

Lấy danh sách tất cả thanh toán có hỗ trợ lọc và phân trang.

### Tham số yêu cầu

| Field | Type | Required | Description | Values |
|-------|------|----------|-------------|--------|
| `status` | string | no | Lọc theo trạng thái thanh toán (xem [References](/docs/references)) | `pending`, `check`, `paid`, `underpaid_check`, `underpaid`, `overpaid`, `cancel` |
| `date_from` | date | no | Ngày bắt đầu (YYYY-MM-DD), ví dụ `2026-01-01` |  |
| `date_to` | date | no | Ngày kết thúc (YYYY-MM-DD), ví dụ `2026-01-31` |  |
| `page` | int | no | Số trang, mặc định `1` |  |
| `per_page` | int | no | Số mục mỗi trang, mặc định `15`, tối đa `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)