Payment credentials
A payment credential is a payment authorization for one transaction: limited to a recipient, an amount and an expiry, and issued by the customer's AI agent to a seller.
LivePayment credentials for bookings are live; the first merchant, a personal trainer, turned on online payment on 2026-10-22.
What a payment credential is
A Shared Payment Token (SPT) is a Stripe product: a payment authorization that a customer's AI agent issues to a recipient, using the payment method the customer approved. The credential is valid only for this transaction, this amount, this period and this recipient.
- Recipient: the credential is issued to a specific Stripe profile.
- Amount: the maximum equals the total of the transaction.
- Expiry: it has an expiry time, and the agent can revoke it at any time.
- States:
active,requires_action(waiting for the customer to complete verification), anddeactivated(stopped; it can no longer pay).
With the credential, the recipient creates and confirms a Stripe payment (a PaymentIntent); later refunds and reporting are handled as if the customer's payment method had been provided directly.
The three roles
An SPT has three roles: the seller who is paid, the agent who issues the credential, and the platform that serves many sellers. Each is explained below with a flow diagram and how it maps to SOP.
Sellers
A seller receives the credential the agent sends and charges it. SOP handles this step for you: the payee is Seller Tech U.S.A. LLC, processed through Stripe, and funds are settled to you as agreed; fees and settlement timing are stated in the quotation.
Steps
- Customer → Agent: Approves a payment method
- Agent → Agent: Gets a one-time credential for SOP, limited in amount and time
- Agent → SOP: Sends the credential with the booking
- SOP → SOP: Charges the approved amount once
- SOP → Seller: Booking confirmed; settled to you as agreed
- Seller → Customer: Provides the service
The payment_handlers in a booking response tell the agent who the credential must be issued to, how much to pay, and when it expires:
payment_handlers in an awaiting_payment booking
JSON
[
{
"id": "stripe_payments",
"type": "com.stripe.payments",
"version": "2026-06-25",
"spec": "https://docs.stripe.com/agentic-commerce/ucp/stripe-payments-handler",
"schema": "https://ucp.stripe.com/payments/2026-06-25/schema.json",
"available_instruments": [
{
"type": "card"
},
{
"type": "link",
"config": {
"network_id": "profile_xxxx"
}
}
],
"config": {
"environment": "testmode",
"business_profile": "profile_xxxx"
}
}
]Run against a local copy of the service: Copied from the awaiting_payment booking above (booking.payment_handlers). Local copy of the connector with a placeholder profile ID; in production business_profile is the seller's real Stripe profile ID.
- After SOP receives the credential, it creates and confirms the Stripe payment; the same credential on the same booking is charged only once.
- SOP verifies the signature of Stripe webhooks and handles payment succeeded, payment failed and refund events; each event is handled only once.
Agents
The agent gets the Stripe profile from the seller, collects the customer's payment method, issues an SPT through Stripe, and gives the credential to the seller. When verification is needed (for example 3D Secure), the agent walks the customer through it. Step by step, see Pay for a customer.
Steps
- Agent → SOP: request_booking
- SOP → Agent: payment_handlers: com.stripe.payments and business profile; amount; expires_at
- Agent → Customer: Asks to approve the exact amount
- Customer → Agent: Approves
- Agent → Agent: Issues a Shared Payment Token for that profile, limited to the amount and expiry
- Agent → SOP: complete_booking with the token
- SOP → Agent: Paid (confirmed, or pending the business), or requires_action with a 3D Secure link
- Agent → Customer: Confirms, or opens the 3D Secure link
Pay for a booking with a Shared Payment Token
curl
# Reuse the same Idempotency-Key when you retry this request after a network error.
curl -sS -X POST "https://mcp.srct.tw/api/v1/businesses/<BUSINESS_ID>/bookings/<BOOKING_ID>/complete" \
-H "User-Agent: my-agent/1.0" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <STATUS_TOKEN>" \
-H "Idempotency-Key: pay-$(uuidgen)" \
-d '{"payment":{"instruments":[{"id":"instr_1","handler_id":"stripe_payments","type":"card","selected":true,"credential":{"type":"stripe_payment_token","token":"spt_..."}}]}}'
Python
import json
import urllib.error
import urllib.request
import uuid
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)
payment = {
"instruments": [{
"id": "instr_1",
"handler_id": "stripe_payments", # an id from payment_handlers
"type": "card",
"selected": True,
"credential": {"type": "stripe_payment_token", "token": "spt_..."}, # the SPT the agent issued
}]
}
headers = {
"Authorization": f"Bearer {STATUS_TOKEN}",
"Idempotency-Key": str(uuid.uuid4()), # reuse the same key when you retry after a network error
}
show(*call("POST", f"/api/v1/businesses/{BUSINESS_ID}/bookings/{BOOKING_ID}/complete", {"payment": payment}, headers))
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 payment = {
instruments: [{
id: "instr_1",
handler_id: "stripe_payments", // an id from payment_handlers
type: "card",
selected: true,
credential: { type: "stripe_payment_token", token: "spt_..." }, // the SPT the agent issued
}],
};
const headers = {
Authorization: `Bearer ${STATUS_TOKEN}`,
"Idempotency-Key": `pay-${Date.now()}`, // reuse the same key when you retry after a network error
};
(async () => {
show(await call("POST", `/api/v1/businesses/${BUSINESS_ID}/bookings/${BOOKING_ID}/complete`, { payment }, headers));
})();
Example response
HTTP 200
{
"ok": true,
"booking": {
"booking_id": "WQEMHR2E",
"status": "pending",
"status_text": "Waiting for the business to confirm",
"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": "Paid online: NT$600",
"details": [],
"payment_details": {
"mode": "online",
"status": "paid",
"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"
},
"why_pending": "First booking with this business from these contact details, so the business confirms it.",
"confirm_by": "2026-10-22T12:01: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"
},
"payment": {
"status": "succeeded",
"transaction_id": "pi_1",
"instrument_type": "card"
}
}Response taken from the service's automated tests: Taken from the connector's test setup: the connector code runs unchanged, and Stripe is replaced by the test suite's fake Stripe server, so transaction_id (pi_1) and the processing fee (USD 1.20, shown as NT$39) are test values. Nothing was charged anywhere.
Connect platforms
A platform that serves many sellers decides who the credential is issued to: the platform's own profile, or each seller's profile. SOP currently uses the former: all merchants share the payment profile of Seller Tech U.S.A. LLC, which charges as the payee and then settles to the merchant as agreed.
Steps
- SOP → Agent: Publishes each business and the payment profile to use
- Customer → Agent: Approves a payment method
- Agent → Agent: Issues a credential for SOP's profile
- Agent → SOP: Sends it with one business's booking
- SOP → SOP: Charges as merchant of record (Seller Tech U.S.A. LLC)
- SOP → Agent: Confirms the booking
- SOP → Seller: Notifies the booking; settles as agreed
- Seller → Customer: Provides the service
In the other model, each merchant has its own payment profile and is the payee itself, and SOP only collects a platform fee. That model is Planned and not implemented.
Supported regions and terms
Stripe currently lists SPT availability as the United States, Canada and some European countries; whether customers, agents and sellers in a given region can use it depends on Stripe's announcements. SPT is still a Stripe preview feature, and using SPT means accepting Stripe's related service terms.
Card data and PCI
SOP and the business never receive a full card number, expiry date or security code; Stripe handles card data. The booking record keeps the card brand and the last four digits, which the business also sees on its confirmation page.
Related pages
- Pay for a customer: Complete a booking payment with a credential the customer approved
- Accept agent bookings: For merchants: what agents can do, where you confirm, how refunds work
- Protocols and standards: How MCP, REST, UCP, MPP and x402 map to SOP