.
| Field | Type | Required | Description |
|---|
planId | string | Yes | Unique identifier for the subscription tier (e.g., builder, pro). |
billing | string | Yes | Billing frequency. Accepted values: monthly, yearly. |
email | string | Yes | Customer's email address for the checkout session. |
name | string | No | Customer's full name. |
successUrl | string | No | URL to redirect upon successful payment. |
returnUrl | string | No | URL to redirect if the user cancels or returns. |
Example POST Payload:
{
"planId": "pro",
"billing": "yearly",
"email": "developer@example.com",
"name": "Jane Doe",
"successUrl": "https://app.example.com/dashboard?checkout=success",
"returnUrl": "https://app.example.com/pricing"
}
GET Request
The GET method requires no parameters, headers, or query strings. It is used to audit the Paddle integration status and retrieve available plan keys.
POST Response
On success, the endpoint returns a 200 OK status with a JSON object containing the resolved Paddle price ID.
| Status Code | Description | Example Response |
|---|
200 | Success | {"priceId": "pri_01h7x9k3m2v4n5p6q7r8s9t0"} |
400 | Missing Fields | {"error": "Missing required fields: planId, billing, email"} |
400 | Invalid Plan | {"error": "Invalid plan: pro/weekly. Please configure PADDLE_PRO_WEEKLY_PRICE_ID"} |
500 | Internal Server Error | {"error": "Failed to create checkout session"} |
GET Response
The GET request returns a 200 OK status with configuration metadata.
| Status Code | Description | Example Response |
|---|
200 | Success | {"configured": true, "environment": "production", "plans": ["builder", "pro"]} |
500 | Internal Server Error | {"error": "Failed to create checkout session"} |
Response Fields (GET):
configured (boolean): true if PADDLE_API_KEY and all required plan price IDs are present in the environment.
environment (string): Reflects the value of PADDLE_ENV (defaults to sandbox if unset).
plans (string[]): Array of available plan keys derived from the internal price map.
Usage Example
Resolving a Price ID (POST)
curl -X POST https://your-domain.com/api/checkout/create-session \
-H "Content-Type: application/json" \
-d '{
"planId": "builder",
"billing": "monthly",
"email": "user@example.com"
}'
Checking Configuration Status (GET)
curl -X GET https://your-domain.com/api/checkout/create-session
Common Pitfalls
-
Missing Environment Variables: The endpoint relies on dynamically constructed environment variables to map plans to Paddle price IDs. The error message explicitly indicates the expected format: PADDLE_${PLAN_ID}_${BILLING}_PRICE_ID (e.g., PADDLE_BUILDER_MONTHLY_PRICE_ID). If these are not defined in your deployment environment, the POST request will return a 400 error. Always verify your .env configuration matches this naming convention before deploying.
-
Expecting a Full Checkout Session: This endpoint does not return a checkout URL, session token, or redirect link. It only returns a priceId. Your frontend must use this value with the Paddle.js SDK (Paddle.Checkout.open({ priceId: response.priceId })) to actually render the payment modal. Attempting to redirect directly to the response or treating it as a session object will break the checkout flow.
-
Case Sensitivity & Billing Values: The planId and billing parameters are strictly case-sensitive and must exactly match the keys defined in your Paddle plan mapping. Passing Monthly instead of monthly, or Pro instead of pro, will trigger an invalid plan error. Always normalize these values to lowercase before sending the request, and ensure they align with the keys returned by the GET endpoint's plans array.
While this endpoint handles price resolution and configuration checks, a complete Paddle integration typically involves complementary routes that work in tandem:
- Webhook Handler: A dedicated endpoint (e.g.,
/api/webhooks/paddle) is required to receive and process asynchronous events from Paddle, such as subscription.created, payment.succeeded, and subscription.updated. This ensures your application's database stays synchronized with Paddle's billing state after the checkout session completes.
- User Subscription Status: Frontend applications often query a user-specific endpoint to retrieve current subscription details, trial status, and payment history. This data is typically updated via the webhook handler after the checkout flow initiated by this endpoint finishes.
- Paddle.js Client Initialization: On the client side, developers must initialize the Paddle SDK using your Vendor ID and Environment ID before calling this endpoint. The
priceId returned here is passed directly into Paddle.Checkout.open() to launch the payment modal, making this route a critical bridge between your Next.js backend and the Paddle frontend SDK.