Skip to content

Create Stripe Setup Intent

POST
/api/billing/stripe/setup-intent
curl --request POST \
--url 'https://example.com/api/billing/stripe/setup-intent?organization_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \
--header 'Authorization: Bearer <token>'

Mint a Stripe SetupIntent so the console can tokenize a card.

The client secret is the only thing that crosses the wire; the card itself goes browser → Stripe and never touches this server (PCI SAQ-A, §5).

SetupIntent is deliberately not on PaymentGatewayAdapter: the ABC covers the five subscription-lifecycle calls every gateway has, and a standalone setup intent is a Stripe-shaped concept with no Razorpay/PayPal counterpart. Adding it there would make the interface describe Stripe rather than the domain, so this route talks to the SDK directly — under the same stripe.api_key discipline stripe_adapter.py documents (a process-wide module global, reassigned immediately before the call so a key rotated in settings is never shadowed).

Card-only, deliberately. automatic_payment_methods offers whatever the account has configured — the console was rendering Pix, Klarna, Naver Pay and Kakao Pay alongside Card — but the rest of this pipeline can only charge a card: StripeAdapter.create_subscription pins the tokenized method as invoice_settings.default_payment_method and bills it off-session every period. Letting a customer set up a method that cannot be charged that way buys them a subscription that fails on its first renewal, so the restriction belongs on the intent (the only place that can impose it — Elements derives its method list from the intent, and cannot narrow it client-side).

organization_id
required
Organization Id
string format: uuid

Successful Response

Media type application/json
SetupIntentResponse

POST /api/billing/stripe/setup-intent — what Stripe Elements needs.

Only the client secret crosses the wire. The gateway customer id it was minted against stays server-side, Fernet-encrypted in payment_references.provider_customer_id.

object
client_secret
required
Client Secret
string
Example generated
{
"client_secret": "example"
}

Validation Error

Media type application/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
ctx
Context
object
input
Input
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
Example generated
{
"detail": [
{
"ctx": {},
"input": "example",
"loc": [
"example"
],
"msg": "example",
"type": "example"
}
]
}