Integrate directly over HTTP and WebSocket, without installing any SDK.
Every SDK on this platform — Unity, the Web SDK, Godot, Unreal — is a thin client over the same REST + WebSocket contract. If your engine or language isn't one of those, or you just don't want a dependency, everything below is enough to build your own client directly.
Authentication
Send your project API key on every request, as a header:
Header
X-Mist-Key: ms_<secret>.<projectId>.<userId>
Create a key from Project Settings → API Keys in the dashboard. The project scope for every request is resolved server-side from the key itself — you never pass a project id separately.
REST base URL
Base URL
https://api.mistscale.com
A dedicated API host, separate from the dashboard site. Every path below is prefixed /v1.
REST endpoints
GET /v1/npcs
Every NPC in the project the key resolves to. No path/query parameter for project id needed.
POST /v1/auth/verify-key
Cheap validity check for a key. Plain-text response body: "verified" or "invalid or revoked key".
That's the whole public REST surface
NPC authoring, knowledge upload, and world knowledge are studio/dashboard operations behind a separate session-based auth mode, not part of the public API-key contract described here.
WebSocket: connecting
One socket per NPC. Everything — chat, voice, spatial context — runs over this single connection:
source=game can be omitted entirely — it's inferred once token looks like an ms_ key. instance_id is required but not validated against anything pre-registered — any client-generated id works. There is no message-level auth: everything is verified once, before the socket upgrade completes.
Client → server messages
chat
{ id, sender_id, message, instance_id } — sends a player message.
voice / audio
{ data (base64), end, sender_id } — streams captured audio chunks. end: true on the final chunk.
spatial_context
{ npc_id, instance_id, location, time_of_day?, weather? } — location is the only required field. No ack.
get_evolution_status / get_quota_status
No body beyond type — requests a one-off status frame back.
heartbeat
No-op, no reply. Send periodically to keep proxies/load balancers from seeing silence — the server has no idle timeout on its own.
Server → client messages
chat_ack
{ id, status: "received" } — sent immediately when a chat message is received, before generation starts.
chat_chunk
{ chat_id, content } — one streamed token. Append it.
chat_revision
{ chat_id, content } — the reply was corrected after generation (grounding). Replace the accumulated text, don't append.
chat_metadata
{ chat_id, metadata } — the turn is settled. metadata carries emotion, evolution pressure, and (dashboard-only) internal reasoning.
transcript
{ user_message } — a voice message finished transcribing.
chat_blocked
{ chat_type, reason, limit, used } — usage quota exceeded, no reply generated. The only structured error frame in the protocol.
quota_status
{ text: {...}, voice: {...} } — reply to get_quota_status.
binary frames
Raw synthesized speech, no JSON envelope, one frame per sentence (voice replies only).
The streaming contract
This is the one rule every SDK on this platform implements, and the one thing your own client needs to replicate exactly: append chat_chunk deltas to build the visible text; if chat_revision arrives, replace the accumulated text outright, don't append; chat_metadata marks the turn settled. Voice doesn't stream token-by-token — grounding runs before anything is sent, so a voice reply arrives as one complete chat_chunk.
No server-side reconnection
Every WebSocket connection is independent — there is no session to resume. If the socket drops mid-reply, that generation is lost; reconnect and send a new message. Chat history persists server-side (keyed by NPC and player id, not by socket), so a fresh connection still has full context on the next turn. Implement your own reconnect-with-backoff on an unexpected close.
Full reference
This page covers what you need to build a working client. For the complete field-by-field reference (error response shapes, CORS, rate limiting, every edge case) see the raw API docs in the mistscale-sdk repository — the same source every SDK on this platform is built against.