Kiểm tra OneQR - Xem chi tiết QR
Nội dung Markdown đầy đủ của trang tài liệu.
# 🔍 Kiểm tra OneQR - Xem chi tiết QR
## 📱 Tổng quan
Để kiểm tra chi tiết một mã QR đã tạo, bạn gọi API **Retrieve QR Transaction** của OneQR. API này trả về đầy đủ thông tin giao dịch và trạng thái thanh toán.
---
## 🔌 Endpoint
```
GET http://api.pay2s.vn/api/{bank_code}/v1/qr/transactions/{transactionId}
```
| Tham số | Ví dụ | Mô tả |
|--------|-------|-------|
| `{bank_code}` | `vcb` | Mã ngân hàng (vcb = Vietcombank, acb = ACB Bank, ...) |
| `{transactionId}` | `0e907bd2-74d0-4c49-96ba-e64660736a2a` | Mã truy vấn (từ response tạo QR) |
---
## 📤 Request
### Headers
```json
{
"Authorization": "Bearer <token>"
}
```
> **Lưu ý**: `<token>` là Bearer token được cấp từ Pay2S
### ✅ Ví dụ Request (cURL)
```bash
curl --location 'http://api.pay2s.vn/api/vcb/v1/qr/transactions/0e907bd2-74d0-4c49-96ba-e64660736a2a' \
--header 'Authorization: Bearer YOUR_BEARER_TOKEN'
```
---
## 📥 Response
### ✅ Thành công (200 OK)
```json
{
"success": true,
"message": "QR transaction retrieved successfully",
"data": {
"transactionId": "da58fde344a1e0c9280207e1143c6f40",
"merchantId": "DEMO_MERCHANT",
"terminalId": "DEMO_TERMINAL",
"orderId": "DEMO17916599748852455",
"amount": 100000,
"description": "THANHTOANDEMO",
"exoDate": null,
"qrData": "https://developer.example.com/payment/?qr=da58fde344a1e0c9280207e1143c6f40",
"status": "processing",
"traceNumber": "DEMOQR50269d422b61",
"bankCode": "978485",
"responseCode": "00",
"requestId": "P2S-1780908087998-3hlh5c4og",
"vcbResponse": {
"code": "00",
"nodeIn": "0.0.0.0",
"message": "Succeed",
"nodeOut": "10.1.60.185",
"subCode": "00",
"checksum": "8DB582799A700B17FA56C2558CC8CCB1",
"operation": "InitInvoice",
"ccPayLoad": "https://developer.example.com/payment/?qr=da58fde344a1e0c9280207e1143c6f40",
"requestId": "P2S-1780908087999-3hlh5c4og",
"paymentRef": "DEMOQR50269d422b61",
"serverTime": "15:42:07 09/06/2026",
"subMessage": "Succeed",
"paymentName": "CUA HANG DEMO"
},
"auditData": {
"channel": "P2S",
"channelId": "0.0.0.0",
"channelTime": "2825600815142",
"channelUser": "adi-payment",
"channelUserBranch": "01"
},
"createdAt": "2026-10-10T19:19:34.931Z"
}
}
```
### Giải thích Response
| Trường | Mô tả |
|--------|-------|
| `success` | Trạng thái: `true` = Lấy thông tin thành công |
| `transactionId` | Mã giao dịch duy nhất |
| `orderId` | ID đơn hàng |
| `amount` | Số tiền (VND) |
| `status` | Trạng thái: `processing` (chờ), `paid` (thanh toán), `cancelled` (hủy) |
| `qrData` | Chuỗi QR mã (EMV-QR format) |
| `traceNumber` | Mã định danh QR |
| `vcbResponse` | Chi tiết response từ ngân hàng |
| `createdAt` | Thời gian tạo QR |
| `paymentRef` | Mã tham chiếu thanh toán |
---
## 💻 Code mẫu - Kiểm tra QR
::: code-group
```php [PHP]
<?php
$bearerToken = "YOUR_BEARER_TOKEN";
$transactionId = "0e907bd2-74d0-4c49-96ba-e64660736a2a";
$url = "http://api.pay2s.vn/api/vcb/v1/qr/transactions/" . $transactionId;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $bearerToken
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['success'] === true) {
$txn = $result['data'];
echo "Order ID: " . $txn['orderId'] . "\n";
echo "Amount: " . $txn['amount'] . " VND\n";
echo "Status: " . $txn['status'] . "\n";
echo "Description: " . $txn['description'] . "\n";
echo "Created: " . $txn['createdAt'] . "\n";
// Kiểm tra thanh toán
if ($txn['status'] === 'paid') {
echo "✅ Thanh toán thành công!\n";
echo "Payment Ref: " . $txn['paymentRef'] . "\n";
} else if ($txn['status'] === 'processing') {
echo "⏳ Chờ thanh toán...\n";
} else if ($txn['status'] === 'cancelled') {
echo "❌ QR đã bị hủy\n";
}
} else {
echo "Error: " . $result['message'];
}
curl_close($ch);
?>
```
```javascript [Node.js]
const axios = require('axios');
const bearerToken = "YOUR_BEARER_TOKEN";
const transactionId = "0e907bd2-74d0-4c49-96ba-e64660736a2a";
const url = `http://api.pay2s.vn/api/vcb/v1/qr/transactions/${transactionId}`;
axios.get(url, {
headers: {
"Authorization": `Bearer ${bearerToken}`
}
})
.then(response => {
if (response.data.success === true) {
const txn = response.data.data;
console.log(`Order ID: ${txn.orderId}`);
console.log(`Amount: ${txn.amount} VND`);
console.log(`Status: ${txn.status}`);
console.log(`Description: ${txn.description}`);
console.log(`Created: ${txn.createdAt}`);
// Check payment status
if (txn.status === 'paid') {
console.log("✅ Payment successful!");
console.log(`Payment Ref: ${txn.paymentRef}`);
} else if (txn.status === 'processing') {
console.log("⏳ Waiting for payment...");
} else if (txn.status === 'cancelled') {
console.log("❌ QR was cancelled");
}
} else {
console.error("Error:", response.data.message);
}
})
.catch(err => console.error(err));
```
```python [Python]
import requests
bearer_token = "YOUR_BEARER_TOKEN"
transaction_id = "0e907bd2-74d0-4c49-96ba-e64660736a2a"
url = f"http://api.pay2s.vn/api/vcb/v1/qr/transactions/{transaction_id}"
headers = {
"Authorization": f"Bearer {bearer_token}"
}
response = requests.get(url, headers=headers)
result = response.json()
if result['success'] == True:
txn = result['data']
print(f"Order ID: {txn['orderId']}")
print(f"Amount: {txn['amount']} VND")
print(f"Status: {txn['status']}")
print(f"Description: {txn['description']}")
print(f"Created: {txn['createdAt']}")
# Check payment status
if txn['status'] == 'paid':
print("✅ Payment successful!")
print(f"Payment Ref: {txn['paymentRef']}")
elif txn['status'] == 'processing':
print("⏳ Waiting for payment...")
elif txn['status'] == 'cancelled':
print("❌ QR was cancelled")
else:
print("Error:", result['message'])
```
```java [Java]
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class RetrieveQRClient {
public static void main(String[] args) throws Exception {
String bearerToken = "YOUR_BEARER_TOKEN";
String transactionId = "0e907bd2-74d0-4c49-96ba-e64660736a2a";
String url = "http://api.pay2s.vn/api/vcb/v1/qr/transactions/" + transactionId;
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + bearerToken);
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
if (responseCode == 200) {
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// Parse and display JSON response
System.out.println("Response: " + response.toString());
// Note: For production, use a JSON library like Gson or Jackson
}
}
}
```
:::
---
## ⚡ Best Practices
1. **Cache transaction ID**: Lưu `transactionId` từ khi tạo QR để kiểm tra sau
2. **Poll status**: Gọi API này định kỳ để kiểm tra trạng thái thanh toán
3. **Error handling**: Kiểm tra `success` trước xử lý `data`
4. **Timeout**: Đặt timeout hợp lý (30-60 giây)
5. **Retry logic**: Nếu request fail, retry sau 2-3 giây
6. **Check payment status**: Luôn kiểm tra `status` trước cập nhật database
7. **Store response**: Lưu toàn bộ response để audit trail
8. **VCB Response**: Kiểm tra `vcbResponse.code` để xác nhận ngân hàng
9. **Avoid repeated calls**: Đừng gọi quá nhiều lần trong một vài giây
10. **Logging**: Log transactionId và status để debug
---
## 🔄 Luồng kiểm tra QR
```javascript
// 1. Tạo QR → nhận transactionId
// 2. Hiển thị QR cho khách hàng
// 3. Poll API kiểm tra status
const interval = setInterval(() => {
getQRStatus(transactionId).then(status => {
if (status === 'completed') {
clearInterval(interval);
console.log("✅ Payment completed");
updateOrderStatus('paid');
} else if (status === 'cancelled') {
clearInterval(interval);
console.log("❌ QR cancelled");
}
});
}, 2000); // Kiểm tra mỗi 2 giây
```
---
## 📊 Trạng thái QR
| Status | Mô tả | Hành động |
|--------|-------|----------|
| `processing` | Chờ thanh toán | Tiếp tục kiểm tra |
| `paid` | Đã thanh toán | Cập nhật order, gửi email |
| `cancelled` | QR bị hủy | Hiển thị lỗi, yêu cầu tạo QR mới |
| `expired` | QR hết hạn | Yêu cầu tạo QR mới |
---
> **Tiếp theo**: Xem [Danh sách OneQR](/oneqr/list-oneqr) để xem tất cả QR hoặc [Webhook](/webhook/tai-lieu-ky-thuat.html) để nhận thông báo tự động
## 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 · Truy vấn trạng thái
<div class="doc-api-actions" data-doc-api-actions><a class="try-button" data-doc-playground href="/playground/?api=oneqr-detail">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.
`GET /api/{bank_code}/v1/qr/transactions/{transactionId}`
Tham số path/query (không gửi JSON body):
```json
{
"bank_code": "vcb",
"transactionId": "LAST_QR"
}
```
HTTP 200. Response:
```json
{
"success": true,
"message": "QR transaction retrieved successfully",
"data": {
"transactionId": "da58fde344a1e0c9280207e1143c6f40",
"merchantId": "DEMO_MERCHANT",
"terminalId": "DEMO_TERMINAL",
"orderId": "DEMO17916599748852455",
"amount": 100000,
"description": "THANHTOANDEMO",
"exoDate": null,
"qrData": "https://developer.example.com/payment/?qr=da58fde344a1e0c9280207e1143c6f40",
"status": "processing",
"traceNumber": "DEMOQR50269d422b61",
"bankCode": "978485",
"responseCode": "00",
"requestId": "P2S-1780908087998-3hlh5c4og",
"vcbResponse": {
"code": "00",
"nodeIn": "0.0.0.0",
"message": "Succeed",
"nodeOut": "10.1.60.185",
"subCode": "00",
"checksum": "8DB582799A700B17FA56C2558CC8CCB1",
"operation": "InitInvoice",
"ccPayLoad": "https://developer.example.com/payment/?qr=da58fde344a1e0c9280207e1143c6f40",
"requestId": "P2S-1780908087999-3hlh5c4og",
"paymentRef": "DEMOQR50269d422b61",
"serverTime": "15:42:07 09/06/2026",
"subMessage": "Succeed",
"paymentName": "CUA HANG DEMO"
},
"auditData": {
"channel": "P2S",
"channelId": "0.0.0.0",
"channelTime": "2825600815142",
"channelUser": "adi-payment",
"channelUserBranch": "01"
},
"createdAt": "2026-10-10T19:19:34.931Z"
}
}
```