# Shared payment tokens
Grant and receive scoped payment credentials for agent-initiated purchases.
> Shared payment tokens (SPTs) are available to agents, customers, and sellers in the US.
# Agents
As the agent, use [shared payment tokens (SPTs)](https://docs.stripe.com/api/shared-payment/issued-token/.md) to grant the seller scoped access to the customer’s payment method for payment processing.
Payment method registration and processing (See full diagram at https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens)
## Before you begin
- By using SPTs, you agree to the [terms of service](https://stripe.com/legal/ssa-services-terms#stripe-agentic-commerce-agent-services-preview).
- If you don’t already have a Stripe account, [create one](https://stripe.com/register).
- Create your [Stripe profile](https://docs.stripe.com/get-started/account/profile.md) in the Dashboard.
## Collect Stripe profile from seller
During seller onboarding, collect the seller’s Stripe profile. Sellers can create a new profile or find their current profile in the [Dashboard](https://dashboard.stripe.com/profiles). You issue an SPT to this profile for each transaction.
## Collect the customer’s payment details
Use the [Payment Element](https://docs.stripe.com/payments/payment-element.md) to securely collect payment details and support multiple payment methods through a single integration. It automatically helps ensure that the payment methods you show customers are supported by sellers. Your checkout page URL must start with `https://` rather than `http://` for your integration to work. You can test your integration without HTTPS, but you must [enable it](https://docs.stripe.com/security/guide.md#tls) before you accept live payments.
### Set up Stripe.js
The Payment Element is automatically available in Stripe.js. Include the Stripe.js script on your checkout page by adding it to the `head` of your HTML file. Always load Stripe.js directly from `js.stripe.com` to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself.
```html
Checkout
```
Create a `Stripe` instance with the following JavaScript on your checkout page.
```javascript
// Set your publishable key: remember to change this to your live publishable key in production
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = Stripe('<>');
```
### Add the Payment Element to your checkout page
> #### Conflicting iframes
>
> Don’t place the Payment Element inside another `iframe` because it conflicts with payment methods that require a redirect to another page for payment confirmation.
The Payment Element needs a container on your checkout page. Create an empty DOM node with a unique ID in your payment form.
```html
```
After your form loads, create an `Elements` instance with `mode`, `amount`, `currency`, and `paymentMethodCreation`. Specify `sellerDetails` and pass the seller’s `networkBusinessProfile` to make sure that Stripe displays the payment methods that the seller supports. This lets you support a different set of payment methods from the seller while showing the buyer compatible payment methods.
Then, create a Payment Element instance and mount it to the container DOM node.
```javascript
const options = {
mode: 'payment',
amount: 1000,
currency: 'usd',
paymentMethodCreation: 'manual',
sellerDetails: {
networkBusinessProfile: "profile_123"
},
// Fully customizable with appearance API.
appearance: {/*...*/},
};
// Set up Stripe.js and Elements to use in checkout formconst elements = stripe.elements(options);
// Create and mount the Payment Element
const paymentElementOptions = { layout: 'accordion'};
const paymentElement = elements.create('payment', paymentElementOptions);
paymentElement.mount('#payment-element');
```
### Collect addresses
By default, the Payment Element only collects the necessary billing address details. Some behavior, such as [calculating tax](https://docs.stripe.com/api/tax/calculations/create.md) or entering shipping details, requires your customer’s full address. You can:
- Use the [Address Element](https://docs.stripe.com/elements/address-element.md) to take advantage of autocomplete and localization features to collect your customer’s full address. This helps ensure the most accurate tax calculation.
- Collect address details using your own custom form.
### Create the PaymentMethod
When the customer submits your payment form, create a `PaymentMethod` and send it to your server to create an SPT.
```javascript
const form = document.getElementById('payment-form');
const submitBtn = document.getElementById('submit');
const handleError = (error) => {
const messageContainer = document.querySelector('#error-message');
messageContainer.textContent = error.message;
submitBtn.disabled = false;
}
form.addEventListener('submit', async (event) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
// Prevent multiple form submissions
if (submitBtn.disabled) {
return;
}
// Disable form submission while loading
submitBtn.disabled = true;
// Trigger form validation and wallet collection
const {error: submitError} = await elements.submit();
if (submitError) {
handleError(submitError);
return;
}
// Create the PaymentMethod using the details collected by the Payment Element
const {error, paymentMethod} = await stripe.preparePaymentMethod({
elements,
params: {
billing_details: {
name: 'Jenny Rosen',
}
}
});
if (error) {
// This point is only reached if there's an immediate error when
// creating the PaymentMethod. Show the error to your customer (for example, payment details incomplete)
handleError(error);
return;
}
// Create the Shared Payment Token
const res = await fetch("/create-spt", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
paymentMethodId: paymentMethod.id,
}),
});
const data = await res.json();
// Handle any next actions or errors. See the Handle any next actions step for implementation.
handleServerResponse(data);
});
```
## Issue a shared payment token to a seller
As the agent, create a `SharedPaymentIssuedToken` for the transaction using your customer’s payment method and the seller’s Stripe profile. Set usage limits, including currency, maximum amount, and expiration window. This request returns a `SharedPaymentToken` ID that you share with the seller for payment processing.
Pass the seller’s `network_business_profile` in `seller_details` to make sure the SPT is granted to the correct party. In test mode, you can use `profile_test_61TU90nIeGjU7NNVXA6TU90m7ISQWsBxpcx9lASWWXTk` as a test seller profile.
```curl
curl https://api.stripe.com/v1/shared_payment/issued_tokens \
-u "<>:" \
-H "Stripe-Version: 2026-04-22.preview" \
-d payment_method=pm_1RgaZbFPC5QUO6ZCe2ekOCNX \
-d "seller_details[network_business_profile]=profile_test_61TU90nIeGjU7NNVXA6TU90m7ISQWsBxpcx9lASWWXTk" \
-d "usage_limits[currency]=usd" \
-d "usage_limits[expires_at]=1751587220" \
-d "usage_limits[max_amount]=1000" \
--data-urlencode "return_url=http://example.com/agent-checkout/return"
```
### Supported payment methods
| Payment method | Availability |
| -------------------------------------------------------------- | --------------- |
| [Cards](https://docs.stripe.com/payments/cards/overview.md) | ✓ Supported 1 |
| [Link](https://docs.stripe.com/payments/wallets/link.md) | ✓ Supported |
| [Apple Pay](https://docs.stripe.com/apple-pay.md) | ✓ Supported |
| [Google Pay](https://docs.stripe.com/google-pay.md) | ✓ Supported |
| [Klarna](https://docs.stripe.com/payments/klarna.md) | ✓ Supported |
| [Affirm](https://docs.stripe.com/payments/affirm.md) (limited) | ✓ Supported 2,3 |
1 In collaboration with the card networks, Stripe might use tokens issued through network programs such as Mastercard’s Agent Pay and Visa’s Intelligent Commerce programs on your behalf. Stripe submits the requested data to the card networks to provision and process those tokens for related transactions. 2 An agent may not programmatically interact with the Affirm loan application UI inside the webview; the buyer must be the one navigating and confirming. It also may not render the Affirm checkout in a browser on the device over which the agent doesn’t have navigation control. 3 If an agent markets Affirm to customers, the agent must comply with Affirm’s [marketing compliance guides](https://docs.affirm.com/developers/docs/compliance_and_guidelines) and use the Affirm [guide](https://businesshub.affirm.com/hc/en-us/articles/10653174159636-Affirm-Marketing-Compliance-Guides) that relates to the Affirm payment options you display to your customers.
### Handle next actions
A `SharedPaymentToken` can transition to the `requires_action` state when a payment created by the seller needs additional customer action before it can complete. If the payment requires additional customer action, such as 3D Secure authentication or a redirect for a local payment method, you must handle that action. For card payments, Stripe might trigger 3D Secure automatically in these cases:
- Industry guidelines require it.
- The issuer requests it.
- The seller requests it while using the `SharedPaymentToken` to process a `PaymentIntent`.
- Certain Stripe optimizations trigger it.
When Stripe triggers 3D Secure, it redirects the customer to the bank’s user interface. When the SPT transitions to `requires_action`, Stripe sends the `shared_payment.issued_token.requires_action` webhook. Retrieve the SPT on your server.
```curl
curl https://api.stripe.com/v1/shared_payment/issued_tokens/spt_123 \
-u "<>:" \
-H "Stripe-Version: 2026-04-22.preview"
```
```
{
"id": "spt_123",
"object": "shared_payment.issued_token",
"status": "requires_action",
"next_action": {
"type": "use_stripe_sdk",
"use_stripe_sdk": {
"value": "ewogICJ0eXBlIjogInN0cmlwZV8zZHN 2X2ZpbmdlcnByaW50IiwKICAic291cmNlIjogInNyY18xQThYeUwyZVp2S1lsbzJDOXhROXpSNXQiLAogICJvbmVfY2xpY2tfYXV0aCI6IHRydWUKfQ=="
}
}
...
}
```
Call `handleNextAction` on the client. Stripe automatically displays the authentication interface in a pop-up modal.
#### JavaScript
```javascript
const handleServerResponse = async (response) => {
if (response.error) {
// Show error from server on payment form
} else if (response.status === "requires_action") {
// Use Stripe.js to handle the required next action
const result = await stripe.handleNextAction({
hashedValue: response.next_action.use_stripe_sdk.value
});
const actionError = result && (result as any).error;
if (actionError) {
// Show error from Stripe.js in payment form
} else {
// Actions handled, show success message
}
} else {
// No actions needed, show success message
}
}
```
After the customer completes the required action, Stripe sends the `shared_payment.issued_token.active` webhook unless you deactivated the `SharedPaymentToken` in the meantime.
### Revoke an SPT
Revoke the SPT at any time to prevent the seller from using it to create a payment.
```curl
curl -X POST https://api.stripe.com/v1/shared_payment/issued_tokens/spt_123/revoke \
-u "<>:" \
-H "Stripe-Version: 2026-04-22.preview"
```
### SPT status
An SPT functions as a state machine, with states tracked using the [status](https://docs.stripe.com/api/shared-payment/issued-token/object.md#shared_payment_issued_token_object-status) attribute. States don’t always follow a linear progression and can loop based on the payment flow. For example, an SPT can transition from `active` to `requires_action` and back to `active`. SPTs can start in either the `active` or `requires_action` state.
| Status | Definition | Can transition to |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `active` | The SPT is ready for an agent to pass to a seller, or for a seller to use it for payment. | `requires_action`, `deactivated` |
| `requires_action` | The SPT requires action from the customer before a payment can be completed. The [next_action](https://docs.stripe.com/api/shared-payment/issued-token/object.md#shared_payment_issued_token_object-next_action) attribute describes the action the customer needs to do. | `active`, `deactivated` |
| `deactivated` | The SPT is deactivated and can’t process new payments. The [deactivated_reason](https://docs.stripe.com/api/shared-payment/issued-token/object.md#shared_payment_issued_token_object-deactivated_reason) attribute explains why. | No transition. The terminal state is currently `deactivated`. |
### Listen for webhook events
We send events to you and the seller when:
- Sellers use a granted SPT to accept a payment.
- You revoke an SPT. Sellers can’t create a payment with a revoked SPT.
| Event | Description | Use case |
| --------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `shared_payment.issued_token.requires_action` | The SPT requires additional customer action before the seller can complete the payment. | You listen for this event to retrieve the SPT, inspect `next_action`, and present the required authentication or redirect flow on the agent interface. |
| `shared_payment.issued_token.active` | The customer completed the required action and the SPT can continue through the payment flow. | You listen for this event to know the SPT is usable again after the required action completes. |
| `shared_payment.issued_token.used` | You receive this event when the seller uses the SPT. | You listen for this event to notify the customer that the payment has been processed. |
| `shared_payment.issued_token.deactivated` | The SPT has been deactivated (consumed, expired, or revoked). | You listen for this event to track when the SPT is no longer valid. |