Contents

Dictum SDK

Voice input infrastructure for product interfaces.

Dictum adds WAV speech capture, explicit transcription states, secure model routing, and final transcript insertion to desktop and mobile web products. The SDK is browser-only and headless: your product always owns the UI.

Browser only

Desktop web and mobile web

7 states

One explicit state machine

18 events

Distinct stable names, at most 16 characters

0 provider keys

No speech vendor secrets in the browser

Quickstart

Ship voice input in one integration pass.

Start with a public project key, a server-issued identity token, and one stable source label for the app surface where users will speak.

Install

npm

# Registry publication is prepared but not active yet.
# Once released:
npm install dictum-sdk
  1. 1. Create a Dictum project and copy the public key.
  2. 2. Mint a signed identity from your backend under the global, non-configurable seven-day maximum.
  3. 3. Check browser compatibility, then listen only for provider-confirmed final transcript segments.

Headless SDK

Use this when the voice control must feel native.

The SDK owns recording, state transitions, edge routing, and transcript events. Your app owns placement, styling, editor insertion, and recovery UI.

Client integration

TypeScript

import { checkCompatibility, createSession } from "dictum-sdk";

const compatibility = checkCompatibility();
if (!compatibility.supported) {
  showUnsupportedBrowser(compatibility.missing);
} else {
  const session = createSession({
    projectKey: "dpk_live_xxx",
    identityToken: await getDictumIdentityToken(),
    sourceLabel: "editor-main",
    target: document.querySelector("#message")
  });

  session.on("state_changed", event => renderVoiceState(event.state));
  session.on("transcript_delta", event => renderFinalSegment(event.data.text));
  session.on("sdk_error", event => showVoiceError(event.data));

  startButton.onclick = () => session.start().catch(showVoiceError);
  pauseButton.onclick = () => session.pause().catch(showVoiceError);
  resumeButton.onclick = () => session.resume().catch(showVoiceError);
  stopButton.onclick = () => session.stop().catch(showVoiceError);
  retryButton.onclick = () => session.retry().catch(showVoiceError);

  const result = await session.result;
  renderFinalTranscript(result.text, result.transport);
}
Method
Contract
checkCompatibility()

Reports required browser capabilities without changing state or requesting microphone access.

createSession()

Creates a one-shot session, locks its target, and preloads remote project configuration.

start()

Requests microphone access and resolves only when the session is listening.

pause()

Pauses capture while keeping the session and UI mounted.

resume()

Continues capture on the same session.

stop()

Ends capture and completes transcription on the session transport.

retry()

Explicitly retries a retryable network failure over POST with retained WAV audio.

destroy()

Idempotently releases microphone, transport, listeners, retained audio, and the pending result.

result

Settles once with the final transcript result, or rejects on a terminal failure or destruction.

Browser support

Detect capabilities before showing voice UI.

Compatibility is capability-based, never user-agent based. Unsupported browsers expose the exact missing APIs so the host can disable voice input without requesting the microphone. Non-browser consumers use the Dictum API directly.

Capability preflight

Browser

const report = checkCompatibility();

if (!report.supported) {
  voiceButton.disabled = true;
  showMessage("Please update your browser to use voice input.");
  console.debug({ capture: report.capture, missing: report.missing });
}

Identity

Sign users server-side, then capture in the browser.

Signed identities are scoped to a project and stable customer subject. Their global, non-configurable maximum lifetime is seven days. The browser receives the identity; the signing key stays on your server.

Backend token route

Server

import { createHmac } from "node:crypto";

const MAX_IDENTITY_LIFETIME_SECONDS = 7 * 24 * 60 * 60;
const encodeJson = value => Buffer.from(JSON.stringify(value)).toString("base64url");

function createDictumIdentity({ keyId, signingSecret, projectKey, userId }) {
  const iat = Math.floor(Date.now() / 1000);
  const header = { alg: "HS256", typ: "JWT", kid: keyId };
  const payload = {
    sub: String(userId),
    aud: projectKey,
    iat,
    exp: iat + MAX_IDENTITY_LIFETIME_SECONDS
  };
  const unsignedToken = [encodeJson(header), encodeJson(payload)].join(".");
  const signature = createHmac("sha256", signingSecret)
    .update(unsignedToken)
    .digest("base64url");

  return [unsignedToken, signature].join(".");
}

app.post("/api/dictum/identity", requireUser, (request, response) => {
  const identityToken = createDictumIdentity({
    keyId: process.env.DICTUM_SIGNING_KEY_ID,
    signingSecret: process.env.DICTUM_SIGNING_SECRET,
    projectKey: process.env.DICTUM_PROJECT_KEY,
    userId: request.user.id
  });

  response.json({ identityToken });
});

Project public key

Allowed in the browser. Identifies the project and routing profile.

Signed identity

Generated server-side, with one global non-configurable maximum lifetime of seven days, and binds the customer user to the project.

Signing key

Server-only. Never place this in frontend code, HTML, logs, or analytics payloads.

Provider API keys

Stored in the Dictum dashboard vault or your backend. Never expose them to users.

Events

Render UI from states. Persist from final output.

Every `transcript_delta` segment is provider-confirmed, final, immutable, and append-only. The SDK never exposes interim hypotheses. Usage, duration, and transcription counts are measured by the Worker rather than submitted by the browser.

Insertion helper

DOM

session.on("transcript_delta", event => {
  // Every segment is provider-confirmed, final, immutable and append-only.
  renderFinalSegment(event.data.text);
});

session.on("text_inserted", event => {
  showInsertedState(event.data.insertMode);
});

session.result.then(result => {
  renderFinalTranscript(result.text);
});

Event payloads

state_changed{ previousState, nextState }

A valid state-machine transition completed.

volume_changed{ level, rms?, peak? }

Opt-in local volume feedback while listening.

transcript_delta{ text, transport }

Provider-confirmed final append-only transcript segment.

text_inserted{ text, insertMode }

The SDK inserted final text into the locked target.

mic_deniedpublic error

The browser denied microphone permission.

no_transcript{ reason, error }

No transcript was produced because audio was empty or contained no speech.

network_errorpublic error

A retryable network, timeout, or stream loss occurred.

audio_invalidpublic error

Captured audio violated the WAV contract.

compat_failed{ code, action, details }

Required browser capabilities are unavailable.

limit_reached{ reason, durationMs, maxSeconds, bytes, maxBytes, action }

The Worker reached its streaming audio boundary and forced transcription.

fallback_started{ from, to, reason }

WebSocket recovery actually started over POST.

quota_exceededpublic error

The account or user exhausted its usage quota.

auth_requiredpublic error

A signed customer identity is missing.

identity_expiredpublic error

The signed identity expired; the host must reload it.

auth_invalidpublic error

The signed identity or project authorization was rejected.

retry_started{ transport: "post" }

An explicit user retry started.

sdk_error{ code, message, retryable, userActionRequired, action? }

General safe public error event emitted for every session failure.

State machine

idle

The one-shot session is ready; no microphone capture is active.

requesting_mic

The browser is resolving permission and capture startup.

listening

WAV capture is active.

paused

Capture is paused while the same session and target remain locked.

retrying

An explicit POST retry is running from retained WAV audio.

transcribing

Capture ended and the final transcript is completing.

failed

A typed public failure occurred; retry is offered only when the error says it is retryable.

Errors

Every voice UI needs recovery states.

Treat Dictum errors as product states, not console messages. Keep user text intact, expose retry where safe, and show account or permission actions when retrying cannot fix the issue.

Code
Meaning
Product response
microphone_permission_denied

User or browser denied microphone permission.

Explain browser permission settings, then create a new session after access is granted.

microphone_not_found

No microphone is available to the browser.

Ask the user to connect or select a microphone, then create a new session.

browser_unsupported

The selected capture path needs browser capabilities that are unavailable.

Disable voice input and ask the user to update their browser.

sdk_disabled

Dictum is disabled for this project.

Keep voice input disabled and ask the project owner to enable the SDK.

network_error

The browser could not reach the Dictum edge service.

Offer retry() only while retryable is true.

stream_lost

The active transcription connection was interrupted.

Keep the retained audio and offer the explicit POST retry.

transcription_failed

The provider could not complete the transcription.

Preserve the host input and let the user start a new session.

transport_response_invalid

The transcription transport returned an invalid success response.

Do not retry automatically; report the protocol failure to the service owner.

empty_audio

The completed session contains no usable audio.

Keep the target intact and let the user start a new session.

no_speech_detected

The Worker completed without a transcript.

Keep the target intact and let the user start a new session.

quota_exceeded

The project has reached its current usage limit.

Disable capture and link to billing or usage controls.

unsupported_audio_type

The capture adapter supplied audio outside the WAV contract.

Fix the adapter to emit audio/wav and create a new session.

audio_too_large

The transcription audio payload exceeded the accepted request size.

Keep the target intact and start a shorter dictation.

rate_limited

The service is temporarily rate limited.

Offer retry() only while retryable is true.

timeout

The transcription request stopped making network progress.

Offer retry() only while retryable is true.

aborted_by_user

The user or host stopped the session.

Treat it as a deliberate cancellation and leave the target intact.

client_not_authenticated

The signed customer identity is missing.

Sign the user in, fetch a signed identity, and create a new session.

identity_expired

The signed customer identity has expired.

Reload the page with a freshly signed identity.

config_response_invalid

The project configuration response is incomplete or invalid.

Keep voice input disabled and report the server configuration failure.

session_response_invalid

The session service returned an invalid success response.

Do not retry automatically; report the protocol failure to the service owner.

auth_config_error

The signed identity or its project/signing-key configuration was rejected.

Issue a new identity with the correct kid and aud, then create a new session.

Security

Keep speech vendors and signing material behind your backend.

Browser integrations should identify the project and current user, not carry secret credentials. Provider keys and signing keys belong in controlled server or dashboard storage.

Service surfaces

Dashboard API

https://dictum-dashboard-api.agentcore.workers.dev

Project, sites, models, provider keys, signing keys, account, and usage.

SDK API

https://dictum-sdk-api.agentcore.workers.dev

Browser-facing facade. Its config check confirms that the project is recognized and active so the client page can enable its Dictum integration; WebSocket is always attempted and is not a configurable feature.

Billing API

https://billing-app.agentcore.workers.dev/dictum

Checkout, billing status, and customer portal.

Dashboard account API

/api/dashboard/account

Public dashboard proxy for account usage and quota state; the usage Worker remains private behind a service binding.

AI Readers

Implementation contract for agents.

If an AI agent reads this page to implement Dictum, it should use the browser-only headless SDK for web UI, send non-browser integrations to the API, never expose server-only secrets, and consume only provider-confirmed final transcript segments.

Machine-readable summary

JSON

{
  "product": "Dictum",
  "capability": "headless voice-to-text for desktop and mobile web browsers",
  "browserOnly": true,
  "nonBrowserIntegration": "Use the Dictum API directly",
  "package": "dictum-sdk",
  "packagePublished": false,
  "browserSecrets": [
    "project public key",
    "signed customer identity under the global non-configurable seven-day maximum"
  ],
  "serverOnlySecrets": [
    "Dictum signing key",
    "speech provider API keys"
  ],
  "states": [
    "idle", "requesting_mic", "listening", "paused", "retrying", "transcribing", "failed"
  ],
  "events": [
    "state_changed", "volume_changed", "transcript_delta", "text_inserted",
    "mic_denied", "no_transcript", "network_error", "audio_invalid",
    "compat_failed", "limit_reached", "fallback_started", "quota_exceeded",
    "auth_required", "identity_expired", "auth_invalid", "retry_started", "sdk_error"
  ],
  "transport": "WebSocket first; explicit bounded recovery to POST",
  "transcriptRule": "Every transcript_delta segment is provider-confirmed, final, immutable, and append-only.",
  "usageRule": "Usage is measured by the Worker, never submitted by the browser SDK.",
  "privacyRule": "Never log raw audio, transcript text, signed identity, or provider secrets."
}

Checklist

Production readiness before launch.

1

Create a project and copy the public project key.

2

Create a server-side signing key for identity tokens.

3

Add one source label per website, app surface, or workflow.

4

Choose provider/model routing and save provider keys in the vault.

5

Use the authorized SDK bundle until the prepared npm release is activated.

6

Run checkCompatibility() before enabling the voice control.

7

Handle state_changed, transcript_delta, sdk_error, and relevant dedicated events.

8

Verify insertion behavior in every target input, textarea, and editor.

9

Offer retry() only for retryable network failures and destroy the session on unmount.

10

Monitor Worker-owned usage and error codes from the dashboard.

Dashboard

Or use your email