Chuyển tới nội dung chính

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

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

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ườngKiểuMô tả
message.contentstringThông báo trạng thái dễ đọc
codeintegerMã trạng thái nội bộ (102000 = thành công)
request_idstringID yêu cầu duy nhất để gỡ lỗi/hỗ trợ
dataobject/arrayDữ liệu phản hồi
metaobjectMetadata 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ểuMặc địnhMô tả
pageinteger1Số trang
page_sizeinteger50Số 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óiGiới hạnKhoảng thời gian
Standard100 yêu cầumỗi phút
Enterprise500 yêu cầumỗ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

Ý nghĩaKhi nào
200Thành côngCác thao tác GET, PUT, DELETE
201Đã tạoCác thao tác POST
400Yêu cầu không hợp lệBody hoặc tham số yêu cầu không hợp lệ
401Không được phépChữ ký không hợp lệ, timestamp hết hạn, hoặc sai client ID
403Bị cấmIP chưa được đưa vào danh sách cho phép (chỉ payout)
404Không tìm thấyTài nguyên không tồn tại
409Xung độtTài nguyên trùng lặp (ví dụ: trùng customer_code)
422Không thể xử lýXác thực thất bại (ví dụ: số dư không đủ)
429Quá nhiều yêu cầuVượt quá giới hạn tốc độ
500Lỗi máy chủLỗi nội bộ — thử lại với backoff

Cài đặt Webhook

  1. Đăng ký URL webhook của bạn thông qua Account API trong quá trình khởi tạo client
  2. Finan gửi một yêu cầu POST đến URL của bạn khi nhận được thanh toán
  3. 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
  4. 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