Go Sample
This sample uses only the Go standard library. It includes signing, POST JSON, GET Query, and examples for creating a collect order, creating a payout order, and querying merchant info.
go
package main
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
type Client struct {
BaseURL string
MchID int
APIToken string
HTTPClient *http.Client
}
func (c *Client) CreateCollectOrder() (map[string]any, error) {
return c.Post("/api/v1/mch/pmt-orders", map[string]any{
"trans_id": "ORDER-" + strconv.FormatInt(time.Now().Unix(), 10),
"currency": "VND",
"amount": "100.00",
"channel": "bank",
"callback_url": "https://merchant.example.com/callback/collect",
"return_url": "https://merchant.example.com/payment/result",
"remarks": "collect demo",
})
}
func (c *Client) CreatePayoutOrder() (map[string]any, error) {
return c.Post("/api/v1/mch/wdl-orders", map[string]any{
"trans_id": "WDL-" + strconv.FormatInt(time.Now().Unix(), 10),
"channel": "bank",
"amount": "100.00",
"currency": "VND",
"account_no": "2333667799212341",
"account_name": "NGUYEN XUAN HUNG",
"account_org": "PVCOMBANK",
"account_org_code": "970412",
"callback_url": "https://merchant.example.com/callback/payout",
"remarks": "payout demo",
})
}
func (c *Client) GetMerchantInfo() (map[string]any, error) {
return c.Get("/api/v1/mch/info", map[string]any{})
}
func (c *Client) Post(path string, params map[string]any) (map[string]any, error) {
params = c.WithSignature(params)
body, err := json.Marshal(params)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, c.BaseURL+path, bytes.NewReader(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
return c.Do(req)
}
func (c *Client) Get(path string, params map[string]any) (map[string]any, error) {
params = c.WithSignature(params)
query := url.Values{}
for key, value := range params {
query.Set(key, fmt.Sprint(value))
}
req, err := http.NewRequest(http.MethodGet, c.BaseURL+path+"?"+query.Encode(), nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
func (c *Client) WithSignature(params map[string]any) map[string]any {
signed := make(map[string]any, len(params)+4)
for key, value := range params {
signed[key] = value
}
signed["mch_id"] = c.MchID
signed["nonce"] = RandString(12)
signed["timestamp"] = time.Now().Unix()
signed["sign"] = c.Sign(signed)
return signed
}
func (c *Client) Sign(params map[string]any) string {
keys := make([]string, 0, len(params))
for key, value := range params {
if key == "sign" || value == nil || fmt.Sprint(value) == "" {
continue
}
keys = append(keys, key)
}
sort.Strings(keys)
var builder strings.Builder
builder.WriteString(c.APIToken)
for _, key := range keys {
builder.WriteString("&")
builder.WriteString(key)
builder.WriteString("=")
builder.WriteString(fmt.Sprint(params[key]))
}
hash := md5.Sum([]byte(builder.String()))
return hex.EncodeToString(hash[:])
}
func (c *Client) Do(req *http.Request) (map[string]any, error) {
httpClient := c.HTTPClient
if httpClient == nil {
httpClient = &http.Client{Timeout: 10 * time.Second}
}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("http request failed: %s", resp.Status)
}
var result map[string]any
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, err
}
if code, ok := result["code"].(float64); !ok || int(code) != 200 {
return nil, fmt.Errorf("api request failed: %v", result)
}
payload, _ := result["payload"].(map[string]any)
return payload, nil
}
func RandString(n int) string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
source := rand.New(rand.NewSource(time.Now().UnixNano()))
result := make([]byte, n)
for i := range result {
result[i] = letters[source.Intn(len(letters))]
}
return string(result)
}
func main() {
client := &Client{
BaseURL: "https://api.example.com",
MchID: 10001,
APIToken: "demo_key_123456",
}
collectOrder, _ := client.CreateCollectOrder()
payoutOrder, _ := client.CreatePayoutOrder()
merchantInfo, _ := client.GetMerchantInfo()
fmt.Println(collectOrder, payoutOrder, merchantInfo)
}