Engine API reference

Last updated  Aug 4, 2026

Everything the SDKs do, you can do over HTTPS — run a turn, execute a confirmed action, synthesize speech, or hold a live voice socket open.

Every endpoint returns the same thing conceptually: a render spec. That is a speak string for the user to hear, an optional widgets array for the client to draw, and optional suggestions or follow-up copy. Clients render the spec; they never decide what goes in it.

Headers & auth

There is no single key that grants data access. Two headers do different jobs: X-Voqal-Key says which assistant to be, and X-Token says who is asking. Both travel on every request.

Terminal
curl https://your-engine.example.com/voqal \  -H "X-Voqal-Key: pk_live_…" \        # which assistant  -H "X-Token: <user backend token>" \  # who is asking  -H "X-Request-ID: prod-84213" \     # prod- or stg-  -H "X-Client-Metadata: {\"country_code\":\"EGY\"}" \  -H "Content-Type: application/json" \  -d '{"transcript":"what is my balance","mode":"text"}'

Request headers

HeaderRequiredPurpose
X-Voqal-KeyRequiredYour publishable key. Resolves the tenant — prompt, tools, theme. Unknown keys are rejected with 401.
X-TokenRequiredThe end user's token for your own backend. The engine forwards it to your tools; it does not store it.
X-Request-IDRequiredRoutes by prefix and correlates logs across a turn: prod- reaches production, stg- reaches staging.
X-Client-MetadataOptionalJSON client context — country code, user id, anything your prompt or tools need.
Sessions can be bound to a device key. When a client posts its public key to /api/v1/create-session, the engine mints a session token bound to that key and expects later requests to be signed with it. A 401 means the client should re-bootstrap the session and retry once — the SDKs already do this silently.

Create a session

POST/api/v1/create-session

Bootstraps a conversation and, in the background, opens the connection to your tools and primes the model's prompt cache. Call it at app launch so the first real turn is not a cold one.

Parameters

ParameterTypeRequiredDescription
public_keyobjectOptionalThe device's ES256 public key as a JWK. Supplying it mints a key-bound session token.
metadataobjectOptionalClient context stored with the session.

Response

201 Created
{  "session_id": "6f2a1c84-3b70-4e51-9d2f-0a71c4e5b810",  "created_at": "2026-08-01T09:24:07Z",  "session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"}

Run a turn

POST/voqal

One conversational turn. The reply streams back as server-sent events — speak deltas first so audio can start, then the widgets, then done. Assembled, it is a render spec.

Parameters

ParameterTypeRequiredDescription
transcriptstringOptionalTyped text, or the final STT result.
audio_base64stringOptional16 kHz mono WAV, when you want the engine to transcribe.
mode"voice" | "text" | "home"OptionalDefaults to text. home is the silent opening glance, with no user input.
messagesarrayOptionalPrior turns, oldest first.
contextobjectOptionalsessionId, screen, country_code, device info.
metaobjectOptionalsdkVersion, platform, locale (BCP-47).

Response

200 OK · assembled from text/event-stream
{  "speak": "Your settleable balance is 42,150 EGP.",  "widgets": [    {      "type": "stat",      "label": "Settleable",      "value": "42,150 EGP",      "delta": "+8.2%"    },    {      "type": "list",      "title": "Recent",      "items": [        {          "title": "Card payment",          "subtitle": "Today",          "trailing": "1,200 EGP"        }      ]    }  ],  "follow": "Want me to settle it now?",  "meta": {    "conversationId": "conv_7Zp3Kd10",    "direction": "ltr"  }}

Execute an action

POST/voqal/execute

Runs an action the user has just confirmed. Only allow-listed action tools are runnable here, and the body carries the client's proof that the device gate passed. The reply is a terminal card, not a conversation.

Parameters

ParameterTypeRequiredDescription
executeobjectRequiredThe tool and arguments carried by the confirm widget.
authobjectRequiredmethod (faceid, touchid, passcode) and verifiedAt.
contextobjectOptionalsessionId and locale for the reply.

Response

200 OK
{  "done": {    "type": "success",    "title": "Settlement requested",    "line1": "42,150 EGP",    "line2": "Arrives within one business day"  },  "speak": "Done — your settlement is on its way."}

Synthesize speech

POST/voqal/tts

Turns a line of text into audio using the tenant's configured voice. It replies with WAV bytes rather than JSON, so the sample below shows the request body.

Parameters

ParameterTypeRequiredDescription
textstringRequiredThe line to speak.
voicestringOptionalOverrides the tenant's default voice.

Response

Request body · replies with audio/wav
{  "text": "Your settleable balance is 42,150 EGP.",  "voice": "default"}

Live voice socket

WS/voqal/stream

The whole voice loop over one socket: microphone frames go up, the engine transcribes on end of speech, runs the turn, and sends the answer and its audio back down. Messages are JSON envelopes with a type.

Parameters

ParameterTypeRequiredDescription
typestringRequiredaudio, end_of_speech, or cancel.
chunkstringOptionalBase64 PCM frame, on audio messages.
contextobjectOptionalSent once, on the opening message.

Response

Server → client message
{  "type": "spec",  "spec": {    "speak": "You have three payouts pending.",    "widgets": [      {        "type": "progress",        "label": "Payouts cleared",        "value": 0.62      }    ]  }}
© 2026 VoqalVoqal SDK & engine documentation