Chi hộ
Khởi tạo chi hộ từ tài khoản Shinhan của bạn đến bất kỳ ngân hàng nào hoạt động tại Việt Nam.

Tham chiếu nhanh
| Endpoint | Phương thức | Mô tả |
|---|---|---|
/api/v1/payouts | POST | Tạo yêu cầu chi hộ mới |
/api/v1/payouts | GET | Liệt kê tất cả yêu cầu chi hộ |
/api/v1/payouts/:id | GET | Lấy yêu cầu chi hộ cụ thể |
/api/v1/payouts/:id/otps | POST | Xác minh OTP cho chi hộ |
API Chi hộ chỉ khả dụng cho giải pháp Doanh nghiệp. Liên hệ support@finan.one để được cấp quyền truy cập.
Cài đặt: Whitelist IP
Trước khi sử dụng API Chi hộ, bạn phải thêm địa chỉ IP máy chủ vào danh sách cho phép.
-
Truy cập book.finan.one/setting → Open API

-
Nhấn Whitelist IP

-
Nhập địa chỉ IP của bạn và lưu

Sau khi IP được thêm vào danh sách cho phép, luồng Cashout trên cổng thông tin sẽ bị vô hiệu hóa. Tất cả chi hộ phải sử dụng API.
API Endpoints
Tạo yêu cầu chi hộ
Tạo yêu cầu chi hộ mới. Lưu lại id được trả về để xác minh OTP.
POST /api/v1/payouts
- cURL
- Go
curl -X POST 'https://api.finan.one/open/api/v1/payouts' \
-H 'Content-Type: application/json' \
-H 'x-client-id: YOUR_CLIENT_ID' \
-H 'x-signature: YOUR_SIGNATURE' \
-H 'x-timestamp: 1699999999' \
-d '{
"account_id": "54957437-0cb5-4992-ad0e-76d26ba4ddc3",
"amount": 6000000,
"beneficiary_account_name": "NGUYEN VAN A",
"beneficiary_account_number": "1234567890",
"beneficiary_bank_id": "161",
"currency": "VND",
"reference_id": "PAYOUT-001",
"description": "thanh toan don hang"
}'
package main
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"
)
type CreatePayoutRequest struct {
AccountID string `json:"account_id"`
Amount int64 `json:"amount"`
BeneficiaryAccountName string `json:"beneficiary_account_name"`
BeneficiaryAccountNumber string `json:"beneficiary_account_number"`
BeneficiaryBankID string `json:"beneficiary_bank_id"`
Currency string `json:"currency,omitempty"`
ReferenceID string `json:"reference_id,omitempty"`
Description string `json:"description"`
}
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)
reqBody := CreatePayoutRequest{
AccountID: "54957437-0cb5-4992-ad0e-76d26ba4ddc3",
Amount: 6000000,
BeneficiaryAccountName: "NGUYEN VAN A",
BeneficiaryAccountNumber: "1234567890",
BeneficiaryBankID: "161",
Currency: "VND",
ReferenceID: "PAYOUT-001",
Description: "thanh toan don hang",
}
jsonBody, _ := json.Marshal(reqBody)
signature := generateSignature(secretKey, "POST", "/api/v1/payouts", string(jsonBody), timestamp)
req, _ := http.NewRequest("POST", "https://api.finan.one/open/api/v1/payouts", bytes.NewBuffer(jsonBody))
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)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Nội dung request
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
account_id | uuid | ✅ | ID tài khoản Shinhan nguồn. Lấy từ API Tài khoản |
amount | integer | ✅ | Số tiền theo đơn vị tiền tệ nhỏ nhất |
beneficiary_account_name | string | ✅ | Tên người nhận đã đăng ký với ngân hàng |
beneficiary_account_number | string | ✅ | Số tài khoản người nhận |
beneficiary_bank_id | string | ✅ | Mã ngân hàng. Xem Tham chiếu mã |
currency | string | Mã tiền tệ ISO (mặc định: VND) | |
reference_id | string | ID giao dịch duy nhất của bạn để theo dõi | |
description | string | ✅ | Nội dung chuyển khoản (tối đa 30 ký tự) |
Phản hồi
- ✅ Success (200)
- ❌ Error
{
"message": { "content": "Thực thi API thành công" },
"code": 102001,
"request_id": "abc123...",
"data": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"status": "waiting_confirm",
"remaining_try": 3
}
}
| Mã | Thông báo | Mô tả |
|---|---|---|
| 400 | Bad Request | Nội dung request không hợp lệ |
| 401 | Unauthorized | Xác thực không hợp lệ |
| 403 | Forbidden | IP không nằm trong danh sách cho phép |
| 404 | Not Found | Không tìm thấy Account ID |
| 422 | Unprocessable Entity | Số dư không đủ hoặc xác thực dữ liệu thất bại |
{
"message": {
"content": "Yêu cầu không hợp lệ",
"error": "IP address not whitelisted"
},
"code": 104000,
"request_id": "abc123..."
}
Trạng thái chi hộ
| Trạng thái | Mô tả |
|---|---|
waiting_confirm | Đang chờ xác minh OTP |
processing | OTP đã xác minh, đang xử lý chuyển khoản |
success | Chi hộ hoàn tất |
failed | Chi hộ thất bại |
Lấy danh sách yêu cầu chi hộ
Truy xuất tất cả yêu cầu chi hộ.
GET /api/v1/payouts
- cURL
- Go
curl -X GET 'https://api.finan.one/open/api/v1/payouts' \
-H 'Content-Type: application/json' \
-H 'x-client-id: YOUR_CLIENT_ID' \
-H 'x-signature: YOUR_SIGNATURE' \
-H 'x-timestamp: 1699999999'
package main
import (
"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)
signature := generateSignature(secretKey, "GET", "/api/v1/payouts", "", timestamp)
req, _ := http.NewRequest("GET", "https://api.finan.one/open/api/v1/payouts", 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)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Phản hồi
- ✅ Success (200)
- ❌ Error
{
"message": { "content": "Thực thi API thành công" },
"code": 102000,
"request_id": "abc123...",
"data": [
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"status": "success",
"amount": 6000000,
"beneficiary_account_name": "NGUYEN VAN A",
"beneficiary_account_number": "1234567890",
"beneficiary_bank_id": "161",
"reference_id": "PAYOUT-001",
"remaining_try": 0,
"created_at": "2024-01-20T14:00:00Z"
}
]
}
| Mã | Thông báo | Mô tả |
|---|---|---|
| 401 | Unauthorized | Xác thực không hợp lệ |
| 403 | Forbidden | IP không nằm trong danh sách cho phép |
GET /api/v1/payouts/:payout_id
Xác minh OTP
Gửi mã OTP để xác nhận yêu cầu chi hộ.
POST /api/v1/payouts/:payout_id/otps
- cURL
- Go
curl -X POST 'https://api.finan.one/open/api/v1/payouts/660e8400-e29b-41d4-a716-446655440001/otps' \
-H 'Content-Type: application/json' \
-H 'x-client-id: YOUR_CLIENT_ID' \
-H 'x-signature: YOUR_SIGNATURE' \
-H 'x-timestamp: 1699999999' \
-d '{
"code": 123456
}'
package main
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"
)
type VerifyOTPRequest struct {
Code int `json:"code"`
}
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)
payoutID := "660e8400-e29b-41d4-a716-446655440001"
reqBody := VerifyOTPRequest{
Code: 123456,
}
jsonBody, _ := json.Marshal(reqBody)
path := "/api/v1/payouts/" + payoutID + "/otps"
signature := generateSignature(secretKey, "POST", path, string(jsonBody), timestamp)
url := "https://api.finan.one/open/api/v1/payouts/" + payoutID + "/otps"
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
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)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Nội dung request
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
code | integer | ✅ | Mã OTP nhận được từ ngân hàng |
Phản hồi
- ✅ Success (200)
- ❌ Error
{
"message": { "content": "Thực thi API thành công" },
"code": 102000,
"request_id": "abc123...",
"data": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"status": "processing",
"remaining_try": 2
}
}
| Mã | Thông báo | Mô tả |
|---|---|---|
| 400 | Bad Request | Định dạng OTP không hợp lệ |
| 401 | Unauthorized | Xác thực không hợp lệ |
| 404 | Not Found | Không tìm thấy yêu cầu chi hộ |
| 422 | Unprocessable Entity | OTP không hợp lệ hoặc không còn lượt thử |
{
"message": {
"content": "Yêu cầu không hợp lệ",
"error": "Invalid OTP code"
},
"code": 104000,
"request_id": "abc123..."
}
Mỗi yêu cầu chi hộ có số lần nhập OTP giới hạn (thường là 3 lần). Sau khi hết lượt thử, hãy tạo yêu cầu chi hộ mới.
Luồng chi hộ
1. Tạo yêu cầu chi hộ → trạng thái: waiting_confirm
2. Nhận OTP từ ngân hàng (SMS/Email)
3. Gửi OTP → trạng thái: processing
4. Chi hộ hoàn tất → trạng thái: success
Bước tiếp theo
- Tham chiếu mã - Mã ngân hàng cho
beneficiary_bank_id - Tài khoản - Lấy
account_idcủa bạn - Webhook thanh toán - Tính năng thử lại webhook