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
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:
https://www.koza.ccAuthentication
Authenticate server-side requests with a store secret key. Create keys in Admin → API keys. Keys look like koza_sk_….
Authorization: Bearer koza_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeep secrets server-side
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
/api/v1/checkout/sessionsCreates a checkout session. Auth required. Accepts snake_case or camelCase.
| Field | Type | Description |
|---|---|---|
line_itemsrequired | array | At least one item: name, amount_cents, quantity (default 1). |
success_urlrequired | string (url) | Redirect after success. Supports {CHECKOUT_SESSION_ID}. |
cancel_urlrequired | string (url) | Redirect if the buyer abandons. |
ui_mode | "hosted" | "embedded" | Default hosted. Use embedded for on-site forms. |
customer_email | string | Prefills email when present. |
currency | string (3) | ISO currency; defaults to the store currency. |
client_reference_id | string | Your internal order / cart id. |
metadata | object | String key/values echoed on the session and webhook. |
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):
{
"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
/api/v1/checkout/sessions/:idFetch a session for your store (verify payment_status after redirect). Auth required.
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.
- Server creates session (secret key never leaves your backend).
- Browser mounts the payment form with koza.js.
- 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_…).
// 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
/api/v1/checkout/sessions/:id/syncAfter 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 -X POST https://www.koza.cc/api/v1/checkout/sessions/cs_…/syncDemo / local only:
/api/v1/checkout/sessions/:id/completeMarks 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 src="https://www.koza.cc/koza.js"></script>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 …/syncKoza.redirectToCheckout({ url: session.url });
// optional: { url, mode: "popup" }Webhooks
Configure endpoints in Admin → Webhooks: URL, events, signing secret.
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
| Field | Type | Description |
|---|---|---|
X-Koza-Event | string | Event name, e.g. checkout.session.completed |
X-Koza-Signature | string | sha256=<hmac_hex> of the raw body using your webhook secret |
Content-Type | string | application/json |
Verify signature
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
{
"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
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.
/api/v1/subscriptions/plansCreate a recurring plan.
| Field | Type | Description |
|---|---|---|
namerequired | string | Plan display name |
amount_centsrequired | integer | Recurring charge in cents (min 50) |
interval | day|week|month|year | Default month |
interval_count | integer | Default 1 (e.g. every 3 months) |
trial_days | integer | Optional free trial length |
/api/v1/subscriptionsStart a subscription for a customer.
| Field | Type | Description |
|---|---|---|
plan_idrequired | string | Plan id (plan_…) |
customer_emailrequired | string | Buyer email |
customer_name | string | Optional display name |
metadata | object | String map echoed on webhooks |
# 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.
| Status | Meaning |
|---|---|
| 400 | Bad request / validation (Zod path + message) |
| 401 | Missing or invalid API key / session |
| 402 | Payment not complete (sync) |
| 403 | Demo complete blocked when live payments are on |
| 404 | Session not found for this store |
| 502 | Upstream 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

