docsCore ConceptsCheckout Flow

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

StateDescriptionTransitions
openSession created with itemsready_for_payment, canceled
not_ready_for_paymentMissing required info (address, etc.)ready_for_payment
ready_for_paymentAll info present, can completecompleted, canceled
completedPurchase finalizedTerminal state
canceledSession canceledTerminal 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:

RequirementDescription
Line itemsAt least one item in cart
Shipping addressValid address provided (for physical goods)
Payment methodPayment 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 StatusCan 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:

ComponentRate
Tax8% 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

FieldTypeDescription
product_idstringProduct identifier from catalog
variant_skustringSpecific variant SKU (optional)
quantityintegerNumber of units
titlestringResolved product title
unit_pricenumberPrice per unit
currencystringCurrency code
subtotalnumberunit_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