主题
05 · Go SDK 使用文档
linkepay-sdk-go 封装了签名、请求、验签,Go 商户推荐直接使用。
1. 安装
bash
go get github.com/linkepay/linkepay-sdk-go
go mod tidy要求 Go 1.23+。
2. 初始化客户端
go
package main
import (
linkepay "github.com/linkepay/linkepay-sdk-go"
"github.com/linkepay/linkepay-sdk-go/types"
)
var client *linkepay.Client
func init() {
client = linkepay.NewClient(&types.Config{
// 生产环境(主网)
BaseURL: "https://linkepay-api.bestxx.com",
ProjectID: "<PROJECT_UID>", // 平台分配,如 Ab3xY9Kq7Z
PrivateKey: "<MERCHANT_PRIVATE_KEY>", // 商户私钥,0x + 64 hex,用于请求签名
PublicKey: "<MERCHANT_PUBLIC_KEY>", // 商户公钥(需已登记到平台)
ApiKey: "<API_KEY>", // 查询类接口需要
// 平台公钥,用于验证回调 / 响应签名
PayPlatformPublicKey: "0xc0b2388188f35c087400575393c124e9c459550f1dfcf848214f47637b599ee08a6b64876c4687e869d070d892b97071fd4c90b0a3491814823b4e97f8e7d50f",
Timeout: 30, // 秒,默认 30
})
}Config 字段说明:
| 字段 | 必填 | 用途 |
|---|---|---|
BaseURL | 是 | 生产环境填 https://linkepay-api.bestxx.com |
ProjectID | 是 | 拼进所有接口路径 |
PrivateKey | 写接口必填 | 生成 X-Signature |
PublicKey | 建议填 | 自检用;平台侧用的是已登记的那份 |
ApiKey | 查询接口必填 | 生成 X-API-Key |
PayPlatformPublicKey | 回调验签必填 | VerifyPlatformSignature / ParseCallbackData 使用 |
Timeout | 否 | 请求超时(秒),默认 30 |
配置来源:私钥和 API Key 请从环境变量 / KMS / K8s Secret 注入,不要写进代码或提交到仓库。
3. 方法一览
| 方法 | 对应接口 | 鉴权 |
|---|---|---|
CreateDepositAddress | 按用户 uid 生成充值地址 | 签名 |
CreateMultipleDepositAddress | 批量生成充值地址 | 签名 |
GetDepositAddress | 查询用户充值地址 | API Key |
RequestWithdrawal | 发起提现 | 签名 |
GetDeposits | 查询充值记录 | API Key |
GetWithdrawals | 查询提现记录 | API Key |
VerifyPlatformSignature | 验证平台签名 | — |
ParseCallbackData | 验签并解析回调 | — |
GenerateKeys | 生成商户密钥对 | — |
SignDataWithPrivateKey | 用指定私钥对任意数据签名 | — |
4. 生成充值地址(按用户 uid)
go
resp, err := client.CreateDepositAddress(&types.CreateDepositAddressRequest{
UserUID: "100286", // SDK 会自动补成 "<PROJECT_UID>-100286"
NetworkID: 4, // TRON 主网
})
if err != nil {
return err
}
fmt.Println("address:", resp.Address) // TNf6U6U4JtLGBYLvPF7mWQimb8UsagJ22u
fmt.Println("uid:", resp.UID) // Ab3xY9Kq7Z-100286SDK 会自动检查并补上
{ProjectID}-前缀,你传原始用户 ID 或已带前缀的值都可以。同一个 uid 重复调用会返回
HTTP 400: uid already used。业务上应先查本地映射表, 没有再调接口,避免依赖报错做分支。
5. 批量生成充值地址
go
resp, err := client.CreateMultipleDepositAddress(&types.CreateMultipleDepositAddressRequest{
NetworkID: 56, // BSC 主网
Count: 10, // 1~100
})
if err != nil {
return err
}
for _, addr := range resp.Data.Addresses {
fmt.Println(addr.Uid, addr.Address, addr.NetworkName)
}6. 查询用户充值地址
go
resp, err := client.GetDepositAddress(&types.GetDepositAddressRequest{
UserUID: "Ab3xY9Kq7Z-100286", // 这里要传完整 uid(含项目前缀)
NetworkID: 4,
})
if err != nil {
return err
}
fmt.Println(resp.Address)注意与
CreateDepositAddress的差异:创建时 SDK 会自动补前缀,查询时不会,需要传完整 uid。
7. 发起提现
go
import "github.com/google/uuid"
withdrawUID := uuid.NewString() // 全局唯一,同时是幂等键,务必落库
resp, err := client.RequestWithdrawal(types.RequestWithdrawalRequest{
UID: withdrawUID,
AssetID: 2, // USDT
NetworkID: 56, // BSC 主网
Amount: 100.5, // 可读金额
ToAddress: "0x4b2048ede5ca5d962795fec5edf8b41a860e2d4d",
UserUID: "Ab3xY9Kq7Z-100286", // 仅业务记录用,不参与签名与落库
})
if err != nil {
// 网络错误/超时:可以用【同一个 withdrawUID】安全重试
return err
}
fmt.Println(resp.Code, resp.Status, resp.Message)要点:
- 先落库再调用:把
withdrawUID与业务单号绑定后再发请求,这样超时后能安全重试。 Amount是float64,SDK 内部用strconv.FormatFloat(amount, 'f', -1, 64)转成字符串。 大额或高精度金额建议自行确认转换结果,必要时直接用 HTTP 调用传字符串金额,规避浮点误差。- 返回
HTTP 500: uid already used说明这单已经提交过,按已提交处理,不要换新 uid 重发。 - 最终结果以提现回调为准。
8. 查询充值 / 提现记录
go
deposits, err := client.GetDeposits(&types.GetDepositsRequest{Page: 1, PageSize: 10})
withdrawals, err := client.GetWithdrawals(&types.GetWithdrawalsRequest{Page: 1, PageSize: 10})SDK 只暴露了 Page / PageSize。若需要按交易哈希、状态、时间范围等条件过滤, 直接按 02-API-参考.md 第 7 节「查询充值 / 提现记录」发 HTTP 请求即可。
实时入账请以回调为准,本接口用于对账与历史查询。
9. 回调验签
方式一:VerifyPlatformSignature(拿到 bool 结果,自行控制流程)
go
ok, err := client.VerifyPlatformSignature(
client.GetPlatformPublicKey(),
callbackReq.VerifyData, // map[string]interface{} 或结构体
callbackReq.Sig,
)方式二:ParseCallbackData(验签 + 反序列化一步到位)
go
data, err := client.ParseCallbackData(types.CallbackRequestDataWithSig{
Data: respData, // types.CallbackRespData
Sig: sig,
})
if err != nil {
// 验签失败或数据非法
return err
}
fmt.Println(data.Type, data.Uid, data.Status, data.Confirmed, data.FloatAmount)完整的回调服务端示例见 03-回调通知.md 第 7 节「接收端示例(Go)」。
10. 生成密钥对
go
keys, err := client.GenerateKeys()
if err != nil {
return err
}
fmt.Println(keys.PrivateKey) // 自己保管
fmt.Println(keys.PublicKey) // 提交给平台登记
fmt.Println(keys.Address)11. 错误处理
SDK 在 HTTP 状态码非 200 时返回形如下面的 error:
HTTP 403: {"code":403,"status":"error","message":"IP address not whitelisted or not approved","error":"no access"} (outbound_ip=1.2.3.4 local_addr=10.0.0.5:41234)outbound_ip 是 SDK 自动探测的本机公网出口 IP(通过 api.ipify.org), 遇到 403 时可以直接拿这个值去核对 IP 白名单,无需登录服务器排查。
SDK 会把请求/响应摘要打到标准输出(
[LinkePay Debug]前缀)。生产环境如需静默, 请在部署层做日志过滤,或改用直接 HTTP 调用。
建议的重试策略:
| 错误 | 处理 |
|---|---|
网络错误 / 超时 / HTTP 5xx | 指数退避重试,写接口务必带相同的 uid |
HTTP 429 | 退避后重试,并检查调用频率(限流约 125 req/s per IP) |
HTTP 403 | 不要重试,检查 IP 白名单 |
HTTP 401 invalid signature | 不要重试,检查签名实现与已登记公钥 |
HTTP 400/500 uid already used | 不要重试,按已提交处理 |
code 1028 insufficient balance | 不要重试,先补充归集地址余额 |
12. 完整可运行示例
仓库内自带示例(linkepay-sdk-go/example/):
| 目录 | 内容 |
|---|---|
example/generate-keys | 生成商户密钥对 |
example/deposit | 生成充值地址 + 查询充值记录 |
example/withdrawal | 发起提现 |
example/callback-server | 回调接收服务(含验签) |
example/verify-callback-sign | 单独验证回调签名 |
example/verify-sign | 验证任意签名 |
示例代码里的
BaseURL/ 密钥 / API Key 均为占位或历史环境值,运行前请替换为你自己的生产配置。