Koza
Start free
Back to Koza

Developers

Checkout API

Accept payments from your own site — hosted redirect or embedded form — then fulfill on checkout.session.completed. White-labeled as Koza Payments.

Secret keys

Bearer auth for server routes

Hosted or embedded

Redirect or mount on-site

Signed webhooks

HMAC delivery you can trust

Introduction

The Checkout Sessions API lets external stores (your SaaS, license shop, landing page) create a payment session on Koza, collect money through Koza Payments, and receive a signed webhook when the session is paid.

Important product rule

External Checkout sessions settle through Koza Payments and fire checkout.session.completed. They do not create a storefront Order unless your integration does. License keys, Discord roles, and downloads are your job in the webhook handler.

Base URL for live calls:

base
https://www.koza.cc

Authentication

Authenticate server-side requests with a store secret key. Create keys in Admin → API keys. Keys look like koza_sk_….

Authorization header
Authorization: Bearer koza_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keep secrets server-side

Never expose koza_sk_ keys in the browser. Only client_secret and publishable_key from an embedded session may run client-side via koza.js.

Concepts

Checkout session

A cs_… object representing one payment attempt: line items, amount, success/cancel URLs, and status (open → paid).

ui_mode

hosted redirects the buyer to Koza’s pay page (/pay/cs_…). embedded returns secrets so you mount the payment form on your domain.

Merchant webhooks

You configure a URL + events in Admin. We POST a signed JSON envelope when something happens — subscribe to checkout.session.completed for external sales.

Create a session

POST/api/v1/checkout/sessions

Creates a checkout session. Auth required. Accepts snake_case or camelCase.

FieldTypeDescription
line_itemsrequiredarrayAt least one item: name, amount_cents, quantity (default 1).
success_urlrequiredstring (url)Redirect after success. Supports {CHECKOUT_SESSION_ID}.
cancel_urlrequiredstring (url)Redirect if the buyer abandons.
ui_mode"hosted" | "embedded"Default hosted. Use embedded for on-site forms.
customer_emailstringPrefills email when present.
currencystring (3)ISO currency; defaults to the store currency.
client_reference_idstringYour internal order / cart id.
metadataobjectString key/values echoed on the session and webhook.
curl
curl -X POST https://www.koza.cc/api/v1/checkout/sessions \
  -H "Authorization: Bearer koza_sk_…" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [
      { "name": "Pro license", "amount_cents": 4900, "quantity": 1 }
    ],
    "success_url": "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://yoursite.com/cart",
    "ui_mode": "embedded",
    "customer_email": "buyer@example.com",
    "metadata": { "source": "your-app" }
  }'

Response (shape abbreviated):

201 response
{
  "ok": true,
  "id": "cs_…",
  "object": "checkout.session",
  "url": "https://www.koza.cc/pay/cs_…",
  "status": "open",
  "payment_status": "unpaid",
  "amount_total": 4900,
  "currency": "usd",
  "ui_mode": "embedded",
  "client_secret": "pi_…_secret_…",
  "publishable_key": "pk_…",
  "demo": false,
  "line_items": [
    { "name": "Pro license", "amount_cents": 4900, "quantity": 1 }
  ],
  "metadata": { "source": "your-app" }
}

Retrieve a session

GET/api/v1/checkout/sessions/:id

Fetch a session for your store (verify payment_status after redirect). Auth required.

curl
curl https://www.koza.cc/api/v1/checkout/sessions/cs_… \
  -H "Authorization: Bearer koza_sk_…"

Embedded checkout

Create the session with ui_mode: "embedded". Use the returned client_secret and publishable_key with koza.js on your page.

  1. Server creates session (secret key never leaves your backend).
  2. Browser mounts the payment form with koza.js.
  3. On success, call sync (or wait for the webhook) and fulfill on checkout.session.completed.

Hosted checkout

Default mode. Create a session, then redirect the buyer to session.url (/pay/cs_…).

redirect
// After create session on your server:
window.location.href = session.url;

// Or with koza.js:
Koza.redirectToCheckout({ url: session.url });

On success we send the buyer to your success_url with the session id substituted when you use the placeholder.

Sync after pay

POST/api/v1/checkout/sessions/:id/sync

After embedded confirm() succeeds, call sync so the session is marked paid even if the processor webhook is delayed. Verifies the payment when possible, then records ledger + fires checkout.session.completed. Session id is an unguessable cs_… token (API key optional).

curl
curl -X POST https://www.koza.cc/api/v1/checkout/sessions/cs_…/sync

Demo / local only:

POST/api/v1/checkout/sessions/:id/complete

Marks a session paid without a real card when payments are in demo mode. Not available when live processor keys are active.

koza.js

Client library for hosted redirect and embedded Payment Element. Load from your Koza origin:

script
<script src="https://www.koza.cc/koza.js"></script>
embedded
const checkout = await Koza.embeddedCheckout({
  clientSecret: data.client_secret,
  publishableKey: data.publishable_key,
  sessionId: data.id,
  returnUrl: "https://yoursite.com/success?session_id=" + data.id,
  appearance: {
    theme: "night",
    variables: { colorPrimary: "#c4f24a" },
  },
});

await checkout.mount("#koza-payment");

// On your Pay button:
const { error } = await checkout.confirm();
if (error) console.error(error);
// else: poll GET session or rely on webhook + optional POST …/sync
hosted redirect
Koza.redirectToCheckout({ url: session.url });
// optional: { url, mode: "popup" }

Webhooks

Configure endpoints in Admin → Webhooks: URL, events, signing secret.

Events
  • checkout.session.completedExternal Checkout API session paid. Subscribe to this for Auxilis-style sales.
  • subscription.createdBuyer subscription became active (or created in demo).
  • subscription.renewedInvoice paid for a subscription (initial or renewal).
  • subscription.canceledSubscription canceled (immediate or after period end).
  • order.createdStorefront order created (not Checkout API sessions).
  • order.fulfilledStorefront order marked fulfilled.
  • order.refundedStorefront order refunded.

Headers

FieldTypeDescription
X-Koza-EventstringEvent name, e.g. checkout.session.completed
X-Koza-Signaturestringsha256=<hmac_hex> of the raw body using your webhook secret
Content-Typestringapplication/json

Verify signature

Node
const crypto = require("crypto");

function verifyKozaSignature(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  // timing-safe compare in production
  return signatureHeader === expected;
}

// Express: use express.raw({ type: "application/json" }) for this route
app.post("/api/koza_webhook", (req, res) => {
  const sig = req.get("X-Koza-Signature") || "";
  if (!verifyKozaSignature(req.body, sig, process.env.KOZA_WEBHOOK_SECRET)) {
    return res.status(401).send("invalid signature");
  }
  const event = JSON.parse(req.body.toString("utf8"));
  // event.event, event.createdAt, event.data
  res.json({ received: true });
});

Payload envelope

checkout.session.completed
{
  "event": "checkout.session.completed",
  "createdAt": "2026-07-14T12:00:00.000Z",
  "data": {
    "id": "cs_…",
    "object": "checkout.session",
    "status": "paid",
    "payment_status": "paid",
    "amount_total": 4900,
    "currency": "usd",
    "customer_email": "buyer@example.com",
    "client_reference_id": null,
    "metadata": { "source": "your-app" },
    "line_items": [
      { "name": "Pro license", "amount_cents": 4900, "quantity": 1 }
    ],
    "payment_ref": "pi_…",
    "success_url": "https://yoursite.com/success?session_id=cs_…"
  }
}

If fulfillment never runs

Payment can succeed on Koza while your app stays empty if the webhook only lists order.*. Add checkout.session.completed, confirm the secret matches, then replay from Admin or scripts/fix-auxilis-webhook.js.

Subscriptions

Sell recurring access with plans and subscriptions. Same secret-key auth as Checkout. Live mode creates a processor subscription and returns a client_secret for the first invoice (Payment Element / koza.js). Demo mode activates immediately.

POST/api/v1/subscriptions/plans

Create a recurring plan.

FieldTypeDescription
namerequiredstringPlan display name
amount_centsrequiredintegerRecurring charge in cents (min 50)
intervalday|week|month|yearDefault month
interval_countintegerDefault 1 (e.g. every 3 months)
trial_daysintegerOptional free trial length
POST/api/v1/subscriptions

Start a subscription for a customer.

FieldTypeDescription
plan_idrequiredstringPlan id (plan_…)
customer_emailrequiredstringBuyer email
customer_namestringOptional display name
metadataobjectString map echoed on webhooks
create plan + subscribe
# Plan
curl -X POST https://www.koza.cc/api/v1/subscriptions/plans \
  -H "Authorization: Bearer koza_sk_…" \
  -H "Content-Type: application/json" \
  -d '{"name":"Pro","amount_cents":999,"interval":"month"}'

# Subscribe
curl -X POST https://www.koza.cc/api/v1/subscriptions \
  -H "Authorization: Bearer koza_sk_…" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":"plan_…","customer_email":"buyer@example.com"}'
# → client_secret (live) or active sub (demo)

Cancel: PATCH /api/v1/subscriptions/:id with { "cancel_at_period_end": true } or { "cancel_immediately": true }.

Merchant webhook events

subscription.created, subscription.renewed (each paid invoice), subscription.canceled. Renewals also credit the store ledger under T+5 settlement.

Errors

Failures return JSON { "error": "…" } with an appropriate HTTP status. Validation issues are usually 400; invalid keys 401; missing sessions 404.

StatusMeaning
400Bad request / validation (Zod path + message)
401Missing or invalid API key / session
402Payment not complete (sync)
403Demo complete blocked when live payments are on
404Session not found for this store
502Upstream payment processor failure

Settlement

When a checkout session is marked paid, Koza writes a store ledger sale (net after platform fee) and holds funds on a T+5 schedule before they become available for payout. Owners manage balances in Admin → Payouts.

White-label

Buyer-facing surfaces say Koza Payments — not the underlying processor. Avoid passing receipt emails that force processor-branded mail when white-labeling.

Next step

Create a store and grab a key

Free to start. Wire checkout, subscribe to webhooks, ship licenses.

API surface documented from the live /api/v1/checkout routes · 2026 Koza