curl --get "${BASE_URL}/api/v2/plan/list" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Accept: application/json" \
--data-urlencode merchant_id=48290713 \
--data-urlencode page=1 \
--data-urlencode page_size=20import json
import os
import urllib.parse
import urllib.request
base_url = os.environ["BASE_URL"].rstrip("/")
url = base_url + "/api/v2/plan/list"
headers = {"Accept": "application/json"}
headers["Authorization"] = "Bearer " + os.environ["ACCESS_TOKEN"]
params = {
"merchant_id": "48290713",
"page": "1",
"page_size": "20",
}
url += "?" + urllib.parse.urlencode(params)
body = None
request = urllib.request.Request(url, data=body, headers=headers, method="GET")
with urllib.request.urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
const env = (name) => {
const value = process.env[name];
if (!value) throw new Error(`Missing environment variable: ${name}`);
return value;
};
const baseUrl = env("BASE_URL").replace(/\/+$/, "");
const url = new URL(baseUrl + "/api/v2/plan/list");
const headers = { Accept: "application/json" };
headers.Authorization = `Bearer ${env("ACCESS_TOKEN")}`;
const params = new URLSearchParams({
"merchant_id": "48290713",
"page": "1",
"page_size": "20",
});
url.search = params.toString();
const response = await fetch(url, {
method: "GET",
headers,
signal: AbortSignal.timeout(30_000),
});
console.log(await response.text());
<?php
$env = static function (string $name): string {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Missing environment variable: " . $name);
}
return $value;
};
$baseUrl = rtrim($env('BASE_URL'), '/');
$url = $baseUrl . "/api/v2/plan/list";
$headers = ['Accept: application/json'];
$headers[] = 'Authorization: Bearer ' . $env('ACCESS_TOKEN');
$params = [
"merchant_id" => "48290713",
"page" => "1",
"page_size" => "20",
];
$url .= '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$curl = curl_init($url);
curl_setopt_array($curl, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($curl);
if ($response === false) {
$error = curl_error($curl);
curl_close($curl);
throw new RuntimeException($error);
}
curl_close($curl);
echo $response, PHP_EOL;
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
)
func mustEnv(name string) string {
value := os.Getenv(name)
if value == "" { panic("Missing environment variable: " + name) }
return value
}
func main() {
baseURL := strings.TrimRight(mustEnv("BASE_URL"), "/")
endpoint := baseURL + "/api/v2/plan/list"
params := url.Values{}
params.Set("merchant_id", "48290713")
params.Set("page", "1")
params.Set("page_size", "20")
endpoint += "?" + params.Encode()
req, err := http.NewRequest("GET", endpoint, nil)
if err != nil { panic(err) }
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer " + mustEnv("ACCESS_TOKEN"))
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(req)
if err != nil { panic(err) }
defer response.Body.Close()
result, err := io.ReadAll(response.Body)
if err != nil { panic(err) }
fmt.Println(string(result))
}
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
public class Example {
static String requireEnv(String name) {
String value = System.getenv(name);
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("Missing environment variable: " + name);
}
return value;
}
public static void main(String[] args) throws Exception {
String baseUrl = requireEnv("BASE_URL").replaceAll("/+$", "");
String endpoint = baseUrl + "/api/v2/plan/list";
Map<String, String> params = new LinkedHashMap<>();
params.put("merchant_id", "48290713");
params.put("page", "1");
params.put("page_size", "20");
String encoded = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "="
+ URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
endpoint += "?" + encoded;
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(endpoint))
.timeout(Duration.ofSeconds(30))
.header("Accept", "application/json");
builder.header("Authorization", "Bearer " + requireEnv("ACCESS_TOKEN"));
HttpRequest request = builder.method("GET", HttpRequest.BodyPublishers.noBody()).build();
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
System.out.println(response.body());
}
}
require "net/http"
require "uri"
base_url = ENV.fetch("BASE_URL").sub(%r{/+$}, "")
uri = URI(base_url + "/api/v2/plan/list")
params = {
"merchant_id" => "48290713",
"page" => "1",
"page_size" => "20",
}
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request["Accept"] = "application/json"
request["Authorization"] = "Bearer " + ENV.fetch("ACCESS_TOKEN")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"
http.open_timeout = 30
http.read_timeout = 30
puts http.request(request).body
{
"code": 0,
"message": "ok",
"data": {
"data": [
{
"plan_id": "TPL62038591",
"plan_name": "Monthly membership",
"description": "Monthly subscription template",
"status": 1,
"invoice_account_code": null,
"invoice_theme_id": null,
"surcharge_config": {
"direct_debit_surcharge": false,
"visa_domestic_surcharge": false,
"visa_international_surcharge": false,
"mastercard_domestic_surcharge": false,
"mastercard_international_surcharge": false,
"amex_domestic_surcharge": false,
"amex_international_surcharge": false
},
"surcharge_config_enabled": [],
"surcharge_config_selected": [],
"recurring": {
"enabled": 1,
"schedule_name": "Monthly fee",
"recurring_type": 3,
"amount": "25.50",
"total_amount": null,
"start_date": null,
"end_date": null,
"end_terms": null,
"day_of_debit": "FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=15",
"day_of_debit_dtstart": null,
"process_type": 5,
"custom_cycle_type": 0,
"custom_cycle": 0,
"custom_cycle_type_text": "",
"frequency": "Monthly"
},
"one_off": {
"enabled": 0,
"schedule_name": null,
"amount": null,
"description": null,
"payment_date": null
},
"created_at": "2026-10-28 09:00:00",
"updated_at": "2026-10-28 09:00:00",
"deleted_at": null
}
],
"current_page": 1,
"per_page": 20,
"total": 1
}
}查询可用订阅模板
查询授权商户及指定业务范围内可用的订阅模板。仅返回 ACTIVE、已启用、非阶梯且非 By agreement 的模板,按创建时间倒序排列。价格筛选针对模板最新价格。区间参数须由调用方保证起点不大于终点。
列表用于选择候选模板,创建订阅时仍须校验模板定价、启用的收费段和所需日期;不满足创建条件时返回业务失败。
所有示例均为格式示例,客户、订单、卡及账户数据须替换为测试环境获准使用的数据。BASE_URL 为服务根域名,不附加 /api/v2;ACCESS_TOKEN 为 /oauth/token 返回的 access_token。日期示例为 2030 年,执行时请改为满足当前日期限制的实际日期。
curl --get "${BASE_URL}/api/v2/plan/list" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Accept: application/json" \
--data-urlencode merchant_id=48290713 \
--data-urlencode page=1 \
--data-urlencode page_size=20import json
import os
import urllib.parse
import urllib.request
base_url = os.environ["BASE_URL"].rstrip("/")
url = base_url + "/api/v2/plan/list"
headers = {"Accept": "application/json"}
headers["Authorization"] = "Bearer " + os.environ["ACCESS_TOKEN"]
params = {
"merchant_id": "48290713",
"page": "1",
"page_size": "20",
}
url += "?" + urllib.parse.urlencode(params)
body = None
request = urllib.request.Request(url, data=body, headers=headers, method="GET")
with urllib.request.urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
const env = (name) => {
const value = process.env[name];
if (!value) throw new Error(`Missing environment variable: ${name}`);
return value;
};
const baseUrl = env("BASE_URL").replace(/\/+$/, "");
const url = new URL(baseUrl + "/api/v2/plan/list");
const headers = { Accept: "application/json" };
headers.Authorization = `Bearer ${env("ACCESS_TOKEN")}`;
const params = new URLSearchParams({
"merchant_id": "48290713",
"page": "1",
"page_size": "20",
});
url.search = params.toString();
const response = await fetch(url, {
method: "GET",
headers,
signal: AbortSignal.timeout(30_000),
});
console.log(await response.text());
<?php
$env = static function (string $name): string {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Missing environment variable: " . $name);
}
return $value;
};
$baseUrl = rtrim($env('BASE_URL'), '/');
$url = $baseUrl . "/api/v2/plan/list";
$headers = ['Accept: application/json'];
$headers[] = 'Authorization: Bearer ' . $env('ACCESS_TOKEN');
$params = [
"merchant_id" => "48290713",
"page" => "1",
"page_size" => "20",
];
$url .= '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$curl = curl_init($url);
curl_setopt_array($curl, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($curl);
if ($response === false) {
$error = curl_error($curl);
curl_close($curl);
throw new RuntimeException($error);
}
curl_close($curl);
echo $response, PHP_EOL;
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
)
func mustEnv(name string) string {
value := os.Getenv(name)
if value == "" { panic("Missing environment variable: " + name) }
return value
}
func main() {
baseURL := strings.TrimRight(mustEnv("BASE_URL"), "/")
endpoint := baseURL + "/api/v2/plan/list"
params := url.Values{}
params.Set("merchant_id", "48290713")
params.Set("page", "1")
params.Set("page_size", "20")
endpoint += "?" + params.Encode()
req, err := http.NewRequest("GET", endpoint, nil)
if err != nil { panic(err) }
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer " + mustEnv("ACCESS_TOKEN"))
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(req)
if err != nil { panic(err) }
defer response.Body.Close()
result, err := io.ReadAll(response.Body)
if err != nil { panic(err) }
fmt.Println(string(result))
}
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
public class Example {
static String requireEnv(String name) {
String value = System.getenv(name);
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("Missing environment variable: " + name);
}
return value;
}
public static void main(String[] args) throws Exception {
String baseUrl = requireEnv("BASE_URL").replaceAll("/+$", "");
String endpoint = baseUrl + "/api/v2/plan/list";
Map<String, String> params = new LinkedHashMap<>();
params.put("merchant_id", "48290713");
params.put("page", "1");
params.put("page_size", "20");
String encoded = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "="
+ URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
endpoint += "?" + encoded;
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(endpoint))
.timeout(Duration.ofSeconds(30))
.header("Accept", "application/json");
builder.header("Authorization", "Bearer " + requireEnv("ACCESS_TOKEN"));
HttpRequest request = builder.method("GET", HttpRequest.BodyPublishers.noBody()).build();
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
System.out.println(response.body());
}
}
require "net/http"
require "uri"
base_url = ENV.fetch("BASE_URL").sub(%r{/+$}, "")
uri = URI(base_url + "/api/v2/plan/list")
params = {
"merchant_id" => "48290713",
"page" => "1",
"page_size" => "20",
}
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request["Accept"] = "application/json"
request["Authorization"] = "Bearer " + ENV.fetch("ACCESS_TOKEN")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"
http.open_timeout = 30
http.read_timeout = 30
puts http.request(request).body
{
"code": 0,
"message": "ok",
"data": {
"data": [
{
"plan_id": "TPL62038591",
"plan_name": "Monthly membership",
"description": "Monthly subscription template",
"status": 1,
"invoice_account_code": null,
"invoice_theme_id": null,
"surcharge_config": {
"direct_debit_surcharge": false,
"visa_domestic_surcharge": false,
"visa_international_surcharge": false,
"mastercard_domestic_surcharge": false,
"mastercard_international_surcharge": false,
"amex_domestic_surcharge": false,
"amex_international_surcharge": false
},
"surcharge_config_enabled": [],
"surcharge_config_selected": [],
"recurring": {
"enabled": 1,
"schedule_name": "Monthly fee",
"recurring_type": 3,
"amount": "25.50",
"total_amount": null,
"start_date": null,
"end_date": null,
"end_terms": null,
"day_of_debit": "FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=15",
"day_of_debit_dtstart": null,
"process_type": 5,
"custom_cycle_type": 0,
"custom_cycle": 0,
"custom_cycle_type_text": "",
"frequency": "Monthly"
},
"one_off": {
"enabled": 0,
"schedule_name": null,
"amount": null,
"description": null,
"payment_date": null
},
"created_at": "2026-10-28 09:00:00",
"updated_at": "2026-10-28 09:00:00",
"deleted_at": null
}
],
"current_page": 1,
"per_page": 20,
"total": 1
}
}授权
OAuth2 client_credentials 授权。access_token 到期后重新获取。
查询参数
业务标识,由 BillBuddy 分配;必填,最长 20 字符,须属于 OAuth 凭据所属商户。
20页码,默认 1。
x >= 1每页条数,默认 20,最大值未限定。
x >= 1模板名称模糊匹配。
255模板扣款频率:1 One-off、3 Weekly、4 Fortnightly、5 Monthly、6 Quarterly、7 Half Yearly、8 Yearly、12 Custom。
1, 3, 4, 5, 6, 7, 8, 12, null 模板最新价格的下限。 金额以主货币单位计,例如 10.50 表示 AUD 10.50,最多两位小数。接受数值或数字字符串,最小 0,两种类型遵守相同范围限制。
x >= 0必须是以下数值的倍数 0.01模板最新价格的上限。 金额以主货币单位计,例如 10.50 表示 AUD 10.50,最多两位小数。接受数值或数字字符串,最小 0,两种类型遵守相同范围限制。
x >= 0必须是以下数值的倍数 0.01创建日期起点,含当日 00:00:00。 必须使用 YYYY-MM-DD。
创建日期终点,含当日 23:59:59。 必须使用 YYYY-MM-DD。
更新日期起点,含当日 00:00:00。 必须使用 YYYY-MM-DD。
更新日期终点,含当日 23:59:59。 必须使用 YYYY-MM-DD。