Skip to main content
This tutorial walks the full stack of a user-facing AI chat product on qlaud. By the end you’ll have a chat backend with:
  • Per-end-user conversations — each of your users has their own thread
  • Tool integration — the assistant calls your business logic (lookups, actions) via webhooks; qlaud handles the dispatch loop
  • Semantic search — your end-user can search their own conversation history; you don’t run a vector DB
  • Streaming UX — text appears word-by-word, like every modern chat
  • Per-user billing — hard spend caps; you bill how you want at month-end
What you DON’T build: Postgres tables, message store, context-window loader, tool-call state machine, embedding pipeline, vector store, conversation search, per-user cost attribution. Estimated time end-to-end: ~30 minutes, mostly waiting on pip install / npm install.

Prerequisites

  • A qlaud account (sign up free, $5 starter credit)
  • Your master key from /keys, exported as QLAUD_MASTER_KEY
  • Python 3.9+ (using plain requests) or Node 18+ (using built-in fetch). No qlaud SDK required for any of this.

Architecture in one paragraph

Each of your end-users gets:
  1. A qlaud per-user API key (qlk_live_…) with a hard spend cap, minted on signup using your master key.
  2. A qlaud thread tagged with their end_user_id.
That’s it. Their messages go to qlaud; qlaud calls the model, optionally fires tools, persists everything, exposes search, and meters cost — all keyed off their thread + their per-user key. Your backend only orchestrates.

Step 1 — On signup, mint a per-user key + thread

Whenever a new user signs up in your app, run this once:
You now have one place per user that holds their entire AI footprint. That’s all the per-user state you need to track on your side.

Step 2 — Send a message in a conversation

Once you have a user’s qlaud_secret and qlaud_thread_id, sending a turn is one call. qlaud loads the prior history server-side; you only send the new user content:
That’s a complete chat backend. No message store, no context loader, no “how do I keep history under N tokens” code. qlaud caps at the last 50 turns automatically and you never see the upstream messages array.

Step 3 — Stream the response (token-by-token UX)

For a real chat UI you want text to appear word-by-word. Add stream: true and read the SSE stream:
Frontend: pipe each yielded chunk straight into your UI. After the stream closes, qlaud has already persisted the full assistant turn for you.

Step 4 — Add a tool

Let’s give the assistant the ability to look up user account info. Two parts: register the tool with qlaud, then host the webhook.

Register the tool (one-time)

Host the webhook (your backend)

Use the tool in a conversation

What happens when the user asks “what plan am I on?” and you pass tool_ids=[lookup_account_id]:
  1. qlaud sends the question + tool definition to Claude
  2. Claude emits a tool_use block: lookup_account({email: "user@example.com"})
  3. qlaud POSTs to your webhook with the input
  4. Your handler queries your DB and returns {output: {plan: "pro", ...}}
  5. qlaud appends a tool_result to the conversation
  6. Claude reads the tool result and responds: “You’re on the Pro plan…”
  7. You get the final text response
You wrote ~20 lines (one webhook handler). qlaud orchestrated the rest — including signature verification, retries on transient failures, parallel dispatch when multiple tools fire at once, and persistence of the entire dance for audit.

Step 5 — Search the user’s history

Your end-user wants to find a past conversation: “What did we discuss about refunds last week?” No vector DB to provision; semantic search is already indexed:
end_user_id filter scopes results to ONE of your end-users — they only see their own past conversations, never any other customer’s. The underlying Vectorize index handles that filter at the metadata layer.

Step 6 — Bill at month-end

End of month, pull per-key usage and invoice however you want (Stripe, Paddle, in-app credits, custom):
cost_micros is what qlaud charged YOU (upstream cost × 1.07 markup). Whatever margin you put on top of that is yours.

What you didn’t build

Roughly 300–500 lines of glue per AI app, deleted.

Next steps

  • Switch models per turn — change model: to gpt-5.4 mid-conversation; history persists, qlaud translates the shape.
  • Use /v1/jobs for long-running batch work that shouldn’t block your request thread.
  • Parallel tool calls happen automatically — when the assistant emits multiple tool_use blocks, qlaud fans out via Promise.all. No code change needed.
  • Per-user spend caps are already enforced gateway-side. Once a user hits their max_spend_usd cap, the next request returns 402 before the upstream model is ever called.
Need help wiring this into an existing codebase? Email hello@qlaud.ai.