单钱包 API · 客户端 Demo
本页配套 单钱包 API 文档里 8-10 号"PetaX 服务 APIs"。这些是商户主动调用 PetaX 的接口,Base URL 是{API_BASE_URL}{SW_PATH_PREFIX}。本页 Demo 只演示请求 URL、Header、查询参数和 JSON body 的基本拼装;示例函数只做最基础的错误处理(非 2xx 抛错),不是生产级 SDK,也不包含商户侧 token 管理、重试策略、日志、监控、金额精度封装或业务编排。交易流水接口的响应字段(balanceChange/priorBalance/createdAt/id/userId/username/ccy)与notify-change-balance返回空字符串,均取自书面 API 文档,尚未拿真实 staging PetaX 账号做过实际请求核对——这一步待办(需真实 bearer token)。
PHP
依赖:无(内置 curl)。
<?php
// client.php — PetaX single-wallet-api 客户端 Demo(PHP,调用 PetaX 服务 API)
// 依赖:无(使用内置 curl)
// 仅用于 Demo:这里演示请求构造和基础非 2xx 错误处理;生产客户端可按需补充 token 管理、重试/超时、结构化日志和金额精度处理。
// 三项配置来自接入环境:API_BASE_URL 是 PetaX 域名,SW_PATH_PREFIX 是单钱包路径前缀,BEARER_TOKEN 是调用 PetaX Service API 的 token。
$API_BASE_URL = getenv('PETAX_API_BASE_URL') ?: 'https://your-petax-host.example';
$SW_PATH_PREFIX = getenv('PETAX_SW_PATH_PREFIX') ?: '/api/0857-sw';
$BEARER_TOKEN = getenv('PETAX_BEARER_TOKEN') ?: '';
// 统一封装出站请求:拼 URL、带 Authorization、按需序列化 JSON body,并把非 2xx 响应转成异常。
function petax_request(string $method, string $path, ?array $query = null, ?array $body = null): array {
global $API_BASE_URL, $SW_PATH_PREFIX, $BEARER_TOKEN;
$url = $API_BASE_URL . $SW_PATH_PREFIX . $path;
if ($query) {
// 过滤 null 查询参数,避免把未使用的筛选条件拼进 URL。
$url .= '?' . http_build_query(array_filter($query, fn($v) => $v !== null));
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $BEARER_TOKEN,
'Content-Type: application/json',
],
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
$raw = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 这里不调用 curl_close($ch):PHP 8.0 起它已是空操作,PHP 8.5 起会触发弃用警告。
if ($status < 200 || $status >= 300) {
throw new RuntimeException("PetaX API error ($status): $raw");
}
return ['status' => $status, 'body' => $raw === '' ? null : json_decode($raw, true)];
}
// 端点 8:通知 PetaX 钱包余额已变化。官方文档该接口返回空字符串,所以 demo 只关心 HTTP 是否成功。
function notify_change_balance(float $balance, string $ccy, string $username): void {
petax_request('POST', '/a/sw/wallets/notify-change-balance', null, [
'balance' => $balance, 'ccy' => $ccy, 'username' => $username,
]);
}
// 端点 9:按官方字段查询交易流水;时间、id、refId 都作为可选筛选条件传给 PetaX。
function list_transactions(?string $createdAtGte = null, ?string $createdAtLt = null, ?string $id = null, ?string $refId = null, int $page = 1, int $size = 10): array {
$res = petax_request('GET', '/a/sw/transactions', [
'createdAtGte' => $createdAtGte, 'createdAtLt' => $createdAtLt,
'id' => $id, 'refId' => $refId, 'page' => $page, 'size' => $size,
]);
return $res['body'];
}
// 端点 10:通过 PetaX 返回的交易 id 查询单笔流水。
function get_transaction_by_id(string $id): array {
$res = petax_request('GET', "/a/sw/transactions/$id");
return $res['body'];
}
Node.js
依赖:无(Node 18+ 内置 fetch)。
// client.js — PetaX single-wallet-api 客户端 Demo(Node.js,调用 PetaX 服务 API)
// 运行:Node 18+(内置 fetch)
// 仅用于 Demo:这里演示请求构造和基础非 2xx 错误处理;生产客户端可按需补充 token 管理、重试/超时、结构化日志和金额精度处理。
// 三项配置来自接入环境:API_BASE_URL 是 PetaX 域名,SW_PATH_PREFIX 是单钱包路径前缀,BEARER_TOKEN 是调用 PetaX Service API 的 token。
const API_BASE_URL = process.env.PETAX_API_BASE_URL || 'https://your-petax-host.example';
const SW_PATH_PREFIX = process.env.PETAX_SW_PATH_PREFIX || '/api/0857-sw';
const BEARER_TOKEN = process.env.PETAX_BEARER_TOKEN || '';
// 统一封装出站请求:拼 URL、带 Authorization、按需序列化 JSON body,并把非 2xx 响应转成异常。
async function petaxRequest(method, path, { query, body } = {}) {
const url = new URL(API_BASE_URL + SW_PATH_PREFIX + path);
if (query) {
// 过滤空查询参数,避免把未使用的筛选条件拼进 URL。
for (const [k, v] of Object.entries(query)) {
if (v !== undefined && v !== null) url.searchParams.set(k, v);
}
}
const res = await fetch(url, {
method,
headers: { Authorization: `Bearer ${BEARER_TOKEN}`, 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
const text = await res.text();
if (!res.ok) throw new Error(`PetaX API error (${res.status}): ${text}`);
return text ? JSON.parse(text) : null;
}
// 端点 8:通知 PetaX 钱包余额已变化。官方文档该接口返回空字符串,所以 demo 只关心 HTTP 是否成功。
async function notifyChangeBalance(balance, ccy, username) {
return petaxRequest('POST', '/a/sw/wallets/notify-change-balance', { body: { balance, ccy, username } });
}
// 端点 9:按官方字段查询交易流水;时间、id、refId 都作为可选筛选条件传给 PetaX。
async function listTransactions({ createdAtGte, createdAtLt, id, refId, page = 1, size = 10 } = {}) {
return petaxRequest('GET', '/a/sw/transactions', { query: { createdAtGte, createdAtLt, id, refId, page, size } });
}
// 端点 10:通过 PetaX 返回的交易 id 查询单笔流水。
async function getTransactionById(id) {
return petaxRequest('GET', `/a/sw/transactions/${id}`);
}
module.exports = { notifyChangeBalance, listTransactions, getTransactionById };
Java
依赖:JDK 11+ 内置 java.net.http.HttpClient。
package com.example.petax;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class PetaxClient {
// 三项配置来自接入环境:API_BASE_URL 是 PetaX 域名,SW_PATH_PREFIX 是单钱包路径前缀,BEARER_TOKEN 是调用 PetaX Service API 的 token。
private static final String API_BASE_URL = System.getenv().getOrDefault("PETAX_API_BASE_URL", "https://your-petax-host.example");
private static final String SW_PATH_PREFIX = System.getenv().getOrDefault("PETAX_SW_PATH_PREFIX", "/api/0857-sw");
private static final String BEARER_TOKEN = System.getenv().getOrDefault("PETAX_BEARER_TOKEN", "");
// 仅用于 Demo:这里演示请求构造和基础非 2xx 错误处理;生产客户端可按需补充 token 管理、重试/超时、结构化日志和金额精度处理。
private final HttpClient http = HttpClient.newHttpClient();
// 统一封装出站请求:拼 URL、带 Authorization、按需发送 JSON body,并把非 2xx 响应转成异常。
private String request(String method, String path, String query, String jsonBody) throws Exception {
String url = API_BASE_URL + SW_PATH_PREFIX + path + (query != null ? "?" + query : "");
var builder = HttpRequest.newBuilder(URI.create(url))
.header("Authorization", "Bearer " + BEARER_TOKEN)
.header("Content-Type", "application/json");
builder = jsonBody != null
? builder.method(method, HttpRequest.BodyPublishers.ofString(jsonBody))
: builder.method(method, HttpRequest.BodyPublishers.noBody());
HttpResponse<String> res = http.send(builder.build(), HttpResponse.BodyHandlers.ofString());
if (res.statusCode() < 200 || res.statusCode() >= 300) {
throw new RuntimeException("PetaX API error (" + res.statusCode() + "): " + res.body());
}
return res.body();
}
// 端点 8:通知 PetaX 钱包余额已变化。官方文档该接口返回空字符串,所以 demo 只关心 HTTP 是否成功。
public String notifyChangeBalance(double balance, String ccy, String username) throws Exception {
String body = String.format("{\"balance\":%s,\"ccy\":\"%s\",\"username\":\"%s\"}", balance, ccy, username);
return request("POST", "/a/sw/wallets/notify-change-balance", null, body);
}
// 端点 9:按官方字段查询交易流水;时间、id、refId 都作为可选筛选条件传给 PetaX。
public String listTransactions(String createdAtGte, String createdAtLt, String id, String refId, int page, int size) throws Exception {
StringBuilder q = new StringBuilder("page=" + page + "&size=" + size);
if (createdAtGte != null) q.append("&createdAtGte=").append(createdAtGte);
if (createdAtLt != null) q.append("&createdAtLt=").append(createdAtLt);
if (id != null) q.append("&id=").append(id);
if (refId != null) q.append("&refId=").append(refId);
return request("GET", "/a/sw/transactions", q.toString(), null);
}
// 端点 10:通过 PetaX 返回的交易 id 查询单笔流水。
public String getTransactionById(String id) throws Exception {
return request("GET", "/a/sw/transactions/" + id, null, null);
}
}
Go
依赖:无(标准库 net/http)。放在独立的 client 包里,方便和你自己的服务代码放一起。
// client.go — PetaX single-wallet-api 客户端 Demo(Go,调用 PetaX 服务 API)
package petaxclient
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
)
// 仅用于 Demo:这里演示请求构造和基础非 2xx 错误处理;生产客户端可按需补充 token 管理、重试/超时、结构化日志和金额精度处理。
// 三项配置来自接入环境:apiBaseURL 是 PetaX 域名,swPathPrefix 是单钱包路径前缀,bearerToken 是调用 PetaX Service API 的 token。
var (
apiBaseURL = getenvOr("PETAX_API_BASE_URL", "https://your-petax-host.example")
swPathPrefix = getenvOr("PETAX_SW_PATH_PREFIX", "/api/0857-sw")
bearerToken = getenvOr("PETAX_BEARER_TOKEN", "")
)
func getenvOr(k, def string) string {
if v := os.Getenv(k); v != "" {
return v
}
return def
}
// 统一封装出站请求:拼 URL、带 Authorization、按需序列化 JSON body,并把非 2xx 响应转成 error。
func petaxRequest(method, path string, query url.Values, body interface{}) ([]byte, error) {
u := apiBaseURL + swPathPrefix + path
if query != nil {
u += "?" + query.Encode()
}
var reader io.Reader
if body != nil {
b, _ := json.Marshal(body)
reader = bytes.NewReader(b)
}
req, err := http.NewRequest(method, u, reader)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+bearerToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("PetaX API error (%d): %s", resp.StatusCode, respBody)
}
return respBody, nil
}
// 端点 8:通知 PetaX 钱包余额已变化。官方文档该接口返回空字符串,所以 demo 只关心 HTTP 是否成功。
func NotifyChangeBalance(balance float64, ccy, username string) error {
_, err := petaxRequest("POST", "/a/sw/wallets/notify-change-balance", nil, map[string]interface{}{
"balance": balance, "ccy": ccy, "username": username,
})
return err
}
// 端点 9:按官方字段查询交易流水;时间、id、refId 都作为可选筛选条件传给 PetaX。
func ListTransactions(createdAtGte, createdAtLt, id, refId string, page, size int) ([]map[string]interface{}, error) {
q := url.Values{}
if createdAtGte != "" {
q.Set("createdAtGte", createdAtGte)
}
if createdAtLt != "" {
q.Set("createdAtLt", createdAtLt)
}
if id != "" {
q.Set("id", id)
}
if refId != "" {
q.Set("refId", refId)
}
q.Set("page", fmt.Sprintf("%d", page))
q.Set("size", fmt.Sprintf("%d", size))
body, err := petaxRequest("GET", "/a/sw/transactions", q, nil)
if err != nil {
return nil, err
}
var out []map[string]interface{}
if err := json.Unmarshal(body, &out); err != nil {
return nil, err
}
return out, nil
}
// 端点 10:通过 PetaX 返回的交易 id 查询单笔流水。
func GetTransactionByID(id string) (map[string]interface{}, error) {
body, err := petaxRequest("GET", "/a/sw/transactions/"+id, nil, nil)
if err != nil {
return nil, err
}
var out map[string]interface{}
if err := json.Unmarshal(body, &out); err != nil {
return nil, err
}
return out, nil
}
Python
依赖:pip install requests。
# client.py — PetaX single-wallet-api 客户端 Demo(Python,调用 PetaX 服务 API)
import os
import requests
# 三项配置来自接入环境:API_BASE_URL 是 PetaX 域名,SW_PATH_PREFIX 是单钱包路径前缀,
# BEARER_TOKEN 是调用 PetaX Service API 的 token。
API_BASE_URL = os.environ.get("PETAX_API_BASE_URL", "https://your-petax-host.example")
SW_PATH_PREFIX = os.environ.get("PETAX_SW_PATH_PREFIX", "/api/0857-sw")
BEARER_TOKEN = os.environ.get("PETAX_BEARER_TOKEN", "")
# 仅用于 Demo:这里演示请求构造和基础非 2xx 错误处理;
# 生产客户端可按需补充 token 管理、重试/超时、结构化日志和金额精度处理。
# 统一封装出站请求:拼 URL、带 Authorization、按需发送 JSON body,并把非 2xx 响应转成异常。
def _request(method, path, params=None, json_body=None):
url = API_BASE_URL + SW_PATH_PREFIX + path
resp = requests.request(
method, url,
# 过滤空查询参数,避免把未使用的筛选条件拼进 URL。
params={k: v for k, v in (params or {}).items() if v is not None},
json=json_body,
headers={"Authorization": f"Bearer {BEARER_TOKEN}"},
)
if not resp.ok:
raise RuntimeError(f"PetaX API error ({resp.status_code}): {resp.text}")
return resp.json() if resp.text else None
# 端点 8:通知 PetaX 钱包余额已变化。官方文档该接口返回空字符串,所以 demo 只关心 HTTP 是否成功。
def notify_change_balance(balance, ccy, username):
return _request("POST", "/a/sw/wallets/notify-change-balance", json_body={
"balance": balance, "ccy": ccy, "username": username,
})
# 端点 9:按官方字段查询交易流水;时间、id、refId 都作为可选筛选条件传给 PetaX。
def list_transactions(created_at_gte=None, created_at_lt=None, id=None, ref_id=None, page=1, size=10):
return _request("GET", "/a/sw/transactions", params={
"createdAtGte": created_at_gte, "createdAtLt": created_at_lt,
"id": id, "refId": ref_id, "page": page, "size": size,
})
# 端点 10:通过 PetaX 返回的交易 id 查询单笔流水。
def get_transaction_by_id(id):
return _request("GET", f"/a/sw/transactions/{id}")