Behavior
- Price snapshot — The subscription price is frozen at order creation (
price_snapshot); two-phase pricing (regularPhase+ optionalspecialPhasefor trials) is supported. - Billing period mapping —
weekly->week/1,monthly->month/1,quarterly->month/3,yearly->year/1. - PSP fault tolerance — If the PSP call fails, the local order is canceled and the error is surfaced.
- Session pre-fill —
billingDetailandbuyerEmailfrom the request body override any pre-filled values on the session; if both are missing the request is rejected with 400. - Email normalization —
buyerEmailis normalized withtrim().toLowerCase()before use.
storeId, productId, billingPeriod, currency. They are ignored if provided.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
checkoutSessionId | string | Yes | Checkout session ID returned by create-checkout-session |
billingDetail | object | Conditional | Buyer billing info; required if not pre-filled on the session |
billingDetail.country | string | Yes (if billingDetail present) | ISO 3166-1 alpha-2 country code |
billingDetail.isBusiness | boolean | Yes (if billingDetail present) | Whether the buyer is a business |
billingDetail.postcode | string | No | Postal code |
billingDetail.state | string | Required for US/CA | State / province code |
billingDetail.businessName | string | Required if isBusiness=true | Legal business name |
billingDetail.taxId | string | Required for EU business buyers | VAT / tax ID (e.g. DE123456789) |
buyerEmail | string | Conditional | Buyer email; required if not pre-filled on the session |
buyerIp | string | No | Buyer IP address (used for tax calculation) |
successUrl | string | No | Post-checkout redirect URL; overrides the session-level value |
Example Request
Success Response (200)
Response Fields
| Field | Type | Description |
|---|---|---|
checkoutUrl | string | PSP checkout URL — redirect the buyer here to complete payment |
Errors
Retry policy: Never retry 4xx — fix the request and resubmit. Retry 5xx with exponential backoff (start 5s, max 3 attempts).
| Status | errors[0].message | What it means | Recommended handling |
|---|---|---|---|
| 400 | Invalid JSON body | Request body is not valid JSON | Fix the request body, then resubmit |
| 400 | Missing required field: checkoutSessionId | checkoutSessionId was not provided | Fix the request body, then resubmit |
| 400 | Session product type mismatch: expected subscription | The session was created for a non-subscription product | Use a session created for a subscription product |
| 400 | Environment mismatch between request and session | Request X-Environment does not match the session environment | Align the request environment with the session |
| 400 | Session missing subscription information (productVersionId or billingPeriod) | Session is malformed — missing required subscription fields | Recreate the checkout session |
| 400 | Missing billingDetail: provide in request body or pre-fill in checkout session | Neither the body nor the session contains billingDetail | Provide billingDetail in the body, then resubmit |
| 400 | State is required for US/CA | billingDetail.state is required for US / CA buyers | Add billingDetail.state, then resubmit |
| 401 | Authentication failed | Session token invalid, expired, or malformed | Re-mint the session token via Issue Session Token |
| 403 | Session does not belong to this store | The session belongs to a different store | Verify the session’s store ownership |
| 409 | Checkout session invalid, please re-enter checkout | Session does not exist or has expired | Re-create the checkout session |
| 500 | Internal server error | Unexpected server-side failure | Retry with exponential backoff (start 5s, max 3 attempts) |