API hóa đơn điện tử Pay2S cho phép backend tạo nháp, gửi nháp, phát hành và đọc hóa đơn qua kết nối đã cấu hình. Hướng dẫn của hoadontudong.com.vn pay2s tập trung vào giao thức và vòng đời yêu cầu; xem riêng thiết kế chống trùng và xử lý timeout khi xây dựng luồng vận hành.
Điều kiện trước khi tích hợp
Tài khoản chính cần gói Basic trở lên, được bật HĐĐT, có kết nối đã kiểm tra và mẫu mặc định. Khi gửi store_id, cửa hàng phải được gán mẫu thuộc kết nối đó. Production cần quyền phát hành thật.
Dùng Partner Code, Access Key và Secret Key của tài khoản chính, cùng bộ khóa tích hợp thanh toán. Không dùng khóa Partner API độc lập, khóa nhân viên/cửa hàng hoặc token Dashboard. Secret Key chỉ được giữ ở backend. API này không tạo link thanh toán và không tự xác minh đơn hàng bên ngoài đã trả tiền.
Endpoint và chữ ký HMAC
POST https://api.pay2s.vn/api/v1/einvoices
Content-Type: application/json
X-Partner-Code: YOUR_PARTNER_CODE
X-Access-Key: YOUR_ACCESS_KEY
X-Timestamp: UNIX_SECONDS
X-Signature: LOWERCASE_HMAC_SHA256_HEX
Timestamp dùng Unix giây 10 chữ số; sai lệch tối đa 300 giây. Body tối đa 256 KiB. Chuỗi ký có đúng bốn dòng, phân tách LF và không thêm xuống dòng cuối:
{timestamp}
POST
/api/v1/einvoices
{sha256_hex_cua_nguyen_body_JSON}
Tính HMAC-SHA256 với Secret Key, xuất hex chữ thường. Body gửi đi phải chính là chuỗi JSON đã băm; không serialize lại sau khi ký.
Ví dụ Node.js: đọc danh sách kết nối
Mẫu dưới đây chỉ gọi hành động đọc kết nối. Cấu hình ba biến môi trường trên backend; không dán khóa vào frontend hoặc bài viết.
import { createHash, createHmac } from 'node:crypto';
const path = '/api/v1/einvoices';
const body = JSON.stringify({ action: 'connections' });
const timestamp = String(Math.floor(Date.now() / 1000));
const hash = createHash('sha256').update(body, 'utf8').digest('hex');
const canonical = [timestamp, 'POST', path, hash].join('\n');
const signature = createHmac('sha256', process.env.PAY2S_SECRET_KEY)
.update(canonical, 'utf8').digest('hex');
const response = await fetch('https://api.pay2s.vn' + path, {
method: 'POST', body,
headers: {
'Content-Type': 'application/json',
'X-Partner-Code': process.env.PAY2S_PARTNER_CODE,
'X-Access-Key': process.env.PAY2S_ACCESS_KEY,
'X-Timestamp': timestamp, 'X-Signature': signature
}, signal: AbortSignal.timeout(90000)
});
const result = await response.json();
if (!response.ok || result.status !== true)
throw new Error(result.message || 'Yêu cầu thất bại');
console.log(result.data);
Các hành động theo vòng đời hóa đơn
| action | Kết quả cần phân biệt |
|---|---|
| connections | Lấy ID kết nối thực tế thuộc tài khoản. |
| create_draft | Tạo nháp tại Pay2S; mặc định chưa gọi nhà cung cấp. |
| submit_draft | Gửi nháp sang nhà cung cấp; chưa ký/phát hành. |
| publish | Ký/cấp số theo môi trường và quyền. |
| detail | Đọc dữ liệu đã lưu tại Pay2S. |
| sync | Đồng bộ trạng thái từ nhà cung cấp, sau đó đọc detail. |
| files | Lấy PDF/XML Base64 khi nhà cung cấp hỗ trợ. |
Khi tạo nháp, gửi connection_id, environment, external_ref, người mua và items. Mỗi dòng có name, quantity, unit_price, tax_rate; mã và đơn vị dùng code, unit. Số lượng phải dương, đơn giá không âm. Tổng do backend tính.
Lưu data.id làm invoice_id cho các bước sau. external_ref duy nhất theo tài khoản chính, xuyên môi trường/kết nối; nên dùng tiền tố Sandbox và Production khác nhau.
Production, tự gửi và tự phát hành
Production cần đúng kết nối, environment: "production", confirm_production: true ở các bước tạo/gửi/phát hành và quyền thực tế của tài khoản. Không tự chuyển môi trường bằng cách đổi một trường khi kết nối vẫn là Sandbox.
Với create_draft, chọn auto_submit: true để gửi nháp, hoặc auto_publish: true để tạo và phát hành. Không bật cả hai; dùng boolean JSON. Nếu gửi lỗi sau khi đã lưu nháp, phản hồi có thể có status: false nhưng vẫn có ID và local_draft_saved: true; giữ ID để kiểm tra.
Đọc trạng thái và giới hạn
draft là nháp; kiểm tra thêm has_provider_reference. processing cần đợi; issued là đã phát hành. Với failed hoặc unknown, xem nhật ký, đồng bộ và đối soát trước khi gửi lại. Phiên bản được rà soát dùng polling, chưa có webhook riêng cho trạng thái HĐĐT.
Giới hạn 60 request/phút/tài khoản tính chung hành động; gặp 429 thì đợi phút kế tiếp. Với files, chọn file_type là all, pdf hoặc xml và giải mã Base64 thành tệp. Không mặc định API luôn trả URL tải công khai.
Đối chiếu đặc tả phiên bản: API HĐĐT chính thức Pay2S, rà soát 13/10/2026.
Biên soạn theo tài liệu Pay2S, rà soát ngày 13/10/2026. Xem cẩm nang hóa đơn điện tử Pay2S để đi theo toàn bộ lộ trình.

hoadontudong.com.vn pay2s · Giải pháp hóa đơn tự động · Tư vấn triển khai.