エージェント経由の予約を受ける
お客さまのAIエージェントが貴店の空き枠を確認し、予約・変更・キャンセルできるようにします。確認は受付確認デスクで行います。
公開中予約は提供中です。オンライン決済も提供中で、2026年10月22日に最初の事業者(パーソナルトレーナー)が有効にしました。
このページは、事業者の方と、事業者に代わって連携を担当する方向けです。
仕組み
サービス、料金、空き枠は、貴店が一つずつ確認してから公開します。お客さまが自分のAIに予約を頼むと、AIがSOPの予約インターフェースを通じて送信します。貴店は受付確認デスクで承認または辞退し、LINEの通知も届きます。
手順
- お客様 → エージェント:サービスを依頼
- エージェント → SOP:事業者と空き枠を検索
- SOP → エージェント:サービス、料金、空き枠を返す
- お客様 → エージェント:枠を選ぶ
- エージェント → SOP:request_booking
- SOP → エージェント:枠を確保:awaiting_payment、金額、期限、payment_handlers
- お客様 → エージェント:ウォレットで金額を承認
- エージェント → SOP:支払い認証情報でcomplete_booking
- SOP → SOP:1回だけ決済。事業者が辞退・未確認なら全額返金
- SOP → 事業者:新しい予約を通知
- 事業者 → SOP:初回の予約は事業者が確認。期限内に確認がなければ解放して返金
- SOP → エージェント:予約状況(確定または確認待ち)と決済結果を返す
- エージェント → お客様:確定、または事業者の確認待ちを伝える
エージェントにできること
| 操作 | MCPツール | REST |
|---|---|---|
| 空き枠の確認 | get_availability | GET availability |
| 予約の作成 | request_booking | POST bookings |
| 予約の照会 | get_booking_status | GET bookings/{booking_id} |
| 変更 | modify_booking | PATCH bookings/{booking_id} |
| キャンセル | cancel_booking | DELETE bookings/{booking_id} |
| 支払い | complete_booking | POST bookings/{booking_id}/complete |
各操作のパラメーターとレスポンスは予約サービスに接続するをご覧ください。以下のサンプルで、事業者側が目にする内容を説明します。
空き枠の確認
エージェントはまず貴店の空き枠を確認します。各時間帯には固定のslot_idがあり、予約の作成や変更ではこれを使います。レスポンスには残り枠と料金も含まれます。
予約可能な時間枠の確認
curl
curl -sS "https://mcp.srct.tw/api/v1/businesses/coach-dunken/availability?service_id=pt&days=2" \
-H "User-Agent: my-agent/1.0"
Python
import json
import urllib.error
import urllib.request
BASE = "https://mcp.srct.tw"
def call(method, path, body=None, headers=None):
req = urllib.request.Request(
BASE + path,
data=None if body is None else json.dumps(body).encode(),
method=method,
headers={"User-Agent": "my-agent/1.0", "Content-Type": "application/json", **(headers or {})},
)
try:
with urllib.request.urlopen(req) as res:
return res.status, json.loads(res.read())
except urllib.error.HTTPError as err: # 4xx and 5xx responses still carry a JSON body
return err.code, json.loads(err.read())
def show(status, body):
print("HTTP", status)
print(json.dumps(body, ensure_ascii=False, indent=2))
show(*call("GET", "/api/v1/businesses/coach-dunken/availability?service_id=pt&days=2"))
Node.js
const BASE = "https://mcp.srct.tw";
async function call(method, path, body, headers = {}) {
const res = await fetch(BASE + path, {
method,
headers: { "User-Agent": "my-agent/1.0", "Content-Type": "application/json", ...headers },
body: body === undefined ? undefined : JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
function show({ status, body }) {
console.log("HTTP", status);
console.log(JSON.stringify(body, null, 2));
}
(async () => {
show(await call("GET", "/api/v1/businesses/coach-dunken/availability?service_id=pt&days=2"));
})();
レスポンス例
HTTP 200
{
"ok": true,
"service_id": "pt",
"bookable_here": true,
"payment": "venue",
"timezone": "Asia/Taipei",
"earliest_bookable": "120 minutes from now",
"online_cancellation": "Online cancellation closes 24 hours before the start time; after that, contact the business directly.",
"quantity_unit": "位",
"slots": [
{
"slot_id": "2026-10-22T08:00",
"slot": "2026-10-22T08:00",
"start": "2026-10-22T08:00:00+08:00",
"label": "10/22(四)08:00",
"remaining": 1,
"price": {
"amount": 1800000,
"currency": "twd",
"per": "person or place",
"text": "NT$18,000/10堂"
},
"resource": {
"teacher": "Dunken"
}
},
{
"slot_id": "2026-10-22T09:00",
"slot": "2026-10-22T09:00",
"start": "2026-10-22T09:00:00+08:00",
"label": "10/22(四)09:00",
"remaining": 1,
"price": {
"amount": 1800000,
"currency": "twd",
"per": "person or place",
"text": "NT$18,000/10堂"
},
"resource": {
"teacher": "Dunken"
}
},
…
]
}本番サービスで実行済み(読み取りのみ):表示用に省略しています。…は省略部分を示します。price.amountは通貨の最小単位(台湾ドルの100倍)です。時刻はAsia/Taipeiです。枠は呼び出した日によって変わります。
予約の作成
お客さまがサービス、時間、人数、連絡先に同意すると、エージェントが予約を送信します。結果は貴店の設定によって変わります。店頭払いの予約は、すぐに確定(confirmed)するか、貴店の確認待ち(pending)になります。オンライン決済の予約は、まずawaiting_paymentになり、支払いが完了してから貴店に通知されます。
予約の作成(現地払い)
curl
# This creates a real booking at a real business. Use a slot value from the availability response.
curl -sS -X POST "https://mcp.srct.tw/api/v1/businesses/<BUSINESS_ID>/bookings" \
-H "User-Agent: my-agent/1.0" \
-H "Content-Type: application/json" \
-d '{"service_id":"pt","slot":"<SLOT>","quantity":1,"customer_name":"Example Customer","phone":"0900000000","email":"customer@example.com"}'
Python
# This creates a real booking at a real business. Use a slot value from the availability response.
import json
import urllib.error
import urllib.request
BASE = "https://mcp.srct.tw"
def call(method, path, body=None, headers=None):
req = urllib.request.Request(
BASE + path,
data=None if body is None else json.dumps(body).encode(),
method=method,
headers={"User-Agent": "my-agent/1.0", "Content-Type": "application/json", **(headers or {})},
)
try:
with urllib.request.urlopen(req) as res:
return res.status, json.loads(res.read())
except urllib.error.HTTPError as err: # 4xx and 5xx responses still carry a JSON body
return err.code, json.loads(err.read())
def show(status, body):
print("HTTP", status)
print(json.dumps(body, ensure_ascii=False, indent=2))
BUSINESS_ID = "<BUSINESS_ID>"
status, body = call("POST", f"/api/v1/businesses/{BUSINESS_ID}/bookings", {
"service_id": "pt",
"slot": "<SLOT>", # the "slot" value from the availability response
"quantity": 1,
"customer_name": "Example Customer",
"phone": "0900000000",
"email": "customer@example.com",
})
show(status, body)
# Keep booking_id and status_token: every later call for this booking needs both.
Node.js
// This creates a real booking at a real business. Use a slot value from the availability response.
const BASE = "https://mcp.srct.tw";
async function call(method, path, body, headers = {}) {
const res = await fetch(BASE + path, {
method,
headers: { "User-Agent": "my-agent/1.0", "Content-Type": "application/json", ...headers },
body: body === undefined ? undefined : JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
function show({ status, body }) {
console.log("HTTP", status);
console.log(JSON.stringify(body, null, 2));
}
const BUSINESS_ID = "<BUSINESS_ID>";
(async () => {
show(await call("POST", `/api/v1/businesses/${BUSINESS_ID}/bookings`, {
service_id: "pt",
slot: "<SLOT>", // the "slot" value from the availability response
quantity: 1,
customer_name: "Example Customer",
phone: "0900000000",
email: "customer@example.com",
}));
// Keep booking_id and status_token: every later call for this booking needs both.
})();
レスポンス例
HTTP 201
{
"ok": true,
"booking": {
"booking_id": "2QAC3NW5",
"status": "pending",
"status_text": "Waiting for the business to confirm",
"business_id": "coach-dunken",
"business_name": "Dunken教練",
"service_id": "pt",
"service_name": "PT一對一教練課",
"slot": "2026-10-25T08:00",
"start": "2026-10-25T08:00:00+08:00",
"label": "10/25(日)08:00",
"quantity": 1,
"quantity_unit": "位",
"payment": "Pay at the venue",
"details": [
"老師:Dunken"
],
"why_pending": "First booking with this business from these contact details, so the business confirms it.",
"confirm_by": "2026-10-22T01:00:00+08:00",
"hold": "Bookings that need the business's confirmation are held for 10 minutes. If the business does not confirm by then, the hold is released automatically and the customer can choose another slot.",
"online_cancel_until": "2026-10-24T08:00:00+08:00"
},
"status_token": "<STATUS_TOKEN>",
"status_token_note": "Needed with booking_id to check, pay, change or cancel this booking later. It gives access to this booking only, and … does not show it again.",
"contact_note": "If this booking cannot be cancelled with cancel_booking, the customer can contact the business directly: …"
}ローカル環境で実行済み:本番と同じ項目で返るよう、本番事業者のサービスを写したコネクターのローカルコピーで実行しました。status_tokenは<STATUS_TOKEN>に置き換えています。新しい連絡先での初回予約は事業者の確認待ち(statusはpending)になります。
変更
エージェントはお客さまに代わって、時間帯または人数を変更できます。元の枠は解放されます。オンラインで支払い済みの予約は、時間帯のみ変更できます。人数を変えると金額が変わるため、いったんキャンセルして予約し直す必要があります。変更とオンラインでのキャンセルは、同じ締め切りまで可能です。
予約の日時変更
curl
curl -sS -X PATCH "https://mcp.srct.tw/api/v1/businesses/<BUSINESS_ID>/bookings/<BOOKING_ID>" \
-H "User-Agent: my-agent/1.0" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <STATUS_TOKEN>" \
-d '{"slot":"<NEW_SLOT>"}'
Python
import json
import urllib.error
import urllib.request
BASE = "https://mcp.srct.tw"
def call(method, path, body=None, headers=None):
req = urllib.request.Request(
BASE + path,
data=None if body is None else json.dumps(body).encode(),
method=method,
headers={"User-Agent": "my-agent/1.0", "Content-Type": "application/json", **(headers or {})},
)
try:
with urllib.request.urlopen(req) as res:
return res.status, json.loads(res.read())
except urllib.error.HTTPError as err: # 4xx and 5xx responses still carry a JSON body
return err.code, json.loads(err.read())
def show(status, body):
print("HTTP", status)
print(json.dumps(body, ensure_ascii=False, indent=2))
BUSINESS_ID = "<BUSINESS_ID>"
BOOKING_ID = "<BOOKING_ID>" # from the create response
STATUS_TOKEN = "<STATUS_TOKEN>" # from the create response (shown once)
AUTH = {"Authorization": f"Bearer {STATUS_TOKEN}"}
NEW_SLOT = "<NEW_SLOT>" # another "slot" value from the availability response
show(*call("PATCH", f"/api/v1/businesses/{BUSINESS_ID}/bookings/{BOOKING_ID}", {"slot": NEW_SLOT}, AUTH))
Node.js
const BASE = "https://mcp.srct.tw";
async function call(method, path, body, headers = {}) {
const res = await fetch(BASE + path, {
method,
headers: { "User-Agent": "my-agent/1.0", "Content-Type": "application/json", ...headers },
body: body === undefined ? undefined : JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
function show({ status, body }) {
console.log("HTTP", status);
console.log(JSON.stringify(body, null, 2));
}
const BUSINESS_ID = "<BUSINESS_ID>";
const BOOKING_ID = "<BOOKING_ID>"; // from the create response
const STATUS_TOKEN = "<STATUS_TOKEN>"; // from the create response (shown once)
const AUTH = { Authorization: `Bearer ${STATUS_TOKEN}` };
const NEW_SLOT = "<NEW_SLOT>"; // another "slot" value from the availability response
(async () => {
show(await call("PATCH", `/api/v1/businesses/${BUSINESS_ID}/bookings/${BOOKING_ID}`, { slot: NEW_SLOT }, AUTH));
})();
レスポンス例
HTTP 200
{
"ok": true,
"changed": {
"from": {
"slot": "2026-10-25T08:00",
"quantity": 1
},
"to": {
"slot": "2026-10-26T08:00",
"quantity": 1
}
},
"booking": {
"booking_id": "2QAC3NW5",
"status": "pending",
"status_text": "Waiting for the business to confirm",
"business_id": "coach-dunken",
"business_name": "Dunken教練",
"service_id": "pt",
"service_name": "PT一對一教練課",
"slot": "2026-10-26T08:00",
"start": "2026-10-26T08:00:00+08:00",
"label": "10/26(一)08:00",
"quantity": 1,
"quantity_unit": "位",
"payment": "Pay at the venue",
"details": [
"老師:Dunken"
],
"why_pending": "First booking with this business from these contact details, so the business confirms it.",
"confirm_by": "2026-10-22T01:00:00+08:00",
"hold": "Bookings that need the business's confirmation are held for 10 minutes. If the business does not confirm by then, the hold is released automatically and the customer can choose another slot.",
"online_cancel_until": "2026-10-25T08:00:00+08:00"
}
}ローカル環境で実行済み:コネクターのローカルコピーで実行。元の枠は解放され、新しい枠が確保されます。レスポンスにfromとtoが含まれます。
キャンセル
お客さまがAIからキャンセルすると、枠が解放され、受付確認デスクに記録が残ります。オンラインでキャンセルできる期限は貴店が設定します。期限を過ぎたら、お客さまは貴店に直接連絡します。お客さまがオンラインで支払い済みの予約をキャンセルした場合は、決済手数料とプラットフォーム手数料を差し引いて返金します。
予約のキャンセル
curl
curl -sS -X DELETE "https://mcp.srct.tw/api/v1/businesses/<BUSINESS_ID>/bookings/<BOOKING_ID>" \
-H "User-Agent: my-agent/1.0" \
-H "Authorization: Bearer <STATUS_TOKEN>"
Python
import json
import urllib.error
import urllib.request
BASE = "https://mcp.srct.tw"
def call(method, path, body=None, headers=None):
req = urllib.request.Request(
BASE + path,
data=None if body is None else json.dumps(body).encode(),
method=method,
headers={"User-Agent": "my-agent/1.0", "Content-Type": "application/json", **(headers or {})},
)
try:
with urllib.request.urlopen(req) as res:
return res.status, json.loads(res.read())
except urllib.error.HTTPError as err: # 4xx and 5xx responses still carry a JSON body
return err.code, json.loads(err.read())
def show(status, body):
print("HTTP", status)
print(json.dumps(body, ensure_ascii=False, indent=2))
BUSINESS_ID = "<BUSINESS_ID>"
BOOKING_ID = "<BOOKING_ID>" # from the create response
STATUS_TOKEN = "<STATUS_TOKEN>" # from the create response (shown once)
AUTH = {"Authorization": f"Bearer {STATUS_TOKEN}"}
show(*call("DELETE", f"/api/v1/businesses/{BUSINESS_ID}/bookings/{BOOKING_ID}", headers=AUTH))
Node.js
const BASE = "https://mcp.srct.tw";
async function call(method, path, body, headers = {}) {
const res = await fetch(BASE + path, {
method,
headers: { "User-Agent": "my-agent/1.0", "Content-Type": "application/json", ...headers },
body: body === undefined ? undefined : JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
function show({ status, body }) {
console.log("HTTP", status);
console.log(JSON.stringify(body, null, 2));
}
const BUSINESS_ID = "<BUSINESS_ID>";
const BOOKING_ID = "<BOOKING_ID>"; // from the create response
const STATUS_TOKEN = "<STATUS_TOKEN>"; // from the create response (shown once)
const AUTH = { Authorization: `Bearer ${STATUS_TOKEN}` };
(async () => {
show(await call("DELETE", `/api/v1/businesses/${BUSINESS_ID}/bookings/${BOOKING_ID}`, undefined, AUTH));
})();
レスポンス例
HTTP 200
{
"ok": true,
"booking": {
"booking_id": "2QAC3NW5",
"status": "cancelled",
"status_text": "Cancelled",
"business_id": "coach-dunken",
"business_name": "Dunken教練",
"service_id": "pt",
"service_name": "PT一對一教練課",
"slot": "2026-10-26T08:00",
"start": "2026-10-26T08:00:00+08:00",
"label": "10/26(一)08:00",
"quantity": 1,
"quantity_unit": "位",
"payment": "Pay at the venue",
"details": [
"老師:Dunken"
],
"cancelled_by": "customer"
}
}ローカル環境で実行済み:コネクターのローカルコピーで実行。現地払いの予約には返金項目はありません。オンライン決済はrefund_resultを参照してください。
構造化されたエラー
エラーは常にcodeとmessageを返し、エージェントが何が起きたか、再試行してよいかを判断できます。たとえば、お客さまが選んだ時間帯がちょうど埋まった場合は、代わりの時間帯を添えてcapacity_full(RESTでは409)を返します。エージェントは別の時間帯で予約し直せます。
構造化エラーの処理:枠が埋まっている場合
curl
# This creates a real booking at a real business. Use a slot value from the availability response.
curl -sS -X POST "https://mcp.srct.tw/api/v1/businesses/<BUSINESS_ID>/bookings" \
-H "User-Agent: my-agent/1.0" \
-H "Content-Type: application/json" \
-d '{"service_id":"pt","slot":"<FULL_SLOT>","quantity":1,"customer_name":"Example Customer","phone":"0900000000","email":"customer@example.com"}'
Python
# This creates a real booking at a real business. Use a slot value from the availability response.
import json
import urllib.error
import urllib.request
BASE = "https://mcp.srct.tw"
def call(method, path, body=None, headers=None):
req = urllib.request.Request(
BASE + path,
data=None if body is None else json.dumps(body).encode(),
method=method,
headers={"User-Agent": "my-agent/1.0", "Content-Type": "application/json", **(headers or {})},
)
try:
with urllib.request.urlopen(req) as res:
return res.status, json.loads(res.read())
except urllib.error.HTTPError as err: # 4xx and 5xx responses still carry a JSON body
return err.code, json.loads(err.read())
def show(status, body):
print("HTTP", status)
print(json.dumps(body, ensure_ascii=False, indent=2))
BUSINESS_ID = "<BUSINESS_ID>"
status, body = call("POST", f"/api/v1/businesses/{BUSINESS_ID}/bookings", {
"service_id": "pt",
"slot": "<FULL_SLOT>", # a slot that is already full
"quantity": 1,
"customer_name": "Example Customer",
"phone": "0900000000",
"email": "customer@example.com",
})
show(status, body)
# status 409, body["error"]["code"] == "capacity_full": offer the customer one of body["next_slots"] and call again.
Node.js
// This creates a real booking at a real business. Use a slot value from the availability response.
const BASE = "https://mcp.srct.tw";
async function call(method, path, body, headers = {}) {
const res = await fetch(BASE + path, {
method,
headers: { "User-Agent": "my-agent/1.0", "Content-Type": "application/json", ...headers },
body: body === undefined ? undefined : JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
function show({ status, body }) {
console.log("HTTP", status);
console.log(JSON.stringify(body, null, 2));
}
const BUSINESS_ID = "<BUSINESS_ID>";
(async () => {
const result = await call("POST", `/api/v1/businesses/${BUSINESS_ID}/bookings`, {
service_id: "pt",
slot: "<FULL_SLOT>", // a slot that is already full
quantity: 1,
customer_name: "Example Customer",
phone: "0900000000",
email: "customer@example.com",
});
show(result);
// status 409, body.error.code === "capacity_full": offer the customer one of body.next_slots and call again.
})();
レスポンス例
HTTP 409
{
"error": {
"code": "capacity_full",
"message": "Only 0 left in this slot. Choose another slot."
},
"next_slots": [
"2026-10-22T08:00",
"2026-10-22T09:00",
"2026-10-22T10:00"
]
}ローカル環境で実行済み:コネクターのローカルコピーで実行。各実行の前に、別の顧客がその枠を予約済みにしました。next_slotsに代わりの空き枠が入ります。
| コード | 意味 | RESTステータス |
|---|---|---|
capacity_full | この時間帯の残り枠が足りません | 409 |
invalid_slot | 時間帯が存在しない、または予約できません | 409 |
duplicate | 同じ連絡先で、同じサービスと時間帯がもう一度送信されました | 409 |
too_late_to_cancel | オンラインでのキャンセル期限を過ぎています | 409 |
payment_declined | 支払いが拒否されました。別の支払い方法で再試行できます | 402 |
payment_expired | 支払い期限を過ぎ、枠は解放されました | 410 |
rate_limited | 回数の上限を超えました | 429 |
支払い後に予約が成立しなかった場合:自動返金
オンラインで支払い済みの予約は、次の場合にその場で全額返金します:貴店が辞退またはキャンセルした、貴店が時間内に確認しなかった。お客さまが締め切り前にオンラインでキャンセルした場合、カード決済の返金額は、決済手数料とプラットフォーム手数料を差し引いた額になります。返金に失敗した場合は、システムが5分ごとに再試行します。
手順
- エージェント → SOP:認証情報でcomplete_booking
- SOP → SOP:決済成功
- 事業者 → SOP:事業者が辞退、または期限内に未確認
- SOP → SOP:自動で全額返金
- エージェント → SOP:または:お客様が期限前に自分でキャンセル
- SOP → SOP:決済手数料とプラットフォーム手数料を差し引いて返金
- SOP → エージェント:返金額と差し引いた手数料を返す
お客様による支払い済み予約のキャンセル:手数料を差し引いて返金
curl
curl -sS -X DELETE "https://mcp.srct.tw/api/v1/businesses/<BUSINESS_ID>/bookings/<BOOKING_ID>" \
-H "User-Agent: my-agent/1.0" \
-H "Authorization: Bearer <STATUS_TOKEN>"
Python
import json
import urllib.error
import urllib.request
BASE = "https://mcp.srct.tw"
def call(method, path, body=None, headers=None):
req = urllib.request.Request(
BASE + path,
data=None if body is None else json.dumps(body).encode(),
method=method,
headers={"User-Agent": "my-agent/1.0", "Content-Type": "application/json", **(headers or {})},
)
try:
with urllib.request.urlopen(req) as res:
return res.status, json.loads(res.read())
except urllib.error.HTTPError as err: # 4xx and 5xx responses still carry a JSON body
return err.code, json.loads(err.read())
def show(status, body):
print("HTTP", status)
print(json.dumps(body, ensure_ascii=False, indent=2))
BUSINESS_ID = "<BUSINESS_ID>"
BOOKING_ID = "<BOOKING_ID>" # from the create response
STATUS_TOKEN = "<STATUS_TOKEN>" # from the create response (shown once)
# When the customer cancels a card-paid booking before the cutoff, it is refunded minus the
# payment processing fee and the platform fee. If the business declines it or does not confirm it, it is refunded in full.
show(*call("DELETE", f"/api/v1/businesses/{BUSINESS_ID}/bookings/{BOOKING_ID}", headers={"Authorization": f"Bearer {STATUS_TOKEN}"}))
Node.js
const BASE = "https://mcp.srct.tw";
async function call(method, path, body, headers = {}) {
const res = await fetch(BASE + path, {
method,
headers: { "User-Agent": "my-agent/1.0", "Content-Type": "application/json", ...headers },
body: body === undefined ? undefined : JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
function show({ status, body }) {
console.log("HTTP", status);
console.log(JSON.stringify(body, null, 2));
}
const BUSINESS_ID = "<BUSINESS_ID>";
const BOOKING_ID = "<BOOKING_ID>"; // from the create response
const STATUS_TOKEN = "<STATUS_TOKEN>"; // from the create response (shown once)
// When the customer cancels a card-paid booking before the cutoff, it is refunded minus the
// payment processing fee and the platform fee. If the business declines it or does not confirm it, it is refunded in full.
(async () => {
show(await call("DELETE", `/api/v1/businesses/${BUSINESS_ID}/bookings/${BOOKING_ID}`, undefined, { Authorization: `Bearer ${STATUS_TOKEN}` }));
})();
レスポンス例
HTTP 200
{
"ok": true,
"booking": {
"booking_id": "WQEMHR2E",
"status": "cancelled",
"status_text": "Cancelled",
"business_id": "example-studio",
"business_name": "Example Studio (test data)",
"service_id": "small_group",
"service_name": "Small-group strength class",
"slot": "2026-10-25T10:00",
"start": "2026-10-25T10:00:00+08:00",
"label": "10/25(日)10:00",
"quantity": 1,
"quantity_unit": "seat",
"payment": "Refunded NT$518 of NT$600 (the Stripe processing fee and the platform fee were deducted because the customer cancelled)",
"details": [],
"payment_details": {
"mode": "online",
"status": "refunded",
"amount": {
"value": 60000,
"currency": "twd",
"text": "NT$600"
},
"collected_by": "Seller Tech U.S.A. LLC through Stripe",
"paid_at": "2026-10-22T11:51:00+08:00",
"card": {
"brand": "visa",
"last4": "4242"
},
"method": "stripe_spt",
"transaction_id": "pi_1",
"refund": "refunded",
"refund_amount": {
"value": 51800,
"currency": "twd",
"text": "NT$518"
},
"refund_fees": {
"stripe": "NT$39",
"platform": "NT$43",
"reason": "customer_cancel"
}
},
"cancelled_by": "customer"
}
}レスポンスはサービスの自動テストから取得:コネクターのテスト環境から取得しました。コネクターのコードはそのまま動かし、Stripeはテストスイートの偽Stripeサーバーに置き換えています。transaction_id(pi_1)と決済手数料(USD1.20、NT$39換算)はテスト値です。実際の課金は一切ありません。
受付確認デスクで見える内容
- 支払い待ちの予約は別の区画に表示され、確認ボタンは押せません。支払いが完了してから通知されます。
- 支払い完了後のLINE通知には、支払い済みの金額が表示されます。カード番号やお客さまの個人情報は含みません。
- 確認ページには、支払い状態、カードの種類、下4桁が表示されます。
- 支払い済みの予約を辞退またはキャンセルすると、その場で返金され、結果が表示されます。
- 書き出したCSVには、支払い方法、支払い状態、金額、支払い日時、返金日時の列が加わります。
事業者側の設定
- 支払い方法:既定は店頭払いです。オンライン決済は、掲載開始時に設定します。価格が0のサービスには課金しません。
- 支払い期限:5〜1440分。設定しない場合は15分です。
- オンライン決済に設定していても、受け取りの設定が完了していない場合、予約の作成は
payment_unavailableを返し、予約は作成されません。 - オンラインでのキャンセル期限と確認ルールは、貴店が決めます。
オンライン決済はSeller Tech U.S.A. LLCがStripeを通じて処理します。手数料と入金時期は見積書に記載します。
現在の状態
予約インターフェースは提供中です。事業者は店頭払いとオンライン決済から選べます。2026年10月22日、最初の事業者(パーソナルトレーナー)がオンライン決済を有効にしました。
始める前に
- サービスの名称、料金、所要時間。
- 予約を受け付ける時間帯と、1枠あたりの人数。
- キャンセル・変更の締め切り。
- オンライン決済を受けるかどうか。受ける場合は、精算に必要な情報。
再送しても重複しません
エージェントはネットワークエラーの後にリクエストを再送しても、予約や課金が重複しません。エージェントがIdempotency-Keyを送ると、SOPは48時間、元の結果を返します。カードの課金にも、Stripe向けの冪等キーが別に付いています。
公開する前に
掲載内容は一緒に整え、すべての項目をご確認いただいてから公開します。オンライン決済は、ご依頼をいただいてから有効にします。
関連ページ
- 予約サービスに接続する:事業者の検索、空き枠の確認、予約の作成と管理
- お客さまに代わって支払う:お客さまが承認した支払い認証情報で予約の支払いを完了する
- 支払い認証情報:Shared Payment Tokenと、事業者・エージェント・プラットフォームの3つの役割
- エージェントに商品を売る:小売商品の計画