POST /api/v1/apps/:appUuid/payment-providers/stripe/checkout-sessions
available for apps that use Stripe billing. For Mollie checkout sessions, see POST /api/v1/apps/:appUuid/payment-providers/mollie/checkout-sessions.
Creates a new checkout sessions resource.
This endpoint documentation is generated from the current Fastify route implementation and should be treated as the implementation-level contract for this version of the API.
Source route file:
src/api/routes/external/private/bearer/apps/payment-providers/stripe/checkout-sessions/post.ts
Request Method
POST
Base URL
https://api.userdocks.local:5000
Endpoint
/api/v1/apps/:appUuid/payment-providers/stripe/checkout-sessions
Path Variables
| Variable | Type | Required | Description |
|---|---|---|---|
appUuid | string | true | Path variable from route pattern. |
Query Parameters
No query parameters.
HTTP Headers
| Variable | Type | Required | Description |
|---|---|---|---|
Authorization | string | true | Bearer token in the form Bearer <jwt>. |
Content-Type | string | true | Use application/json for JSON request bodies. |
Request Body
Schema reference: createCheckoutSessionSchema
{
"tenantUuid": "11111111-1111-1111-1111-111111111111",
"productUuid": "22222222-2222-2222-2222-222222222222",
"unitAmount": 10000,
"currency": "EUR",
"taxRateId": "txr_12345",
"quantity": 1,
"mode": "subscription",
"description": "Growth subscription",
"descriptionUnused": "Starter credit",
"recurringInterval": "month",
"recurringIntervalCount": 1,
"billingAddressCollection": true,
"shippingAddressCollection": false,
"successUrl": "https://app.example.com/success",
"cancelUrl": "https://app.example.com/cancel",
"termsOfServiceUrl": "https://app.example.com/terms",
"collectTermsOfServiceConsent": true,
"isTaxIdCollectionEnabled": true,
"isTaxIdCollectionRequired": false
}
description is optional. For Stripe checkout sessions in payment or setup
mode, it is copied to the generated Stripe invoice description (shown as the
invoice memo in Stripe). For subscriptions it becomes the recurring invoice line
description. descriptionUnused is optional and is used only for the
unused-time credit line of a Stripe upgrade. Both fields are limited to 500
characters and do not change the checkout-session response.
Successful Response
Success status code(s): 200.
{
"kind": "checkoutSessions",
"totalItems": 1,
"itemsLength": 1,
"items": [
{
"createdCheckoutSession": {
"id": 1,
"uuid": "csrow_11111111-1111-1111-1111-111111111111",
"appUuid": "app_11111111-1111-1111-1111-111111111111",
"paymentProviderUuid": "pp_11111111-1111-1111-1111-111111111111",
"sessionId": "cs_test_12345",
"nextActionUrl": "https://checkout.stripe.com/pay/cs_test_12345",
"userUuid": "user_11111111-1111-1111-1111-111111111111",
"tenantUuid": "tenant_11111111-1111-1111-1111-111111111111",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z",
"deletedAt": null
},
"nextAction": {
"url": "https://checkout.stripe.com/pay/cs_test_12345"
}
}
]
}
Subscription upgrades
Stripe receives inline price_data tied to the existing provider product. A
Userdocks ProductPrice is not created. Amounts are positive minor-unit
integers (10000 is EUR 100.00); currencies are normalized to uppercase. Inline
subscriptions require recurringInterval, and recurringIntervalCount defaults
to 1. Deprecated productPriceUuid and priceId inputs still use the legacy
provider price.
When mode is subscription and the requested same-currency price is more
expensive than the tenant's current price, this endpoint updates the existing
Stripe subscription item and invoices the prorated difference immediately. The
new price is pending until that invoice is paid.
For an immediately paid invoice, nextAction.url is the configured
successUrl. If authentication or payment retry is required, it is the Stripe
hosted invoice URL. In the latter case the old Stripe price and Userdocks plan
period remain active. A failed or expired pending update creates no plan-period
history. Cross-currency plan comparisons are rejected.
Matching billing cadences keep their anchor. Stripe applies its normal billing anchor reset when the recurring cadence changes. See Subscription upgrades and plan history.
When description or descriptionUnused is supplied, the upgrade must retain
the current billing cadence. Userdocks preserves Stripe's
Unused time on ... after ... and Remaining time on ... after ... wording
while replacing the product-name portion. The recurring description is also
applied to future billing-cycle invoice lines. While payment or authentication
is pending, the response links to the hosted invoice; retrying the identical
request reuses that invoice.
Error Responses
| HTTP Status | Example Error |
|---|---|
401 | {"errors":[{"validation":"error","code":"[E4010]","message":"Unauthorized Token"}]} |
403 | {"errors":[{"validation":"error","code":"[E4030]","message":"App Is Disabled"}]} |
400 | {"errors":[{"validation":"error","code":"[E4000]","message":"Bad Request / validation error"}]} |
500 | {"errors":[{"validation":"error","code":"[E0000]","message":"Internal Server Error"}]} |
Example
const url = `https://api.userdocks.local:5000/api/v1/apps/appUuid-value/payment-providers/stripe/checkout-sessions`;
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: 'Bearer <jwt>',
'Content-Type': 'application/json',
},
body: '{"tenantUuid":"11111111-1111-1111-1111-111111111111","productUuid":"22222222-2222-2222-2222-222222222222","unitAmount":10000,"currency":"EUR","taxRateId":"txr_12345","quantity":1,"mode":"payment","description":"September service invoice","billingAddressCollection":true,"shippingAddressCollection":false,"successUrl":"https://app.example.com/success","cancelUrl":"https://app.example.com/cancel","collectTermsOfServiceConsent":true}',
});
const data = await response.json();
console.log(response.status, data);
Named discounts
Supply the root-level discount with
{ "name": "Partner deal", "amount": 1000, "duration": "once" } or duration
"forever". Amounts use the price currency's minor units and reduce the product
line once, regardless of quantity. The original price and named reduction remain
visible on the invoice. Discounts must be smaller than the product line
subtotal; setup sessions and charges below the provider minimum are rejected.
See Named billing discounts for renewal behavior, per-line invoice examples, tax handling, and midterm upgrade calculations.