Stripe Shared Payment Tokens: five wire shapes I only found by shipping
Five response shapes from Stripe's Shared Payment Tokens preview API that I didn't find documented, captured from real test-mode responses. Stripe's Shared Payment Tokens are the payment primitive for agentic commerce: a token that carries its own spend limits — max_amount, currency, expires_at — so an agent can pay without ever holding a card credential. The concept docs are good, and there are…
Stripe's Shared Payment Tokens (SPT) are a new payment primitive that allows agents to pay without holding a card credential. They carry their own spend limits, such as max_amount, currency, and expires_at. However, the failure surface of SPTs is not well-documented, which can lead to issues in building systems that use them.
The author discovered five failure shapes while testing SPTs in real test-mode responses. Each failure costs time and must be pinned in tests, as the wire format is not a contract and can change.
1. A decline results in a 402 HTTP status code, with the PaymentIntent nested inside the error body. This is unlike other payment APIs that return a 200 status code with a non-succeeded status. The decline message is "Your card was declined," and the decline_code should be used instead of code, as code only provides the category, not the actual reason.
2. A 200 HTTP status code does not necessarily mean a successful charge. In the case of 3D Secure authentication, the response is 200, but the shared_payment_token_action is empty, and no money moved. The system requires status === "succeeded" to consider a charge successful.
3. After a successful charge against the same token, payment_method_details are null. This field should be retrieved at grant time, as it is consumed during the charge.
4. The amount_captured field is an object, with currency and value properties, while max_amount is a bare integer in minor units. Directly comparing these values can lead to errors, as they are not directly comparable.
5. Granted tokens and issued tokens are different objects. The issued token has a status field (active, requires_action, deactivated), while the granted token does not. When a charge comes back with requires_action, the state blocking it is invisible on the granted token.
Other important points include the lack of a list endpoint for granted tokens, the existence of only one webhook event (shared_payment.granted_token.deactivated), and a 403 error when the agent does not have access to the endpoint.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.
This story
This is one outlet's version. Read the fullest account.