Commerce API reference

Catalog, Stripe Connect, Checkout, discounts, auctions. All endpoints are tenant-scoped and require Authorization: Bearer kl_live_*.

No-code option: Manage products, prices, stock, images and Stripe Connect onboarding from the customer portal at /app/catalog. Use this API when you need to script catalog sync from your own backend.

Endpoint index

Method + pathPurpose
GET /v1/me/catalog/productsList products (filterable)
GET /v1/me/catalog/products/:idGet one product
POST /v1/me/catalog/productsUpsert a single product
POST /v1/me/catalog/syncBulk upsert (up to 500 items)
DELETE /v1/me/catalog/products/:idArchive (soft-delete)
GET /v1/me/commerce/connect/statusStripe Connect onboarding status
POST /v1/me/commerce/connect/onboarding-linkGet a Stripe Express onboarding URL
POST /v1/me/commerce/checkoutMint a Stripe Checkout session
GET /v1/me/commerce/discountsList discount codes
POST /v1/me/commerce/discountsCreate a discount code
POST /v1/me/commerce/discounts/drop/:streamIdDrop a time-limited code during a stream
GET /v1/me/commerce/discounts/check/:codeVerify a code is still redeemable
GET /v1/me/commerce/auctionsList auctions (filter by status)
POST /v1/me/commerce/auctionsCreate an auction
POST /v1/me/commerce/auctions/:id/bidPlace a bid (atomic)

Product object

{
  "id":             "prod_xxx",
  "externalId":     "SKU-1234",     // your own SKU — used for idempotent upserts
  "name":           "Linen Dress",
  "description":    "100% European linen",
  "imageUrl":       "https://cdn.example.com/sku-1234.webp",
  "priceCents":     4900,           // 49.00 USD
  "compareAtCents": 7900,           // MSRP for "X% off" display
  "currency":       "USD",
  "stock":          17,             // -1 = unlimited / don't track
  "lowStockAt":     5,              // emits inventory.low when crossed
  "active":         true,
  "stripePriceId":  "price_xxx",    // cached after first sale (read-only)
  "metadata":       { "color": "linen-natural" },
  "createdAt":      "...",
  "updatedAt":      "..."
}

Discount object

{
  "id":             "disc_xxx",
  "code":           "FLASH50",      // case-insensitive at redeem
  "percentOff":     50,             // OR amountOffCents — not both
  "amountOffCents": null,
  "startsAt":       null,
  "endsAt":         "2026-05-21T19:00:00.000Z",
  "maxRedemptions": 100,
  "redemptions":    23,
  "maxPerCustomer": 1,
  "streamId":       "stream_abc",   // optional: locks code to a stream
  "active":         true,
  "createdAt":      "..."
}

Auction object

{
  "id":                 "auc_xxx",
  "productId":          "prod_xxx",
  "streamId":           "stream_abc",
  "startingBidCents":   5000,
  "reservePriceCents":  8000,       // optional; if top bid is below this, no winner
  "bidIncrementCents":  100,
  "endsAt":             "2026-05-21T19:03:00.000Z",
  "antiSnipeSec":       10,         // bid in last N sec → endsAt extended by N
  "status":             "LIVE",     // LIVE | ENDED | SETTLED | CANCELLED
  "winningBidId":       null,
  "bids":               [ /* most recent bid */ ]
}

Order object

{
  "id":                       "ord_xxx",
  "stripeCheckoutSessionId":  "cs_test_...",
  "stripePaymentIntentId":    "pi_test_...",
  "customerExternalId":       "user_42",
  "customerEmail":            "buyer@example.com",
  "streamId":                 "stream_abc",
  "subtotalCents":            9800,
  "discountCents":            4900,
  "totalCents":               4900,
  "currency":                 "USD",
  "status":                   "PAID",      // PENDING | PAID | FULFILLED | REFUNDED | ...
  "discountCode":             "FLASH50",
  "applicationFeeCents":      142,         // 2.9% platform fee Kardolive took
  "items": [
    { "productId": "prod_xxx", "nameSnapshot": "Linen Dress", "priceCents": 4900, "quantity": 2 }
  ],
  "paidAt":                   "2026-05-21T18:30:00.000Z"
}

Stripe Connect setup

To accept money, sellers need a Stripe Express account linked to their Kardolive tenant.

  1. Seller (or admin on their behalf) calls POST /v1/me/commerce/connect/onboarding-link with returnUrl + refreshUrl.
  2. Kardolive creates a Stripe account (Express, type=express, capabilities=card_payments + transfers) and returns a one-time onboarding URL.
  3. Redirect the seller to that URL. Stripe walks them through bank account + identity verification.
  4. When done, Stripe redirects back to your returnUrl.
  5. Stripe fires account.updated to Kardolive's webhook endpoint. Kardolive flips stripeChargesEnabled = true on the tenant.
  6. Now you can call /checkout.

Platform fee (optional)

Set STRIPE_PLATFORM_FEE_PCT on the API server (e.g. 2.9 for 2.9%). Kardolive automatically attaches an application_fee_amount on every Checkout — the fee is routed to your platform Stripe account, the rest to the seller. Default: 0% (seller keeps everything).

Checkout flow (full sequence)

1. Your client sends cart items to your backend
   POST /api/cart/checkout  { items, streamId, discountCode? }

2. Your backend calls Kardolive
   POST /v1/me/commerce/checkout  → { url, sessionId }

3. Your backend returns the Stripe URL to the client

4. Client opens window.location = url (or new tab)
   → Stripe-hosted Checkout

5. Buyer pays
   → Stripe sends checkout.session.completed to Kardolive's webhook endpoint
   → Kardolive marks order PAID, decrements stock, fires purchase.completed → your endpoint

6. Your endpoint receives purchase.completed
   → Create Order row in your ERP, deduct inventory, trigger fulfillment, send email

Idempotency & ordering

Pricing & currency

All monetary fields are integer cents — never floats. $49.00 = 4900. Currency is ISO 4217 lowercase at the API boundary (we normalize to uppercase in storage). Mixed-currency carts are not supported: every item in a checkout must share the same currency.

Errors

CodeWhen
400 "Seller has not completed Stripe Connect onboarding"chargesEnabled = false on the tenant
400 "only N of X remaining"Cart quantity exceeds stock
400 "min bid is N cents"Bid below current top + increment
400 "auction has ended"Bid arrived after endsAt (no anti-snipe extension because remaining > threshold)
404 "product not found"productId not in this tenant

Next

Live shopping guide → · Webhooks →