Checkout API
Initialize and complete checkout sessions
Checkout API
The Checkout API handles the core checkout flow: initializing sessions with payment providers, completing purchases, and retrieving payment tokens for upsells.
Initialize Checkout
Initialize a checkout session with a payment provider.
POST /api/checkout/initialize
Content-Type: application/jsonRequest Body
interface InitializeRequest {
token: string; // JWT checkout token
provider: PaymentProviderType; // Payment provider to use
// Optional: Override/update customer info (for global links)
customer?: {
email: string;
firstName: string;
lastName: string;
phone?: string;
};
// Optional: Override/update addresses
shippingAddress?: {
line1: string;
line2?: string;
city: string;
state: string;
postalCode: string;
country: string;
};
billingAddress?: {
line1: string;
line2?: string;
city: string;
state: string;
postalCode: string;
country: string;
};
}
type PaymentProviderType =
| 'stripe'
| 'nmi'
| 'sticky'
| 'konnektive'
| 'shopify'
| 'ultracart'
| 'epd';Example Request
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"provider": "stripe",
"customer": {
"email": "customer@example.com",
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890"
},
"shippingAddress": {
"line1": "123 Main St",
"city": "New York",
"state": "NY",
"postalCode": "10001",
"country": "US"
}
}Success Response
{
"success": true,
"provider": "stripe",
"providerOrderId": "pi_3ABC123DEF456",
"clientSecret": "pi_3ABC123DEF456_secret_xyz789"
}Response fields vary by provider:
| Provider | Response Fields |
|---|---|
| Stripe | clientSecret for Stripe.js |
| Shopify | checkoutUrl for redirect |
| NMI | providerOrderId |
| Sticky.io | providerOrderId |
Error Responses
// Missing token or provider
{
"error": "Missing token or provider"
}
// Status: 400
// Invalid or expired token
{
"error": "Invalid token"
}
// Status: 401
// Provider not allowed for this checkout
{
"error": "Payment provider not allowed for this checkout"
}
// Status: 400Complete Checkout
Complete checkout after successful payment. Creates order records, retrieves payment tokens for upsells, and optionally records in CRM.
POST /api/checkout/complete
Content-Type: application/jsonRequest Body
interface CompleteCheckoutRequest {
// Required fields
orderId: string;
transactionId: string;
provider: PaymentProviderType;
customerEmail: string;
customerName: string;
amount: number; // In cents (9999 = $99.99)
currency: string;
// Optional: Provider-specific order ID
providerOrderId?: string;
// Optional: Customer and address info for CRM
customer?: {
firstName: string;
lastName: string;
phone?: string;
ipAddress?: string;
};
billingAddress?: {
line1: string;
line2?: string;
city: string;
state: string;
postalCode: string;
country: string;
};
shippingAddress?: {
line1: string;
line2?: string;
city: string;
state: string;
postalCode: string;
country: string;
};
lineItems?: Array<{
id: string;
name?: string;
quantity: number;
unitPrice: number;
sku?: string;
}>;
// CRM options
recordInCrm?: boolean;
crmProvider?: 'konnektive' | 'sticky' | 'ultracart' | 'none';
crmCampaignId?: string;
affId?: string;
subId?: string;
// Sales attribution for commissions
salesAttribution?: {
salespersonId: string;
salespersonName?: string;
salespersonEmail?: string;
teamId?: string;
teamName?: string;
commissionRate?: number; // 0.10 = 10%
commissionType?: 'percentage' | 'fixed';
source?: string;
campaignCode?: string;
generatedAt?: number;
};
}Example Request
{
"orderId": "order_abc123",
"transactionId": "pi_3ABC123DEF456",
"provider": "stripe",
"providerOrderId": "pi_3ABC123DEF456",
"customerEmail": "customer@example.com",
"customerName": "John Doe",
"amount": 9999,
"currency": "USD",
"customer": {
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890",
"ipAddress": "192.168.1.1"
},
"billingAddress": {
"line1": "123 Main St",
"city": "New York",
"state": "NY",
"postalCode": "10001",
"country": "US"
},
"lineItems": [
{
"id": "prod_123",
"name": "Premium Plan",
"quantity": 1,
"unitPrice": 9999,
"sku": "PREM-001"
}
],
"recordInCrm": false,
"salesAttribution": {
"salespersonId": "sp_123",
"salespersonName": "Jane Smith",
"commissionRate": 0.10,
"commissionType": "percentage"
}
}Success Response
{
"success": true,
"orderId": "order_abc123",
"transactionId": "pi_3ABC123DEF456",
"paymentMethodToken": "pm_1ABC|cus_XYZ",
"provider": "stripe",
"crmOrderId": "12345678",
"crmProvider": "konnektive",
"commissionId": "comm_xyz789"
}Payment Method Token Formats
The paymentMethodToken enables 1-click upsell charges:
| Provider | Format | Usage |
|---|---|---|
| Stripe | paymentMethodId|customerId | PaymentIntent with saved method |
| NMI | customerVaultId|transactionId | Customer vault charge |
| Sticky.io | stickyOrderId | Add-to-order |
| Konnektive | orderId | Add-to-order |
Get Payment Token
Retrieve payment method token for processing upsell charges.
POST /api/checkout/get-payment-token
Content-Type: application/jsonRequest Body
{
"provider": "stripe",
"transactionId": "pi_3ABC123DEF456",
"providerOrderId": "pi_3ABC123DEF456"
}Response
{
"success": true,
"paymentMethodToken": "pm_1ABC|cus_XYZ",
"provider": "stripe"
}Generate Token (Development)
Generate checkout tokens and short URLs for development and testing.
POST /api/token/generate
Content-Type: application/jsonRequest Body
interface GenerateTokenRequest {
orderInfo?: {
orderId?: string;
total?: number;
currency?: string;
productName?: string;
productDescription?: string;
};
lineItems?: Array<{
id: string;
name: string;
description?: string;
quantity: number;
unitPrice: number;
}>;
customer?: {
email?: string;
firstName?: string;
lastName?: string;
phone?: string;
};
salesAttribution?: {
salespersonId: string;
salespersonName?: string;
commissionRate?: number;
};
}Response
{
"success": true,
"code": "abc123",
"checkoutUrl": "https://checkout.example.com/c/abc123",
"token": "eyJhbGciOiJIUzI1NiIs...",
"payload": {
"orderId": "order_test_123",
"total": 4999,
"currency": "USD"
}
}This endpoint auto-generates demo data if fields are not provided. Use it for testing checkout flows and sales attribution.
Checkout Flow Diagram
┌─────────────────────────────────────────────────────────────────┐
│ Your Server │
├─────────────────────────────────────────────────────────────────┤
│ 1. Generate JWT token with order details │
│ └─> Sign with CHECKOUT_TOKEN_SECRET │
└───────────────────────────┬─────────────────────────────────────┘
│
v
┌─────────────────────────────────────────────────────────────────┐
│ Checkout Frontend │
├─────────────────────────────────────────────────────────────────┤
│ 2. Customer enters info, selects payment method │
│ │
│ 3. POST /api/checkout/initialize │
│ └─> Returns clientSecret (Stripe) or checkoutUrl │
│ │
│ 4. Collect payment via provider SDK │
│ └─> Stripe.js, hosted form, etc. │
│ │
│ 5. POST /api/checkout/complete │
│ └─> Creates order, returns paymentMethodToken │
│ │
│ 6. (Optional) Create upsell session │
│ └─> POST /api/upsell/create-session │
└───────────────────────────┬─────────────────────────────────────┘
│
v
┌─────────────────────────────────────────────────────────────────┐
│ Webhook Delivery │
├─────────────────────────────────────────────────────────────────┤
│ 7. Events sent to configured webhooks │
│ - checkout.completed │
│ - payment.succeeded │
│ - order.confirmed │
└─────────────────────────────────────────────────────────────────┘Error Codes
| Code | Description |
|---|---|
INVALID_TOKEN | The checkout token is invalid or expired |
CHECKOUT_NOT_FOUND | No checkout found for the given token |
CHECKOUT_EXPIRED | The checkout session has expired |
PAYMENT_FAILED | Payment processing failed |
VALIDATION_ERROR | Request validation failed |
PROVIDER_NOT_ALLOWED | Payment provider not allowed for this checkout |
Error Response Format
{
"error": "Payment failed: Card declined",
"details": "insufficient_funds"
}Code Examples
Node.js / TypeScript
// Initialize checkout
const initResponse = await fetch('/api/checkout/initialize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: checkoutToken,
provider: 'stripe',
customer: {
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe',
},
}),
});
const { clientSecret } = await initResponse.json();
// Use Stripe.js to confirm payment
const { error, paymentIntent } = await stripe.confirmPayment({
elements,
clientSecret,
confirmParams: {
return_url: `${window.location.origin}/success`,
},
});
if (!error && paymentIntent.status === 'succeeded') {
// Complete checkout
const completeResponse = await fetch('/api/checkout/complete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderId: 'order_123',
transactionId: paymentIntent.id,
provider: 'stripe',
customerEmail: 'customer@example.com',
customerName: 'John Doe',
amount: 9999,
currency: 'USD',
}),
});
const { paymentMethodToken } = await completeResponse.json();
// Use token for upsells if needed
}Python
import requests
# Initialize checkout
init_response = requests.post(
'https://checkout.example.com/api/checkout/initialize',
json={
'token': checkout_token,
'provider': 'stripe',
'customer': {
'email': 'customer@example.com',
'firstName': 'John',
'lastName': 'Doe',
},
}
)
data = init_response.json()
client_secret = data['clientSecret']
# Complete checkout after payment
complete_response = requests.post(
'https://checkout.example.com/api/checkout/complete',
json={
'orderId': 'order_123',
'transactionId': 'pi_abc123',
'provider': 'stripe',
'customerEmail': 'customer@example.com',
'customerName': 'John Doe',
'amount': 9999,
'currency': 'USD',
}
)
result = complete_response.json()
print(f"Order completed: {result['orderId']}")
print(f"Payment token: {result['paymentMethodToken']}")CRM Integration
When recordInCrm is true, the order is recorded in the configured CRM after payment:
{
"orderId": "order_123",
"transactionId": "pi_abc",
"provider": "stripe",
"recordInCrm": true,
"crmProvider": "konnektive",
"crmCampaignId": "camp_123",
"customer": { ... },
"billingAddress": { ... },
"lineItems": [ ... ]
}Note: CRM recording requires customer and billingAddress fields. If these are missing, CRM recording is skipped (unless failOnCrmError is configured).
The response includes CRM order ID:
{
"success": true,
"orderId": "order_123",
"crmOrderId": "12345678",
"crmProvider": "konnektive"
}