// Demo of signing and order creation. sign = HMAC-SHA256(params sorted by key as k=v joined by "&", then append "&secret=<secret>") in hex. Nested objects (extra etc.) are serialized as compact JSON with keys sorted before signing. Replace placeholders with your real credentials.
package main

import (
  "bytes"
  "crypto/hmac"
  "crypto/sha256"
  "encoding/hex"
  "encoding/json"
  "fmt"
  "net/http"
  "sort"
  "strings"
  "time"
)

func main() {
  baseUrl := "<BASE_URL>"
  merchantNo := "<YOUR_MERCHANT_NO>"
  apiKey := "<YOUR_API_KEY>"
  apiSecret := "<API_SECRET>"

  payload := map[string]any{
    "merchant_no": merchantNo,
    "api_key": apiKey,
    "timestamp": time.Now().Unix(),
    "nonce": "random-xyz",
    "out_order_no": "202501010001",
    "amount": 10000,
    "currency": "PHP",
    "pay_method": "gcash",
    "country": "PH",
    "notify_url": "https://merchant.example.com/api/notify/pay",
    "extra": map[string]any{
      "customer": map[string]any{
        "first_name": "<FIRST_NAME>",
        "last_name": "<LAST_NAME>",
        "email": "<EMAIL>",
        "phone": "<PHONE>",
      },
    },
  }

  // stableJSON: disables HTML escaping (Go escapes <>& by default), consistent with the semantics of JS JSON.stringify
  stableJSON := func(v any) string {
    var buf bytes.Buffer
    enc := json.NewEncoder(&buf)
    enc.SetEscapeHTML(false)
    enc.Encode(v)
    return strings.TrimRight(buf.String(), "\n")
  }

  keys := make([]string, 0, len(payload));
  for k := range payload {
    if k == "sign" || payload[k] == nil { continue }
    keys = append(keys, k)
  }
  sort.Strings(keys)
  var b strings.Builder
  for i, k := range keys {
    if i > 0 { b.WriteString("&") }
    b.WriteString(k)
    b.WriteString("=")
    switch payload[k].(type) {
    case map[string]any, []any:
      b.WriteString(stableJSON(payload[k]))
    default:
      b.WriteString(fmt.Sprint(payload[k]))
    }
  }
  b.WriteString("&secret=")
  b.WriteString(apiSecret)

  mac := hmac.New(sha256.New, []byte(apiSecret))
  mac.Write([]byte(b.String()))
  sign := hex.EncodeToString(mac.Sum(nil))
  payload["sign"] = sign

  body, _ := json.Marshal(payload)
  req, _ := http.NewRequest("POST", baseUrl+"/merchant/pay/create", bytes.NewBuffer(body))
  req.Header.Set("Content-Type", "application/json")
  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()
}