Skip to main content
This guide walks through the headline qlaud workflow — minting a qlk_live_… key per end-user of your app, enforcing a per-user spending cap, and generating invoices from per-key usage.

Mental model

Stripe patternqlaud equivalent
CustomerA qlk_live_… key with name: "user_<id>"
Subscription / metered usagePer-key usage_events we record on every API call
Spending limitmax_spend_usd enforced on the key
Webhook on overage(coming soon) cap_exceeded webhook
InvoiceGET /v1/usage → fold into Stripe InvoiceItem.create()
You hold one master key (scope: 'admin') that lets you mint and revoke per-user keys. Every other key is scope: 'standard' and can only be used for inference.

Architecture

                                                   ┌── /v1/messages ─→ Claude
your user ──HTTP──→ your backend ──qlk_live_user_42──→ qlaud ──┼── /v1/audio/* ─→ OpenAI
                                                   └── /v1/videos ──→ Sora 2

           Master key holder (you)

        POST /v1/keys ──── mint per-user keys
        GET  /v1/usage ─── pull per-user spend
        DEL  /v1/keys/:id  revoke when user churns

Step 1 — Mint your master key

In the dashboard, create a key with scope Master (admin). Store it as QLAUD_MASTER_KEY in your backend’s secret manager. Never expose this key to clients — it can mint other keys.

Step 2 — Mint a per-user key on signup

When a user signs up to your app, mint a qlaud key for them with their monthly cap.
// pages/api/signup.ts (or wherever you handle signup)
async function onUserSignup(user: { id: string; email: string }) {
  const r = await fetch('https://api.qlaud.ai/v1/keys', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.QLAUD_MASTER_KEY!,
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      name: `user_${user.id}`,        // we surface this in /v1/usage
      max_spend_usd: 5,                // hard cap; gateway-enforced
    }),
  });
  const { id, secret } = await r.json();

  // Store with the user — `secret` is shown ONCE; we only keep a hash.
  await db.users.update(user.id, {
    qlaud_key_id: id,
    qlaud_key_secret: secret,
  });
}
The secret is returned once at creation time. Save it immediately — we only store its SHA-256 hash. If you lose it, you must revoke the key and mint a new one.

Step 3 — Use the per-user key for inference

In your app’s request flow, swap the master key for the user’s key when calling qlaud. The cap is enforced gateway-side — you don’t need any extra logic.
// When user_42 calls your /chat endpoint:
const userKey = await db.users.findById(user.id).qlaud_key_secret;

const r = await fetch('https://api.qlaud.ai/v1/messages', {
  method: 'POST',
  headers: {
    'x-api-key': userKey,
    'anthropic-version': '2023-06-01',
    'content-type': 'application/json',
  },
  body: JSON.stringify({
    model: 'claude-sonnet-4-6',
    max_tokens: 1000,
    messages,
  }),
});

// If user_42 has hit their $5 cap, qlaud returns 402 with:
// {"error":{"type":"authentication_error",
//           "message":"this API key has reached its spending cap..."}}

Step 4 — Bill at month-end

Pull per-user spend from qlaud and create Stripe invoice items.
import os, requests, stripe
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]

usage = requests.get(
    "https://api.qlaud.ai/v1/usage",
    headers={"x-api-key": os.environ["QLAUD_MASTER_KEY"]},
).json()

for k in usage["by_key"]:
    user = db.users.find_by_qlaud_key_id(k["key_id"])
    if k["cost_micros"] == 0 or not user.stripe_customer_id:
        continue

    stripe.InvoiceItem.create(
        customer=user.stripe_customer_id,
        amount=int(k["cost_micros"] / 100),    # micro-dollars → cents
        currency="usd",
        description=f"AI usage — {k['request_count']} requests",
    )

Optional — date-range billing

/v1/usage defaults to month-to-date. Pass from_ms and to_ms (UTC milliseconds) to scope to any window:
# Last 30 days
NOW=$(date +%s)000
THEN=$(( NOW - 30 * 86400 * 1000 ))
curl "https://api.qlaud.ai/v1/usage?from_ms=$THEN&to_ms=$NOW" \
  -H "x-api-key: $QLAUD_MASTER_KEY"

Optional — drill down to one user

curl "https://api.qlaud.ai/v1/keys/<key_id>/usage" \
  -H "x-api-key: $QLAUD_MASTER_KEY"

# Returns: { total_cost_micros, max_spend_micros, events: [...] }
# events = last 100 requests with model, status, latency_ms, cost

Revoking a key

When a user churns or you need to roll a key:
curl -X DELETE https://api.qlaud.ai/v1/keys/<key_id> \
  -H "x-api-key: $QLAUD_MASTER_KEY"
Revocation propagates to our cache immediately — the key stops working on the next request, no waiting for TTL.

What you didn’t have to build

  • Per-user usage tracking → usage_events table on our side
  • Per-user spending caps → max_spend_micros column, KV-cached check
  • Failed-payment handling for AI usage → 402 from qlaud, propagate to user
  • Per-provider billing reconciliation → one wallet, one invoice from us
  • Storing customer-facing AI prices → catalog already includes our 7% markup

Coming soon

  • Webhookscap_exceeded, low_balance, key_revoked. POST to your URL on event.
  • Per-key rechargePOST /v1/keys/:id/credit to add credit on a single user-key without touching your master wallet (for “user paid you, push credit to their key” flows).
  • @qlaud/sdk — Stripe-SDK-shaped Node + Python clients with qlaud.keys.create(), qlaud.usage.list(), etc.