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

Xác thực

Mọi yêu cầu API đều phải bao gồm ba header xác thực. Finan sử dụng chữ ký HMAC SHA-256 để xác minh tính toàn vẹn của yêu cầu.

Header bắt buộc

HeaderMô tả
x-client-idID khách hàng duy nhất của bạn (được cung cấp bởi Finan)
x-signatureGiá trị băm SHA-256 của dữ liệu yêu cầu (xem bên dưới)
x-timestampDấu thời gian Unix hiện tại — phải nằm trong khoảng 30 giây so với thời gian máy chủ
curl -X POST 'https://api.finan.one/open/api/v1/payments' \
-H 'Content-Type: application/json' \
-H 'x-client-id: YOUR_CLIENT_ID' \
-H 'x-signature: YOUR_GENERATED_SIGNATURE' \
-H 'x-timestamp: 1699999999'

Cách tạo chữ ký

Bước 1: Chuẩn bị các trường

TrườngKiểuMô tả
Secret KeystringKhóa bí mật của bạn được cung cấp bởi Finan
MethodstringPhương thức HTTP: GET, POST, PUT, DELETE
Relative PathstringĐường dẫn API không bao gồm tiền tố /open (xem ghi chú bên dưới)
PayloadstringNội dung JSON của yêu cầu dưới dạng chuỗi. Chuỗi rỗng "" cho các yêu cầu GET
TimestampstringDấu thời gian Unix (cùng giá trị với header x-timestamp)
Đường dẫn tương đối

URL gốc là https://api.finan.one/open/api/v1/... nhưng chữ ký chỉ sử dụng đường dẫn sau /open.

Bao gồm chuỗi truy vấn khi lọc theo tham số truy vấn:

URL đầy đủĐường dẫn chữ ký
https://api.finan.one/open/api/v1/payments/api/v1/payments
https://api.finan.one/open/api/v1/payouts/abc123/otps/api/v1/payouts/abc123/otps
https://api.finan.one/open/api/v1/master-bank-accounts?account_id=xxx/api/v1/master-bank-accounts?account_id=xxx

Bước 2: Nối chuỗi với dấu gạch dưới

{SECRET_KEY}_{METHOD}_{RELATIVE_PATH}_{PAYLOAD}_{TIMESTAMP}

Ví dụ POST (có nội dung JSON):

mySecretKey_POST_/api/v1/payments_{"amount":6000000,"payment_method":"bank_transfer"}_1699999999

Ví dụ GET (payload rỗng):

mySecretKey_GET_/api/v1/payments__1699999999
Yêu cầu GET

Đối với các yêu cầu GET, payload là một chuỗi rỗng. Điều này có nghĩa là chuỗi nối sẽ có hai dấu gạch dưới liên tiếp (__) giữa đường dẫn và dấu thời gian.

Bước 3: Băm với SHA-256

Áp dụng SHA-256 cho chuỗi đã nối. Kết quả được mã hóa hex chính là x-signature của bạn.

package main

import (
"crypto/sha256"
"encoding/hex"
"fmt"
"strconv"
"time"
)

func generateSignature(secretKey, method, path, payload, timestamp string) string {
message := secretKey + "_" + method + "_" + path + "_" + payload + "_" + timestamp
hash := sha256.Sum256([]byte(message))
return hex.EncodeToString(hash[:])
}

func main() {
secretKey := "mySecretKey"
timestamp := strconv.FormatInt(time.Now().Unix(), 10)

// POST request with body
postPayload := `{"amount":6000000,"payment_method":"bank_transfer"}`
postSig := generateSignature(secretKey, "POST", "/api/v1/payments", postPayload, timestamp)
fmt.Println("POST Signature:", postSig)

// GET request (empty payload)
getSig := generateSignature(secretKey, "GET", "/api/v1/payments", "", timestamp)
fmt.Println("GET Signature:", getSig)
}

Ví dụ request đầy đủ

Request POST (Tạo thanh toán)

package main

import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net/http"
"strconv"
"time"
)

func generateSignature(secretKey, method, path, payload, timestamp string) string {
message := secretKey + "_" + method + "_" + path + "_" + payload + "_" + timestamp
hash := sha256.Sum256([]byte(message))
return hex.EncodeToString(hash[:])
}

func main() {
clientID := "YOUR_CLIENT_ID"
secretKey := "YOUR_SECRET_KEY"
timestamp := strconv.FormatInt(time.Now().Unix(), 10)

payload := `{"amount":6000000,"payment_method":"bank_transfer","reference_id":"ORDER-001"}`
path := "/api/v1/payments"
signature := generateSignature(secretKey, "POST", path, payload, timestamp)

req, _ := http.NewRequest("POST", "https://api.finan.one/open"+path, bytes.NewBufferString(payload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-client-id", clientID)
req.Header.Set("x-signature", signature)
req.Header.Set("x-timestamp", timestamp)

resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)
fmt.Printf("Status: %d\nBody: %s\n", resp.StatusCode, string(body))
}

Request GET (Danh sách thanh toán)

timestamp := strconv.FormatInt(time.Now().Unix(), 10)
path := "/api/v1/payments"
signature := generateSignature(secretKey, "GET", path, "", timestamp)

req, _ := http.NewRequest("GET", "https://api.finan.one/open"+path, nil)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-client-id", clientID)
req.Header.Set("x-signature", signature)
req.Header.Set("x-timestamp", timestamp)

Môi trường

Môi trườngURL gốc
Productionhttps://api.finan.one/open
Staginghttps://api-stg.finan.one/open

Lỗi thường gặp

LỗiNguyên nhânGiải pháp
401 UnauthorizedChữ ký không hợp lệXác minh khóa bí mật, kiểm tra payload khớp chính xác với nội dung
401 Timestamp expiredDấu thời gian cũ hơn 30 giâySử dụng dấu thời gian Unix hiện tại, kiểm tra đồng bộ thời gian máy chủ
401 Invalid clientSai ID khách hàngXác minh giá trị x-client-id

Xác minh chữ ký Webhook

Khi bạn nhận được webhook từ Finan, hãy xác minh tính xác thực bằng cách tính lại chữ ký:

func verifyWebhookSignature(secretKey, body, receivedSignature, timestamp string) bool {
expected := generateSignature(secretKey, "POST", "/your-webhook-path", body, timestamp)
return expected == receivedSignature
}

Sử dụng các header x-signaturex-timestamp từ yêu cầu webhook để xác minh.


Bộ sưu tập Postman

Nhập bộ sưu tập Postman của chúng tôi để kiểm thử nhanh:

Tải xuống Bộ sưu tập Postman


Bước tiếp theo