Checkout Flow
This guide explains how checkout sessions work in Lorn AI, including session states, lifecycle management, and best practices for handling purchases.
Overview
A checkout session represents a shopping cart that progresses through defined states until completion or cancellation. Each session maintains complete state—items, pricing, shipping, and customer information.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ │ │ │ │ │ │ │
│ Create │────▶│ Update │────▶│ Complete │────▶│ Order │
│ Session │ │ Session │ │ Session │ │ Fulfilled │
│ │ │ │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
POST PATCH POST Webhook
/checkout_sessions /checkout_sessions /complete order.created
/{id} Session States
State Diagram
┌──────────────────┐
│ │
┌───────▶│ not_ready_for │◀──────┐
│ │ payment │ │
│ │ │ │
│ └────────┬─────────┘ │
│ │ │
│ │ Add required │
│ │ information │
│ │ │
│ ▼ │
┌──────┴───────┐ ┌─────────────────┐ │
│ │ │ │ │
Created ───▶│ open │◀─│ ready_for │─────┘
│ │ │ payment │ Remove required
└──────────────┘ │ │ information
│ └────────┬────────┘
│ │
│ │ Complete
│ Cancel │
│ ▼
┌──────▼───────┐ ┌─────────────────┐
│ │ │ │
│ canceled │ │ completed │
│ │ │ │
└──────────────┘ └─────────────────┘State Descriptions
| State | Description | Transitions |
|---|---|---|
open | Session created with items | → ready_for_payment, canceled |
not_ready_for_payment | Missing required info (address, etc.) | → ready_for_payment |
ready_for_payment | All info present, can complete | → completed, canceled |
completed | Purchase finalized | Terminal state |
canceled | Session canceled | Terminal state |
Creating a Checkout Session
Basic Creation
curl -X POST "https://{{YOUR_STORE_URL}}/checkout_sessions" \
-H "Content-Type: application/json" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}" \
-d '{
"items": [
{
"product_id": "prod_abc123",
"variant_sku": "prod_abc123_black_m",
"quantity": 2
}
]
}'With Full Details
curl -X POST "https://{{YOUR_STORE_URL}}/checkout_sessions" \
-H "Content-Type: application/json" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}" \
-d '{
"items": [
{
"product_id": "prod_abc123",
"variant_sku": "prod_abc123_black_m",
"quantity": 2
}
],
"shipping_address": {
"name": "Jane Doe",
"line1": "123 Main Street",
"line2": "Apt 4B",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"customer": {
"email": "jane@example.com",
"phone": "+1-555-123-4567",
"name": "Jane Doe"
},
"payment_method": "demo_card"
}'Response
{
"checkout_session": {
"id": "cs_demo_a1b2c3d4e5",
"status": "open",
"currency": "USD",
"line_items": [
{
"product_id": "prod_abc123",
"variant_sku": "prod_abc123_black_m",
"quantity": 2,
"title": "Classic Cotton T-Shirt - Black (M)",
"unit_price": 29.99,
"currency": "USD",
"subtotal": 59.98
}
],
"shipping_address": {
"name": "Jane Doe",
"line1": "123 Main Street",
"line2": "Apt 4B",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"customer": {
"email": "jane@example.com",
"phone": "+1-555-123-4567",
"name": "Jane Doe"
},
"payment_method": "demo_card",
"shipping": {
"method": "ground",
"amount": 7.99,
"currency": "USD"
},
"tax": {
"rate": 0.08,
"amount": 4.80,
"currency": "USD"
},
"amounts": {
"subtotal": 59.98,
"tax": 4.80,
"shipping": 7.99,
"total": 72.77,
"currency": "USD"
},
"client_secret": "pi_demo_cs_demo_a1b2c3d4e5_secret_demo",
"created_at": "2024-01-15T10:30:00Z"
}
}Updating a Checkout Session
Update Cart Items
Replace all items in the cart:
curl -X PATCH "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}" \
-H "Content-Type: application/json" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}" \
-d '{
"items": [
{
"product_id": "prod_abc123",
"variant_sku": "prod_abc123_black_m",
"quantity": 3
},
{
"product_id": "prod_xyz789",
"quantity": 1
}
]
}'Update Shipping Address
curl -X PATCH "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}" \
-H "Content-Type: application/json" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}" \
-d '{
"shipping_address": {
"name": "Jane Doe",
"line1": "456 Oak Avenue",
"city": "Los Angeles",
"state": "CA",
"postal_code": "90001",
"country": "US"
}
}'Update Customer Information
curl -X PATCH "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}" \
-H "Content-Type: application/json" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}" \
-d '{
"customer": {
"email": "jane.doe@newmail.com",
"name": "Jane Doe"
}
}'Retrieving Checkout State
Get the current state of a checkout session:
curl "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}"This returns the full session state, useful for:
- Displaying cart summary
- Verifying totals before completion
- Resuming abandoned carts
Completing a Checkout
Finalize the purchase:
curl -X POST "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}/complete" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}"Success Response
{
"checkout_session": {
"id": "cs_demo_a1b2c3d4e5",
"status": "completed",
"currency": "USD",
"line_items": [...],
"amounts": {
"subtotal": 59.98,
"tax": 4.80,
"shipping": 7.99,
"total": 72.77,
"currency": "USD"
},
"created_at": "2024-01-15T10:30:00Z"
}
}Requirements for Completion
A session can only be completed when:
| Requirement | Description |
|---|---|
| Line items | At least one item in cart |
| Shipping address | Valid address provided (for physical goods) |
| Payment method | Payment method specified |
Canceling a Checkout
Cancel an in-progress session:
curl -X POST "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}/cancel" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}"Response
{
"checkout_session": {
"id": "cs_demo_a1b2c3d4e5",
"status": "canceled",
...
}
}Cancellation Rules
| Current Status | Can Cancel? |
|---|---|
open | ✅ Yes |
not_ready_for_payment | ✅ Yes |
ready_for_payment | ✅ Yes |
completed | ❌ No (returns 405) |
canceled | ❌ No (returns 405) |
Price Calculation
Lorn AI automatically calculates pricing on every session update:
Pricing Components
┌─────────────────────────────────────────────────────┐
│ Price Breakdown │
├─────────────────────────────────────────────────────┤
│ │
│ Line Item 1: $29.99 × 2 = $59.98 │
│ Line Item 2: $49.99 × 1 = $49.99 │
│ ──────── │
│ Subtotal: $109.97 │
│ │
│ Tax (8%): $8.80 │
│ Shipping (ground): $7.99 │
│ ──────── │
│ Total: $126.76 │
│ │
└─────────────────────────────────────────────────────┘Demo Mode Rates
In demo mode, fixed rates apply:
| Component | Rate |
|---|---|
| Tax | 8% of subtotal |
| Shipping | $7.99 (ground) |
Line Items
Structure
Each line item contains:
{
"product_id": "prod_abc123",
"variant_sku": "prod_abc123_black_m",
"quantity": 2,
"title": "Classic Cotton T-Shirt - Black (M)",
"unit_price": 29.99,
"currency": "USD",
"subtotal": 59.98
}Fields
| Field | Type | Description |
|---|---|---|
product_id | string | Product identifier from catalog |
variant_sku | string | Specific variant SKU (optional) |
quantity | integer | Number of units |
title | string | Resolved product title |
unit_price | number | Price per unit |
currency | string | Currency code |
subtotal | number | unit_price × quantity |
Best Practices
1. Use Idempotency Keys
Prevent duplicate orders with idempotency:
curl -X POST "https://{{YOUR_STORE_URL}}/checkout_sessions/{{SESSION_ID}}/complete" \
-H "X-ACP-API-Key: {{YOUR_API_KEY}}" \
-H "Idempotency-Key: complete_order_{{SESSION_ID}}_v1"2. Verify Before Completing
Always show the user the final totals:
# Get current state
session = get_checkout_session(session_id)
# Display for confirmation
print(f"Subtotal: ${session['amounts']['subtotal']}")
print(f"Tax: ${session['amounts']['tax']}")
print(f"Shipping: ${session['amounts']['shipping']}")
print(f"Total: ${session['amounts']['total']}")
# Get user confirmation
if user_confirms():
complete_checkout(session_id)3. Handle Errors Gracefully
Check for error messages in responses:
response = create_checkout(items)
session = response["checkout_session"]
# Check for issues
if session.get("messages"):
for msg in session["messages"]:
if msg["type"] == "error":
print(f"Error: {msg['content']}")
# Handle: out_of_stock, invalid item, etc.4. Support Cart Modifications
Allow users to update their cart:
# User wants to change quantity
session = update_checkout(session_id, {
"items": [
{"product_id": "prod_abc", "quantity": 3} # Updated quantity
]
})
# Show updated totals
print(f"New total: ${session['checkout_session']['amounts']['total']}")Complete Flow Example
import requests
BASE_URL = "https://{{YOUR_STORE_URL}}"
HEADERS = {"X-ACP-API-Key": "{{YOUR_API_KEY}}", "Content-Type": "application/json"}
# Step 1: Search for products
products = requests.get(
f"{BASE_URL}/acp/products",
params={"q": "running shoes", "max_price": 150},
headers=HEADERS
).json()
product = products["items"][0]
print(f"Found: {product['title']} - ${product['price']}")
# Step 2: Create checkout session
session = requests.post(
f"{BASE_URL}/checkout_sessions",
json={
"items": [{"product_id": product["id"], "quantity": 1}]
},
headers=HEADERS
).json()
session_id = session["checkout_session"]["id"]
print(f"Session created: {session_id}")
# Step 3: Add shipping address
session = requests.patch(
f"{BASE_URL}/checkout_sessions/{session_id}",
json={
"shipping_address": {
"name": "Jane Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"customer": {
"email": "jane@example.com"
}
},
headers=HEADERS
).json()
print(f"Total: ${session['checkout_session']['amounts']['total']}")
# Step 4: Complete the purchase
order = requests.post(
f"{BASE_URL}/checkout_sessions/{session_id}/complete",
headers=HEADERS
).json()
print(f"Order completed! Status: {order['checkout_session']['status']}")Next Steps
- API Reference: Checkout Sessions — Full endpoint documentation
- Webhooks — Receive order notifications
- Error Codes — Handle checkout errors