Quickstart
Get an API key and stream your first answer from the gateway.
This page takes you from nothing to a streamed answer in a few minutes. The examples use Node.js, but the gateway speaks JSON over a standard WebSocket, so any language with a WebSocket client works.
Create and export an API key
Create a key at vaktex.com/app. Keys start with vk-live-. The full key is shown once, so copy it now. Each licence has one live key, and rotating it revokes the old one.
Export the key as an environment variable so your code can read it:
export VAKTEX_KEY="vk-live-..." Keep the key on your server. Do not put it in a URL or in code that ships to browsers.
Install a WebSocket client
npm install ws Make your first request
Save this helper as gateway.js. The other guides reuse it. It opens a connection, sends one turn and collects the result.
import WebSocket from 'ws';
export async function connect(key = process.env.VAKTEX_KEY) {
const ws = new WebSocket('wss://gateway.vaktex.com/vaktex/v1/stream', {
headers: { Authorization: `Bearer ${key}` }
});
// The first message is session.ready. A bad key rejects the upgrade instead.
await new Promise((resolve, reject) => {
ws.once('message', resolve);
ws.once('error', reject);
ws.once('unexpected-response', (_req, res) => reject(new Error(`HTTP ${res.statusCode}`)));
});
function turn(request, { onText } = {}) {
return new Promise((resolve, reject) => {
const result = { text: '', toolCalls: [], errors: [], complete: null };
const onMessage = (data) => {
const event = JSON.parse(data.toString());
if (event.type === 'block.delta' && event.delta.kind === 'text') {
result.text += event.delta.text;
onText?.(event.delta.text);
} else if (event.type === 'tool_call') {
result.toolCalls.push(event);
} else if (event.type === 'error') {
result.errors.push(event);
} else if (event.type === 'turn.complete') {
ws.off('message', onMessage);
result.complete = event;
resolve(result);
}
};
ws.on('message', onMessage);
ws.once('error', reject);
ws.send(JSON.stringify({ type: 'start', request }));
});
}
return { turn, close: () => ws.close() };
} Now create example.js:
import { connect } from './gateway.js';
const gateway = await connect();
const result = await gateway.turn(
{
provider: 'auto',
model: 'auto',
messages: [
{
role: 'user',
content: [{ type: 'text', text: 'Write a one-sentence bedtime story about a unicorn.' }]
}
]
},
{ onText: (piece) => process.stdout.write(piece) }
);
console.log(`\n\nStopped: ${result.complete.stop_reason}`);
console.log(`Tokens: ${result.complete.usage.input_tokens} in, ${result.complete.usage.output_tokens} out`);
gateway.close(); Run it:
node example.js The story prints as it is written, followed by why the turn stopped and how many tokens it used.
What just happened
- You opened a WebSocket and the gateway checked your key. It replied with
session.ready. - You sent a
startframe with a request. Settingproviderandmodeltoautolet the gateway choose a model that can handle it. - The gateway streamed
block.deltaevents as the model wrote. The helper printed the text of each one. - The gateway sent
turn.completewith the stop reason and final usage. A new turn can start now.
To pin a specific model instead, set both fields, for example provider: "anthropic" and model: "claude-sonnet-5-5". Read the live list from the model catalog.
Not using Node?
The protocol is plain JSON frames, so you can use any WebSocket library. Here is the same request in Python with the websockets package:
import asyncio, json, os
import websockets
async def main():
headers = {"Authorization": f"Bearer {os.environ['VAKTEX_KEY']}"}
async with websockets.connect(
"wss://gateway.vaktex.com/vaktex/v1/stream", additional_headers=headers
) as ws:
await ws.recv() # session.ready
await ws.send(json.dumps({
"type": "start",
"request": {
"provider": "auto",
"model": "auto",
"messages": [{"role": "user", "content": [{"type": "text", "text": "Hello!"}]}],
},
}))
async for raw in ws:
event = json.loads(raw)
if event["type"] == "block.delta" and event["delta"]["kind"] == "text":
print(event["delta"]["text"], end="", flush=True)
elif event["type"] == "turn.complete":
break
asyncio.run(main()) Browsers cannot set headers on a WebSocket. They pass the key as a subprotocol instead: new WebSocket(url, ['vaktex.v1', 'vaktex.auth.' + key]). Only do this for keys you are willing to expose to that user.
Next steps
- Text inputs and outputs: roles, parameters and models.
- Conversation state: continue a conversation across turns.
- Function calling: let a model call your code.
- Errors and handling: know what to do when something fails.