單錢包 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 = 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') ?: '';
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) {
$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)];
}
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,
]);
}
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'];
}
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 管理、重試/超時、結構化日誌和金額精度處理。
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 || '';
async function petaxRequest(method, path, { query, body } = {}) {
const url = new URL(API_BASE_URL + SW_PATH_PREFIX + path);
if (query) {
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;
}
async function notifyChangeBalance(balance, ccy, username) {
return petaxRequest('POST', '/a/sw/wallets/notify-change-balance', { body: { balance, ccy, username } });
}
async function listTransactions({ createdAtGte, createdAtLt, id, refId, page = 1, size = 10 } = {}) {
return petaxRequest('GET', '/a/sw/transactions', { query: { createdAtGte, createdAtLt, id, refId, page, size } });
}
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 {
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();
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();
}
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);
}
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);
}
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 管理、重試/超時、結構化日誌和金額精度處理。
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
}
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
}
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
}
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
}
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 = 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 管理、重試/超時、結構化日誌和金額精度處理。
def _request(method, path, params=None, json_body=None):
url = API_BASE_URL + SW_PATH_PREFIX + path
resp = requests.request(
method, 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
def notify_change_balance(balance, ccy, username):
return _request("POST", "/a/sw/wallets/notify-change-balance", json_body={
"balance": balance, "ccy": ccy, "username": username,
})
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,
})
def get_transaction_by_id(id):
return _request("GET", f"/a/sw/transactions/{id}")