Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.fluveo.com/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks through the full commerce flow: create a product, set a price, and collect payment using a Checkout Session or a shareable Checkout Link.

Overview

The commerce model has four layers:
  1. Product — what you sell (name, description, images)
  2. Price — how much it costs (amount, currency, one-time or recurring)
  3. Checkout Session — a server-driven payment flow for a specific set of line items
  4. Checkout Link — a shareable, reusable payment URL (no code required)

Step 1: Create a product

curl -X POST https://api.leanrails.com/v1/products \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Ergonomic Standing Desk",
    "description": "Height-adjustable bamboo standing desk, 60x30 inches",
    "images": ["https://cdn.example.com/desk-hero.jpg"],
    "shippable": true,
    "metadata": {
      "warehouse_sku": "DESK-BAMBOO-60"
    }
  }'
Response:
{
  "id": "prod_8mn4qr7vw2xz",
  "object": "product",
  "active": true,
  "name": "Ergonomic Standing Desk",
  "description": "Height-adjustable bamboo standing desk, 60x30 inches",
  "images": ["https://cdn.example.com/desk-hero.jpg"],
  "default_price": null,
  "shippable": true,
  "metadata": {
    "warehouse_sku": "DESK-BAMBOO-60"
  },
  "livemode": false,
  "created": 1742025600,
  "updated": 1742025600
}
You can also create a product with an inline price using default_price_data:
curl -X POST https://api.leanrails.com/v1/products \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Wireless Keyboard",
    "default_price_data": {
      "currency": "usd",
      "unit_amount": 7900
    }
  }'

Step 2: Create a price

If you did not use default_price_data, create a price separately:
curl -X POST https://api.leanrails.com/v1/prices \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "product": "prod_8mn4qr7vw2xz",
    "currency": "usd",
    "unit_amount": 49900
  }'
Response:
{
  "id": "price_3fg6hj9km1np",
  "object": "price",
  "active": true,
  "product": "prod_8mn4qr7vw2xz",
  "currency": "usd",
  "type": "one_time",
  "billing_scheme": "per_unit",
  "unit_amount": 49900,
  "tax_behavior": "unspecified",
  "metadata": {},
  "livemode": false,
  "created": 1742025610
}

Step 2b: Create product variants (optional)

If your product comes in different configurations (size, color, material), create variants. Each variant is linked to a Price.
curl -X POST https://api.leanrails.com/v1/products/prod_8mn4qr7vw2xz/variants \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "title": "Bamboo — 60x30",
    "price_id": "price_3fg6hj9km1np",
    "sku": "DESK-BAMBOO-60",
    "weight": 25000,
    "weight_unit": "g"
  }'

Create with inline price

curl -X POST https://api.leanrails.com/v1/products/prod_8mn4qr7vw2xz/variants \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "title": "Walnut — 72x30",
    "price": 69900,
    "currency": "usd",
    "sku": "DESK-WALNUT-72"
  }'
When you provide price instead of price_id, a Price object is automatically created and linked to the variant.
When creating a product with default_price_data, a hidden default variant (is_default: true) is automatically created and linked to the price. You don’t need to create it manually.

Step 3: Accept payment with a Checkout Session

Create a Checkout Session to collect payment for one or more line items. In payment mode, a PaymentIntent is created automatically.
curl -X POST https://api.leanrails.com/v1/checkout/sessions \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "mode": "payment",
    "line_items": [
      {
        "price": "price_3fg6hj9km1np",
        "quantity": 1
      }
    ],
    "success_url": "https://yourstore.com/thank-you?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://yourstore.com/cart"
  }'
Response:
{
  "id": "cs_5ab7cd9ef1gh",
  "object": "checkout.session",
  "mode": "payment",
  "status": "open",
  "payment_status": "unpaid",
  "ui_mode": "hosted",
  "url": "https://checkout.leanrails.com/cs/cs_5ab7cd9ef1gh",
  "payment_intent": "pi_2wx4yz6ab8cd",
  "currency": "usd",
  "amount_subtotal": 49900,
  "amount_total": 49900,
  "livemode": false,
  "created": 1742025620
}
Redirect your customer to the url to complete payment. For a no-code option, create a reusable Checkout Link that you can share anywhere:
curl -X POST https://api.leanrails.com/v1/checkout_links \
  -u "sk_test_xxx:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "title": "Standing Desk",
    "line_items": [
      {
        "price": "price_3fg6hj9km1np",
        "quantity": 1
      }
    ],
    "after_completion": {
      "type": "redirect",
      "redirect": {
        "url": "https://yourstore.com/thank-you"
      }
    }
  }'
Response:
{
  "id": "cl_4de6fg8hi0jk",
  "object": "checkout_link",
  "active": true,
  "url": "https://checkout.leanrails.com/cl/cl_4de6fg8hi0jk",
  "title": "Standing Desk",
  "currency": "usd",
  "livemode": false,
  "created": 1742025630
}
Share the url via email, social media, or embed it on your website.

Step 4: Handle the completion webhook

When payment completes, you receive a checkout.session.completed webhook event:
# Example webhook payload
{
  "id": "evt_1abc2def3ghi",
  "type": "checkout.session.completed",
  "data": {
    "object": {
      "id": "cs_5ab7cd9ef1gh",
      "object": "checkout.session",
      "status": "complete",
      "payment_status": "paid",
      "payment_intent": "pi_2wx4yz6ab8cd",
      "amount_total": 49900,
      "currency": "usd"
    }
  }
}
Use this event to fulfill the order, send a confirmation email, or update your database.
Always verify webhook signatures before processing events. See the Webhooks guide for details on signature verification.

Next steps