Bridge by Wekoya / Docs / Get started
Browser and mobile apps
Updated
Your API key must stay on your server. To let a web page or a phone app call Bridge directly (for chat, voice or pictures without a round trip through your server), give it a guest key: a key your server makes for one user, that lasts minutes, can only do what you allow, and stops at the amount you set.
- Your app asks your server Your signed-in user's app asks your own backend for a key.
- Your server asks Bridge With your real key, it calls POST /v1/guest-keys.
- Bridge returns a guest key Short-lived, limited to what you allowed, capped in naira.
- The app calls Bridge Directly, with the guest key, like any API key.
Make a guest key
On your server, with your API key:
curl https://wekoya-api.wekoya.tech/v1/guest-keys \
-H "Authorization: Bearer $WEKOYA_API_KEY" -H "Content-Type: application/json" \
-d '{
"expires_in": 900,
"max_spend": 50,
"uses": ["chat", "speech"],
"end_user": "user_123",
"origins": ["https://app.example.com"]
}'{
"object": "guest_key",
"id": "8f1c2d7e-…",
"key": "wk_guest_…",
"expires_at": "2026-10-10T12:15:00.000Z",
"max_spend": 50,
"currency": "NGN",
"uses": ["chat", "speech"],
"end_user": "user_123",
"origins": ["https://app.example.com"]
}The guest key is shown once. Give it to the app; don't store it. When it runs out or expires, the app asks your server for a new one.
Use it in the app
A route on your server hands keys to your signed-in users:
// On your server: a route your signed-in users call to get a guest key.
app.post("/api/bridge-key", requireSignedIn, async (req, res) => {
const response = await fetch("https://wekoya-api.wekoya.tech/v1/guest-keys", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WEKOYA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ expires_in: 900, max_spend: 50, uses: ["chat"], end_user: req.user.id }),
})
const guest = await response.json()
if (!response.ok) return res.status(502).json({ error: guest.error?.message ?? "Could not get a key" })
res.json({ key: guest.key, expires_at: guest.expires_at })
})The app then uses the guest key exactly like an API key:
// In the browser: use the guest key like an API key.
import OpenAI from "openai"
const { key } = await fetch("/api/bridge-key", { method: "POST" }).then((r) => r.json())
const client = new OpenAI({
baseURL: "https://wekoya-api.wekoya.tech/v1",
apiKey: key,
dangerouslyAllowBrowser: true, // safe here: the key is short-lived and limited
})
const reply = await client.chat.completions.create({
model: "gemini-3.8-flash",
messages: [{ role: "user", content: "Suggest a name for my bakery" }],
})For live audio, a browser WebSocket cannot send a key, so the app gets a one-time ticket first (allow live in uses):
// Live audio from a browser. A WebSocket cannot send headers, so get a one-time ticket first.
const ticket = await fetch("https://wekoya-api.wekoya.tech/v1/audio/live/tickets", {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({ model: "nova-3" }),
}).then((r) => r.json())
const socket = new WebSocket(ticket.url) // the ticket works once, within a minuteWhat you can set
max_spend(required): the most it can spend, in your account's currency. Then it stops withkey_limit_exceeded.expires_in: seconds it lasts, from 60 to 86,400 (a day). Default 900 (15 minutes).uses: what it may call:chat,speech,transcription,live,realtime,images,embeddings,decisions,music,search,videos. Defaultchat. Everything else (keys, billing, batches, pipelines) is refused.models: which models, written like a key's model list. Never wider than the key that makes it.end_user: spend from one of your end users' budgets. The app cannot choose a different one.origins: only from these websites, such ashttps://app.example.com. Leave it out for phone apps, which send no origin.max_requests: stop after this many requests.label: a name you will recognise.
Stopping one early
When a user signs out, revoke their key. Revoking the API key that made guest keys stops all of them, and stops any live audio they started.
curl -X POST https://wekoya-api.wekoya.tech/v1/guest-keys/$GUEST_KEY_ID/revoke \
-H "Authorization: Bearer $WEKOYA_API_KEY"Make guest keys with a key that has no spending limit of its own (each guest key has its own cap), and keep that key on your server. GET /v1/guest-keys lists the ones still working, with what each has spent.