Skip to Content

Start Checkout

Create checkout URLs without requiring prior user authentication. Automatically handles user creation and returns a payment URL.

Server-Side Only: This is a server-side API that requires authentication with your API key.

Overview

The Start Checkout API endpoint allows you to programmatically create payment sessions for your users. This is ideal for:

  • E-commerce integration - Direct checkout from product pages
  • Custom payment flows - Build your own checkout experience
  • Automated billing - Programmatically start subscriptions
  • Trial management - Include trial periods in checkout

API Reference

Endpoint

POST https://onlineapp.pro/api/v1/paywall/{paywallId}/start-checkout

Authentication

Include the x-api-key header with your API key.

Get your API key

API Key Location

Get your paywall ID

Navigate to your paywall settings page and get the ID from the Paywall ID field:

Paywall ID location

Get price ID

Use the Get Prices API to retrieve available price IDs.

Request Body

{ "email": "user@example.com", "priceId": "456", "successUrl": "https://mysite.com/payment/success", "errorUrl": "https://mysite.com/payment/error", "shopUrl": "https://mysite.com/shop", "ignoreActivePurchase": false, "trial_days": 7, "userMeta": { "my-user-uuid": "pojfoih27938y50ujtb4ip1n2b", "utm_source": "facebook" } }

Required Fields

FieldTypeDescription
emailstringUser’s email address
priceIdstringPrice ID from your paywall configuration
successUrlstringURL to redirect after successful payment
errorUrlstringURL to redirect after payment failure
shopUrlstringURL to redirect if user cancels checkout

Optional Fields

FieldTypeDescription
ignoreActivePurchasebooleanWhether to ignore existing active purchases (default: false). By default, if a user already has an active subscription, calling start checkout returns a 409 error. To allow user subscription upgrades, pass this argument as true - the previous subscription will be cancelled after successful purchase.
trial_daysnumberNumber of trial days to include in subscription
userMetaobjectCustom metadata to associate with user (returned in webhooks)

Response Format

{ "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_...", "userId": "uuid-of-user", "acquiring": "stripe" }

Basic Usage

Simple Checkout Creation

const createCheckout = async (userEmail, priceId) => { const paywallId = '123'; try { const response = await fetch(`https://onlineapp.pro/api/v1/paywall/${paywallId}/start-checkout`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-secret-api-key' }, body: JSON.stringify({ email: userEmail, priceId: priceId, successUrl: 'https://mysite.com/payment/success', errorUrl: 'https://mysite.com/payment/error', shopUrl: 'https://mysite.com/shop' }) }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); return data; } catch (error) { console.error('Failed to create checkout:', error); throw error; } }; // Usage const checkout = await createCheckout('user@example.com', '456'); console.log('Checkout URL:', checkout.checkoutUrl);

Checkout with Trial

const createTrialCheckout = async (userEmail, priceId, trialDays = 7) => { const paywallId = '123'; const response = await fetch(`https://onlineapp.pro/api/v1/paywall/${paywallId}/start-checkout`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-secret-api-key' }, body: JSON.stringify({ email: userEmail, priceId: priceId, trial_days: trialDays, successUrl: 'https://mysite.com/payment/success', errorUrl: 'https://mysite.com/payment/error', shopUrl: 'https://mysite.com/shop', userMeta: { trial_signup: 'true', signup_source: 'landing_page' } }) }); return response.json(); };

Process Flow

Validate Parameters

  • Check email format
  • Verify price ID exists
  • Validate URL formats

Authentication

  • Verify API key
  • Check paywall permissions

User Management

  • Find existing user by email
  • Create new user if needed
  • Link user to paywall

Purchase Validation

  • Check for active purchases (unless ignored)
  • Validate price and paywall combination

Payment Session

  • Create checkout session with payment processor
  • Configure trial period if specified
  • Set redirect URLs

Response

  • Return checkout URL and user information

Error Handling

Common Error Responses

StatusErrorDescription
400Bad RequestMissing or invalid parameters
401UnauthorizedInvalid API key
404Not FoundPaywall or price not found
409ConflictUser has active purchase (when not ignored)
500Internal Server ErrorPayment processor error

Error Handling Example

const handleCheckoutError = (error, response) => { switch (response?.status) { case 400: return 'Please check your input and try again.'; case 401: return 'Authentication failed. Please contact support.'; case 404: return 'Selected plan is no longer available.'; case 409: return 'You already have an active subscription.'; default: return 'Something went wrong. Please try again later.'; } };

Integration

Redirect to Checkout

// After receiving the checkout URL, redirect the user: window.location.href = data.checkoutUrl; // Or open in new tab: window.open(data.checkoutUrl, '_blank');

React Component Example

import { useState } from 'react'; const CheckoutForm = ({ priceId, planName, trialDays = 0 }) => { const [email, setEmail] = useState(''); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); setIsLoading(true); setError(''); try { const response = await fetch('/api/create-checkout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, priceId, trialDays, userMeta: { plan_selected: planName, signup_page: window.location.pathname } }) }); const data = await response.json(); if (data.success) { window.location.href = data.checkoutUrl; } else { setError(data.error || 'Failed to create checkout'); } } catch (err) { setError('Network error. Please try again.'); } finally { setIsLoading(false); } }; return ( <form onSubmit={handleSubmit} className="checkout-form"> <h3>Subscribe to {planName}</h3> {trialDays > 0 && ( <p className="trial-info"> Start with a {trialDays}-day free trial </p> )} <div className="form-group"> <label htmlFor="email">Email Address</label> <input type="email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} required placeholder="Enter your email" /> </div> {error && ( <div className="error-message"> {error} </div> )} <button type="submit" disabled={isLoading || !email} className="checkout-button" > {isLoading ? 'Creating checkout...' : trialDays > 0 ? 'Start Free Trial' : 'Subscribe Now'} </button> </form> ); };

Payment Status Tracking

Webhooks Recommended: Webhooks provide the most reliable payment tracking, ensuring notification delivery even if users close their browsers after payment.

Webhook Integration

app.post('/webhook/paywall', express.raw({type: 'application/json'}), (req, res) => { const event = req.body; switch (event.type) { case 'payment.completed': console.log('Payment completed:', event.data); updateUserSubscription(event.data.user.id, 'active'); break; case 'subscription.created': console.log('Subscription created:', event.data); updateUserSubscription(event.data.user.id, 'active'); break; case 'subscription.cancelled': console.log('Subscription cancelled:', event.data); updateUserSubscription(event.data.user.id, 'cancelled'); break; case 'refund.created': console.log('Refund created:', event.data); handleRefund(event.data.user.id); break; } res.json({received: true}); });

Security Guidelines

1. Secure API Key Storage

// Good: Server-side environment variable const apiKey = process.env.PAYWALL_API_KEY; // Bad: Client-side exposure // const apiKey = 'sk_live_...'; // Never do this!

2. Input Validation

const validateCheckoutInput = (data) => { const errors = []; // Email validation if (!data.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) { errors.push('Valid email is required'); } // URL validation const urlRegex = /^https?:\/\/.+/; ['successUrl', 'errorUrl', 'shopUrl'].forEach(field => { if (data[field] && !urlRegex.test(data[field])) { errors.push(`${field} must be a valid URL`); } }); return errors; };

Best Practices

1. Always Use HTTPS

// Ensure all URLs use HTTPS const ensureHttps = (url) => { if (url.startsWith('http://')) { return url.replace('http://', 'https://'); } return url; };

2. Handle User Experience

const createCheckoutWithUX = async (data) => { // Show loading state showLoadingSpinner('Creating checkout...'); try { const result = await createCheckout(data); // Show success message briefly before redirect showSuccessMessage('Redirecting to payment...'); setTimeout(() => { window.location.href = result.checkoutUrl; }, 1000); } catch (error) { hideLoadingSpinner(); showErrorMessage('Failed to create checkout. Please try again.'); } };

Next Steps

Last updated on