Hủy OneQR - Hủy QR động
Nội dung Markdown đầy đủ của trang tài liệu.
# 🎯 Hủy OneQR - Hủy QR động
## 📱 Tổng quan
Để hủy một mã QR động đã tạo, bạn gọi API **Cancel QR Code** của OneQR. Khi hủy QR, giao dịch sẽ không thể thanh toán được nữa.
---
## 🔌 Endpoint
```
POST http://api.pay2s.vn/api/{bank_code}/v1/qr/cancel
```
| Tham số | Ví dụ | Mô tả |
|--------|-------|-------|
| `{bank_code}` | `vcb` | Mã ngân hàng (vcb = Vietcombank, acb = ACB Bank, ...) |
---
## 📤 Request
### Headers
```json
{
"Content-Type": "application/json",
"Authorization": "Bearer <token>"
}
```
> **Lưu ý**: `<token>` là Bearer token được cấp từ Pay2S
### Body Parameters (JSON)
| Tham số | Loại | Bắt buộc | Mô tả |
|--------|------|---------|-------|
| `orderId` | String | ✓ | ID đơn hàng trong hệ thống của bạn |
| `traceNumber` | String | ✓ | Mã định danh QR được trả về từ API tạo QR |
### ✅ Ví dụ Request (cURL)
```bash
curl --location 'http://api.pay2s.vn/api/vcb/v1/qr/cancel' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_BEARER_TOKEN' \
--data '{
"orderId": "123456",
"traceNumber": "QRPP2S26159194HHKZE"
}'
```
---
## 📥 Response
### ✅ Thành công (200 OK)
```json
{
"success": true,
"message": "QR transaction cancelled successfully",
"data": {
"transactionId": "da58fde344a1e0c9280207e1143c6f40",
"orderId": "DEMO17916599748852455",
"status": "cancelled",
"cancelResponse": {
"code": "00",
"message": "Succeed",
"data": {
"subCode": "00",
"subMessage": "Succeed",
"requestId": "0368e7f9-902c-4bd3-adb6-c5766e328856",
"checksum": "3E808EBC44F716562EE1290FF9C2A5F0",
"vcbResponse": {
"code": "00",
"message": "Succeed",
"requestId": "0368e7f9-902c-4bd3-adb6-c5766e328856",
"subCode": "00",
"subMessage": "Succeed",
"serverTime": "15:46:33 08/06/2026",
"nodeOut": "10.1.60.186",
"nodeIn": "",
"operation": "CancelInvoice",
"success": true,
"idQrCode": "31928425",
"checksum": "25B3AFCB0ABA8EF2DADE66255156653C"
},
"success": true
}
}
}
}
```
| Trường | Mô tả |
|--------|-------|
| `success` | Trạng thái: `true` = Hủy thành công |
| `message` | Mô tả: `QR transaction cancelled successfully` |
| `status` | Trạng thái: `cancelled` = QR đã bị hủy |
| `transactionId` | Mã giao dịch duy nhất |
| `orderId` | ID đơn hàng được hủy |
---
## 💻 Code mẫu - Hủy QR
::: code-group
```php [PHP]
<?php
$bearerToken = "YOUR_BEARER_TOKEN";
$url = "http://api.pay2s.vn/api/vcb/v1/qr/cancel";
$data = [
'orderId' => "123456",
'traceNumber' => "QRPP2S26159194HHKZE"
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $bearerToken,
"Content-Type: application/json"
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['success'] === true) {
$orderId = $result['data']['orderId'];
$status = $result['data']['status'];
echo "Order " . $orderId . " cancelled with status: " . $status;
} else {
echo "Error: " . $result['message'];
}
curl_close($ch);
?>
```
```javascript [Node.js]
const axios = require('axios');
const bearerToken = "YOUR_BEARER_TOKEN";
const payload = {
orderId: "123456",
traceNumber: "QRPP2S26159194HHKZE"
};
axios.post("http://api.pay2s.vn/api/vcb/v1/qr/cancel", payload, {
headers: {
"Authorization": `Bearer ${bearerToken}`,
"Content-Type": "application/json"
}
})
.then(response => {
if (response.data.success === true) {
console.log("Order cancelled:", response.data.data.orderId);
console.log("Status:", response.data.data.status);
} else {
console.error("Error:", response.data.message);
}
})
.catch(err => console.error(err));
```
```python [Python]
import requests
import json
bearer_token = "YOUR_BEARER_TOKEN"
payload = {
'orderId': "123456",
'traceNumber': "QRPP2S26159194HHKZE"
}
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json"
}
response = requests.post("http://api.pay2s.vn/api/vcb/v1/qr/cancel",
data=json.dumps(payload),
headers=headers)
result = response.json()
if result['success'] == True:
print("Order cancelled:", result['data']['orderId'])
print("Status:", result['data']['status'])
else:
print("Error:", result['message'])
```
:::
---
## ⚡ Best Practices
1. **Validate parameters**: Kiểm tra `orderId` và `traceNumber` không rỗng
2. **Error handling**: Kiểm tra `success` trước xử lý `data`
3. **Timing**: Chỉ hủy QR khi khách hàng từ chối thanh toán
4. **Status check**: Không hủy QR đã được thanh toán
5. **Retry logic**: Nếu request fail, retry sau 2-3 giây
6. **Update database**: Cập nhật status = 'cancelled' trong database
7. **Trace number**: Lưu trữ traceNumber để audit log
8. **User notification**: Thông báo cho khách hàng khi QR bị hủy
9. **Timeout handling**: Đặt timeout hợp lý (30-60 giây)
10. **Logging**: Log toàn bộ cancel request/response
---
## 📌 Luồng hủy QR
```
1. Khách từ chối thanh toán → 2. Hệ thống gọi API hủy QR →
3. Gửi orderId + traceNumber → 4. Pay2S xác nhận hủy →
5. QR không thể scan nữa → 6. Cập nhật status = cancelled →
7. Thông báo khách hàng
```
---
> **Tiếp theo**: Xem [Tạo OneQR](/oneqr/khoi-tao-oneqr) để tạo QR mới hoặc [Webhook](/webhook/tai-lieu-ky-thuat.html) để nhận thông báo thanh toán
## Request và response đối chiếu ngày 11/10/2026
Các mẫu dưới đây giữ cấu trúc trường và kiểu dữ liệu. Khóa, chữ ký, URL phiên đã được thay bằng placeholder; danh sách chỉ giữ tối đa hai phần tử và dữ liệu ảnh/PDF/XML dài được rút gọn. Không sao chép placeholder để gọi API thật.
### OneQR · Hủy QR
<div class="doc-api-actions" data-doc-api-actions><a class="try-button" data-doc-playground href="/playground/?api=oneqr-cancel">Thử API trong Playground ↗</a><a class="try-button experience-button" data-doc-experience hidden>Trải nghiệm ↗</a></div>
**Mô phỏng; chưa xác minh với API nhà cung cấp.** Giữ mô phỏng theo cấu hình demo. Chưa có API OneQR thật để xác minh lại hợp đồng nhà cung cấp.
`POST /api/{bank_code}/v1/qr/cancel`
Body:
```json
{
"transactionId": "da58fde344a1e0c9280207e1143c6f40"
}
```
HTTP 200. Response:
```json
{
"success": true,
"message": "QR transaction cancelled successfully",
"data": {
"transactionId": "da58fde344a1e0c9280207e1143c6f40",
"orderId": "DEMO17916599748852455",
"status": "cancelled",
"cancelResponse": {
"code": "00",
"message": "Succeed",
"data": {
"subCode": "00",
"subMessage": "Succeed",
"requestId": "0368e7f9-902c-4bd3-adb6-c5766e328856",
"checksum": "3E808EBC44F716562EE1290FF9C2A5F0",
"vcbResponse": {
"code": "00",
"message": "Succeed",
"requestId": "0368e7f9-902c-4bd3-adb6-c5766e328856",
"subCode": "00",
"subMessage": "Succeed",
"serverTime": "15:46:33 08/06/2026",
"nodeOut": "10.1.60.186",
"nodeIn": "",
"operation": "CancelInvoice",
"success": true,
"idQrCode": "31928425",
"checksum": "25B3AFCB0ABA8EF2DADE66255156653C"
},
"success": true
}
}
}
}
```