Hướng dẫn tích hợp
Hướng dẫn này sẽ đi qua toàn bộ luồng tích hợp — từ thiết lập đến nhận webhook thanh toán đầu tiên của bạn.
Tổng quan API
Base URL: https://api.finan.one/open
Tất cả các endpoint đều yêu cầu header xác thực: x-client-id, x-signature, x-timestamp.
Luồng tích hợp đầy đủ
Luồng 1: Nhận thanh toán (Phổ biến nhất)
1. Setup Account → GET /api/v1/master-bank-accounts
2. Create Payment → POST /api/v1/payments
3. Share Payment Link → Send payment_url or qr_code to customer
4. Receive Webhook → POST to your registered callback URL
5. Verify Payment → GET /api/v1/payments/:id (optional fallback)
- Go
- JavaScript
package main
import (
"context"
"fmt"
"log"
finan "github.com/finan-one/finan-go"
)
func main() {
client := finan.NewClient("YOUR_CLIENT_ID", "YOUR_SECRET_KEY")
ctx := context.Background()
// Bước 1: Lấy tài khoản ngân hàng
accounts, err := client.GetBankAccounts(ctx)
if err != nil {
log.Fatal(err)
}
accountID := accounts[0].AccountID
// Bước 2: Tạo yêu cầu thanh toán
payment, err := client.CreatePayment(ctx, &finan.CreatePaymentRequest{
PaymentMethod: finan.PaymentMethodBankTransfer,
AccountID: accountID,
Amount: 500000, // 500,000 VND
ReferenceID: "ORDER-001",
Description: "Don hang #001",
Customer: &finan.PaymentCustomer{
Name: "Nguyen Van A",
Email: "[email protected]",
},
})
if err != nil {
log.Fatal(err)
}
// Bước 3: Chia sẻ với khách hàng
fmt.Println("Payment URL:", payment.PaymentURL)
fmt.Println("QR Code:", payment.BankTransferDetails.QRCode)
// Bước 4: Webhook được gửi tự động khi nhận được thanh toán
// Bước 5: (Tùy chọn) Kiểm tra trạng thái thanh toán
status, _ := client.GetPayment(ctx, payment.PaymentRequestID)
fmt.Println("Status:", status.Status) // unpaid, paid, partial_paid, extra_paid
}
import { FinanClient } from '@finan-one/finan-js';
const client = new FinanClient('YOUR_CLIENT_ID', 'YOUR_SECRET_KEY');
// Bước 1: Lấy tài khoản ngân hàng
const accounts = await client.getBankAccounts();
const accountId = accounts[0].account_id;
// Bước 2: Tạo yêu cầu thanh toán
const payment = await client.createPayment({
payment_method: 'bank_transfer',
account_id: accountId,
amount: 500000, // 500,000 VND
reference_id: 'ORDER-001',
description: 'Don hang #001',
customer: {
name: 'Nguyen Van A',
email: '[email protected]',
},
});
// Bước 3: Chia sẻ với khách hàng
console.log('Payment URL:', payment.payment_url);
console.log('QR Code:', payment.bank_transfer_detail?.qr_code);
// Bước 4: Webhook được gửi tự động khi nhận được thanh toán
// Bước 5: (Tùy chọn) Kiểm tra trạng thái thanh toán
const status = await client.getPayment(payment.payment_request_id);
console.log('Status:', status.status); // unpaid, paid, partial_paid, extra_paid
Luồng 2: Thanh toán qua hóa đơn
1. Create Customer → POST /api/v1/customers
2. Create Product → POST /api/v1/products
3. Create Invoice → POST /api/v1/invoices (returns payment_link)
4. Share Invoice Link → Send payment_link to customer
5. Receive Webhook → POST to your registered callback URL
6. Check Invoice → GET /api/v1/invoices/:id
- Go
- JavaScript
// Bước 1: Tạo khách hàng (một lần)
// Xem: /docs/api/business/customer
// Bước 2: Tạo sản phẩm (một lần)
// Xem: /docs/api/business/product
// Bước 3: Tạo hóa đơn
invoice, err := client.CreateInvoice(ctx, &finan.CreateInvoiceRequest{
InvoiceCode: "INV-001",
TransactionDate: "2024-01-20T10:00:00Z",
DueDate: "2024-01-27T10:00:00Z",
TaxType: "price_excluding_tax",
Items: []finan.InvoiceItem{
{Code: "PRD0001", TaxCode: "TAX_CODE_10", Quantity: 2, UnitPrice: 100000},
},
Customer: finan.InvoiceCustomer{Code: "CUST123"},
PaymentMethods: []string{"bank_transfer", "card"},
AccountID: accountID,
})
fmt.Println("Invoice Payment Link:", invoice.PaymentLink)
// Bước 1: Tạo khách hàng (một lần)
// Xem: /docs/api/business/customer
// Bước 2: Tạo sản phẩm (một lần)
// Xem: /docs/api/business/product
// Bước 3: Tạo hóa đơn
const invoice = await client.createInvoice({
invoice_code: 'INV-001',
transaction_date: '2024-01-20T10:00:00Z',
due_date: '2024-01-27T10:00:00Z',
tax_type: 'price_excluding_tax',
items: [
{ code: 'PRD0001', tax_code: 'TAX_CODE_10', quantity: 2, unit_price: 100000 },
],
customer: { code: 'CUST123' },
payment_methods: ['bank_transfer', 'card'],
account_id: accountId,
});
console.log('Invoice Payment Link:', invoice.payment_link);
Luồng 3: Gửi chi hộ
1. Get Account → GET /api/v1/master-bank-accounts
2. Create Payout → POST /api/v1/payouts (returns id + OTP sent)
3. Receive OTP → From bank via SMS/Email
4. Verify OTP → POST /api/v1/payouts/:id/otps
5. Check Status → GET /api/v1/payouts/:id
Điều kiện tiên quyết
Payout yêu cầu đưa IP vào danh sách cho phép và chỉ khả dụng cho tài khoản Enterprise.
Định dạng phản hồi
Tất cả các phản hồi API đều tuân theo cấu trúc bọc sau:
{
"message": {
"content": "Thực thi API thành công"
},
"code": 102000,
"request_id": "af2684a45bca4d444ef60c6dc90b4139",
"data": { ... },
"meta": {
"page": 1,
"page_size": 50,
"total_pages": 1,
"total_rows": 1
}
}
| Trường | Kiểu | Mô tả |
|---|---|---|
message.content | string | Thông báo trạng thái dễ đọc |
code | integer | Mã trạng thái nội bộ (102000 = thành công) |
request_id | string | ID yêu cầu duy nhất để gỡ lỗi/hỗ trợ |
data | object/array | Dữ liệu phản hồi |
meta | object | Metadata phân trang (chỉ cho các endpoint danh sách) |
Phân trang
Các endpoint danh sách trả về kết quả phân trang. Sử dụng các tham số truy vấn sau:
| Tham số | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
page | integer | 1 | Số trang |
page_size | integer | 50 | Số mục mỗi trang |
Ví dụ:
curl -X GET 'https://api.finan.one/open/api/v1/payments?page=2&page_size=50' \
-H 'x-client-id: YOUR_CLIENT_ID' \
-H 'x-signature: YOUR_SIGNATURE' \
-H 'x-timestamp: 1699999999'
Metadata phân trang (trong trường meta):
{
"meta": {
"page": 2,
"page_size": 50,
"total_pages": 3,
"total_rows": 150
}
}
Giới hạn tốc độ
| Gói | Giới hạn | Khoảng thời gian |
|---|---|---|
| Standard | 100 yêu cầu | mỗi phút |
| Enterprise | 500 yêu cầu | mỗi phút |
Khi bị giới hạn tốc độ, API trả về 429 Too Many Requests:
{
"message": {
"content": "Yêu cầu không hợp lệ",
"error": "Rate limit exceeded. Retry after 30 seconds."
},
"code": 104000,
"request_id": "abc123..."
}
Phương pháp tốt nhất
- Lưu bộ nhớ đệm cho các dữ liệu được truy cập thường xuyên (ví dụ: tài khoản ngân hàng)
- Sử dụng webhook thay vì polling để kiểm tra trạng thái thanh toán
- Gộp các thao tác khi có thể
Định dạng phản hồi lỗi
Các phản hồi lỗi tuân theo cùng cấu trúc bọc với code mức lỗi:
{
"message": {
"content": "Bad Request"
},
"code": 400000,
"request_id": "abc123...",
"data": null
}
Mã trạng thái HTTP
| Mã | Ý nghĩa | Khi nào |
|---|---|---|
200 | Thành công | Các thao tác GET, PUT, DELETE |
201 | Đã tạo | Các thao tác POST |
400 | Yêu cầu không hợp lệ | Body hoặc tham số yêu cầu không hợp lệ |
401 | Không được phép | Chữ ký không hợp lệ, timestamp hết hạn, hoặc sai client ID |
403 | Bị cấm | IP chưa được đưa vào danh sách cho phép (chỉ payout) |
404 | Không tìm thấy | Tài nguyên không tồn tại |
409 | Xung đột | Tài nguyên trùng lặp (ví dụ: trùng customer_code) |
422 | Không thể xử lý | Xác thực thất bại (ví dụ: số dư không đủ) |
429 | Quá nhiều yêu cầu | Vượt quá giới hạn tốc độ |
500 | Lỗi máy chủ | Lỗi nội bộ — thử lại với backoff |
Cài đặt Webhook
- Đăng ký URL webhook của bạn thông qua Account API trong quá trình khởi tạo client
- Finan gửi một yêu cầu
POSTđến URL của bạn khi nhận được thanh toán - Luôn phản hồi với HTTP
200— ngay cả khi quá trình xử lý của bạn thất bại - Xác minh chữ ký webhook bằng header
x-signature(xem cách thực hiện)
Chính sách thử lại: Các webhook thất bại sẽ được thử lại 3 lần trong 30 phút (5 phút → 15 phút → 30 phút).
Danh sách kiểm tra trước khi đưa lên production
- Tạo chữ ký hoạt động đúng cho cả yêu cầu GET và POST
- Endpoint webhook đã được triển khai và trả về HTTP 200
- Đã triển khai xác minh chữ ký webhook
- Xử lý lỗi bao gồm tất cả mã trạng thái HTTP
- Xử lý hết hạn link thanh toán (30 phút) với logic thử lại
- Đã đưa IP vào danh sách cho phép cho Payout API (nếu áp dụng)
- Chuyển base URL từ staging sang production
Bước tiếp theo
- Xác thực — Cách ký yêu cầu
- Tài khoản — Thiết lập tài khoản ngân hàng
- Tham chiếu mã — Mã thuế, mã ngân hàng, mã danh mục