Skip to main content

POST /api/v1/apps/:appUuid/tenants/:tenantUuid/payment-providers/:paymentProvider/checkout-sessions

Creates a new checkout sessions resource from a server-side app integration.

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/apiKey/app/tenants/paymentProviders/checkout-sessions/post.ts

Request Method​

POST

Base URL​

https://api.userdocks.local:5000

Endpoint​

/api/v1/apps/:appUuid/tenants/:tenantUuid/payment-providers/:paymentProvider/checkout-sessions

Path Variables​

VariableTypeRequiredDescription
appUuidstringtruePath variable from route pattern.
tenantUuidstringtruePath variable from route pattern.
paymentProviderstringtrueUse stripe or mollie.

Query Parameters​

No query parameters.

HTTP Headers​

VariableTypeRequiredDescription
x-api-keystringtrueAPI key value for the app.
x-client-idstringtrueMust match :appUuid path variable.
x-api-key-typestringtrueUse write.
Content-TypestringtrueUse application/json for JSON request bodies.

Request Body​

Schema reference: createCheckoutSessionSchema, without tenantUuid. The tenant is resolved from the :tenantUuid path variable.

{
"productUuid": "11111111-1111-1111-1111-111111111111",
"unitAmount": 1300,
"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 Stripe subscriptions it becomes the recurring invoice-line description. descriptionUnused is used only for a Stripe upgrade's unused-time credit line. Both fields are limited to 500 characters. Mollie ignores these Stripe-specific options. They do not change the 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"
}
}
]
}

Provider Notes​

  • Stripe and Mollie use the same endpoint shape.
  • unitAmount is a positive integer in the currency's minor unit: 1300 means EUR 13.00. Currencies are three-letter codes and are normalized to uppercase.
  • Inline subscriptions require recurringInterval; the interval count defaults to 1.
  • Legacy productPriceUuid and provider priceId are deprecated but supported.
  • items[0].nextAction.url is the URL your app should open for the tenant.
  • The provider customer is created when the tenant does not already have one.
  • A higher same-currency Stripe subscription price updates the existing item with an immediate proration invoice. The price applies only after payment.
  • While authentication or retry is required, nextAction.url is the hosted invoice URL and the old plan remains active. Failed or expired pending updates create no Userdocks history.
  • Cross-currency Stripe price comparisons are rejected. Matching cadences keep their anchor; cadence changes use Stripe's normal reset behavior.
  • Custom-description upgrades must keep the existing cadence. Their unused and remaining proration lines retain Stripe's surrounding wording and dates, and description is reused on future billing-cycle invoice lines. Pending payment returns the hosted invoice, and retrying the identical request reuses it.
  • Renewals update the active plan period and do not create subscription history rows. See Subscription upgrades and plan history.

Error Responses​

HTTP StatusExample Error
401{"errors":[{"validation":"error","code":"[E4010]","message":"Unauthorized Token or API key"}]}
401{"errors":[{"validation":"error","code":"[E4011]","message":"Unauthorized API key type"}]}
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/tenants/tenantUuid-value/payment-providers/stripe/checkout-sessions`;

const response = await fetch(url, {
method: 'POST',
headers: {
'x-api-key': '<api-key>',
'x-client-id': 'appUuid-value',
'x-api-key-type': 'write',
'Content-Type': 'application/json',
},
body: '{"productUuid":"11111111-1111-1111-1111-111111111111","unitAmount":1300,"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.