Preview Documentation — This documentation is tentative and subject to change. Packages and endpoints are not yet live.

Interpreter SDK

Embed real-time interpretation into your web application. Drop in our pre-built UI or build your own with headless mode.

Preview Documentation: This documentation is tentative and subject to change. The SDK packages are not yet published to npm, and the API endpoints are not yet live. This preview is provided to help you plan your integration.


Why vitalvoice.ai

Built for critical communication where misunderstanding isn't an option:

  • Domain-trained accuracy: Optimized for healthcare, law enforcement, and legal terminology
  • HIPAA compliant: BAA available, no audio retention, end-to-end encryption
  • Sub-second latency: Real-time interpretation for emergency response
  • 57 languages: Spanish, Mandarin, Arabic, Vietnamese, Tagalog, and more - with specialized vocabulary support

Whether you're building a telehealth platform, an e-citation, court management solution, or EMS dispatch app, vitalvoice.ai handles the interpretation so you can focus on your product.


Quick Start

Note: The following packages and endpoints are tentative and not yet available. This section demonstrates the planned integration flow.

1. Install the SDK

bash
npm install @vitalvoice/interpreter

2. Get a Session Token (Server-Side)

Your backend requests a short-lived token using your API key:

bash
curl -X POST https://api.vitalvoice.ai/v1/sessions \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "targetLanguages": ["es", "fr", "de"],
    "maxDurationSeconds": 300
  }'

Response:

json
{
  "sessionToken": "sess_ephemeral_abc123...",
  "expiresAt": "2025-01-15T12:05:00Z",
  "sessionId": "sess_def456"
}

Important: Never expose your API key (sk_live_...) in client-side code. Always request session tokens from your backend.

3. Initialize the Interpreter (Client-Side)

js
import { Interpreter } from '@vitalvoice/interpreter';
 
// Fetch token from your backend
const { sessionToken } = await fetch('/api/interpret-session', {
  method: 'POST',
  credentials: 'include'
}).then(r => r.json());
 
// Initialize interpreter
const interpreter = Interpreter.create({
  sessionToken,
  container: document.querySelector('.interpreter-container'),
  mode: 'standard'
});
 
await interpreter.connect();

That's it. The interpreter renders a microphone button in your container and displays interpretations in a popover.


Compliance

HIPAA

vitalvoice.ai is HIPAA compliant. We offer Business Associate Agreements (BAAs) to all partners.

What we handle:

  • Encrypted transmission of all audio and text
  • Zero retention of protected health information (PHI)
  • SOC 2 Type II certified infrastructure
  • Annual third-party security audits

Your responsibilities:

  • Authenticate users before issuing session tokens
  • Implement appropriate access controls in your application
  • Maintain audit logs using session IDs and metadata

Contact your account manager to execute a BAA before processing PHI.

Data Handling

Data TypeRetentionNotes
Audio streamsNoneProcessed in real-time, never stored
TranscriptsNoneDelivered to your app, not retained
Session metadata90 daysSession IDs, timestamps, language pairs
Usage metrics1 yearAggregated billing data only

Authentication

Note: Authentication endpoints and flows described here are tentative. Final implementation may differ.

How It Works

┌─────────────────┐         ┌─────────────────┐         ┌─────────────────┐
│  User's Browser │         │   Your Backend  │         │  Interpreter API│
└────────┬────────┘         └────────┬────────┘         └────────┬────────┘
         │                           │                           │
         │  1. Request session       │                           │
         │  ─────────────────────>   │                           │
         │                           │                           │
         │                           │  2. POST /v1/sessions     │
         │                           │     Authorization: sk_... │
         │                           │  ─────────────────────>   │
         │                           │                           │
         │                           │  3. { sessionToken, ... } │
         │                           │  <─────────────────────   │
         │                           │                           │
         │  4. Return token          │                           │
         │  <─────────────────────   │                           │
         │                           │                           │
         │  5. Interpreter connects  │                           │
         │  ─────────────────────────────────────────────────>   │
         │                           │                           │

Session Token Properties

  • Short-lived: Tokens expire in 5 minutes if unused
  • Single-use: One token, one session
  • Scoped: Inherits rate limits and quotas from your API key
  • Secure: Cannot be used to create additional tokens or access other endpoints

Backend Implementation Example

curl -X POST https://api.vitalvoice.ai/v1/sessions \
-H "Authorization: Bearer $VITALVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "targetLanguages": ["es", "fr"],
  "maxDurationSeconds": 300,
  "metadata": {
    "userId": "user_123",
    "facility": "memorial_hospital"
  }
}'

Session Options

ParameterTypeRequiredDescription
targetLanguagesstring[]YesLanguages to interpret into (ISO 639-1 codes)
maxDurationSecondsnumberNoSession time limit (default: 600, max: 1800)
metadataobjectNoArbitrary data for your records (returned in webhooks)

Standard Mode

Standard mode provides a complete, pre-built UI. You provide a container element; we handle everything else.

Note: UI components and theming options are tentative and may change before release.

Basic Setup

js
const interpreter = Interpreter.create({
  sessionToken,
  container: document.querySelector('.interpreter-container'),
  mode: 'standard',
  targetLanguages: ['es', 'fr', 'de']
});
 
await interpreter.connect();

What Gets Rendered

Controls (in your container):

  • Microphone button with active/inactive states
  • Language selector
  • Mute toggle

Transcript popover (appended to <body>):

  • Real-time transcript display
  • Collapse/expand toggle
  • Positioned in viewport corner

Configuration Options

js
Interpreter.create({
  // Required
  sessionToken: string,
  container: HTMLElement,
  mode: 'standard',
 
  // Language settings
  sourceLanguage: string,        // Auto-detect if omitted
  targetLanguages: string[],     // Required
 
  // Appearance
  theme: 'light' | 'dark' | ThemeConfig,
 
  // Transcript popover
  transcript: {
    position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left',
    defaultExpanded: boolean,    // Default: true
  }
});

Custom Theming

js
Interpreter.create({
  // ...
  theme: {
    primaryColor: '#6366f1',
    backgroundColor: '#ffffff',
    textColor: '#1f2937',
    borderRadius: '8px',
    fontFamily: 'Inter, system-ui, sans-serif'
  }
});

Headless Mode

Headless mode gives you full control over the UI. The SDK manages connections and audio capture - you render everything.

Note: The headless API is tentative and subject to change.

Basic Setup

js
const interpreter = Interpreter.create({
  sessionToken,
  container: document.querySelector('.hidden-container'),
  mode: 'headless',
  targetLanguages: ['es', 'fr']
});
 
// Listen for events
interpreter.on('interpretation', ({ original, interpreted, targetLanguage, isFinal }) => {
  // Render in your UI
  updateTranscript(original, interpreted);
});
 
interpreter.on('stateChange', (state) => {
  updateConnectionStatus(state);
});
 
interpreter.on('error', (error) => {
  showErrorMessage(error.message);
});
 
await interpreter.connect();
 
// Wire up your UI controls
document.querySelector('.mic-button').addEventListener('click', () => {
  if (interpreter.isListening) {
    interpreter.stopListening();
  } else {
    interpreter.startListening();
  }
});

Initialization

js
const interpreter = Interpreter.create(options);
OptionTypeRequiredDescription
sessionTokenstringYesToken from your backend
containerHTMLElementYesMount point for SDK internals
mode'headless'YesMust be 'headless'
sourceLanguagestringNoISO 639-1 code, auto-detect if omitted
targetLanguagesstring[]YesLanguages to interpret into

Connection Lifecycle

js
await interpreter.connect();    // Establish connection
interpreter.disconnect();       // End session gracefully
interpreter.destroy();          // Clean up all resources

Audio Controls

js
interpreter.startListening();   // Begin capturing audio
interpreter.stopListening();    // Stop capturing audio
interpreter.mute();             // Mute microphone (stay connected)
interpreter.unmute();           // Unmute microphone
 
// Input device selection
const devices = await interpreter.getInputDevices();
await interpreter.setInputDevice(deviceId);

State Properties

js
interpreter.state        // 'disconnected' | 'connecting' | 'connected' | 'error'
interpreter.isListening  // boolean
interpreter.isMuted      // boolean

Events

js
// Connection state changes
interpreter.on('stateChange', (state: State) => {});
 
// Interpretation results
interpreter.on('interpretation', (event: InterpretationEvent) => {});
 
// Audio input level (for visualizers)
interpreter.on('audioLevel', (level: number) => {});
 
// Errors
interpreter.on('error', (error: InterpreterError) => {});

InterpretationEvent structure:

ts
interface InterpretationEvent {
  original: string;           // Original speech text
  interpreted: string;        // Interpreted text
  sourceLanguage: string;     // Detected or configured source
  targetLanguage: string;     // Interpretation target
  isFinal: boolean;           // false = partial, true = final
  confidence?: number;        // 0-1 confidence score
}

Programmatic Transcript Control

Even in headless mode, you may want to use our transcript popover:

js
interpreter.expandTranscript();
interpreter.collapseTranscript();
interpreter.isTranscriptExpanded;  // boolean

Framework Wrappers

We provide thin wrappers that integrate with framework-native reactivity patterns.

Note: Framework packages are not yet published to npm. Package names and APIs are tentative.

React

bash
npm install @vitalvoice/interpreter-react
tsx
import { useInterpreter } from '@vitalvoice/interpreter-react';
 
function InterpretationUI() {
  const {
    interpreter,
    state,
    isListening,
    isMuted,
    interpretations,
    error
  } = useInterpreter({
    sessionToken,
    targetLanguages: ['es', 'fr'],
    mode: 'headless'
  });
 
  return (
    <div>
      <button onClick={() => isListening ? interpreter.stopListening() : interpreter.startListening()}>
        {isListening ? 'Stop' : 'Start'}
      </button>
 
      <div className="transcript">
        {interpretations.map((t, i) => (
          <p key={i}>{t.interpreted}</p>
        ))}
      </div>
    </div>
  );
}

Angular

bash
npm install @vitalvoice/interpreter-angular
ts
import { InterpreterService } from '@vitalvoice/interpreter-angular';
 
@Component({
  selector: 'app-interpretation',
  template: `
    <button (click)="toggle()">
      {{ (isListening$ | async) ? 'Stop' : 'Start' }}
    </button>
 
    <div class="transcript">
      <p *ngFor="let t of interpretations$ | async">{{ t.interpreted }}</p>
    </div>
  `
})
export class InterpretationComponent implements OnInit, OnDestroy {
  constructor(private interpreterService: InterpreterService) {}
 
  state$ = this.interpreterService.state$;
  isListening$ = this.interpreterService.isListening$;
  interpretations$ = this.interpreterService.interpretations$;
 
  async ngOnInit() {
    await this.interpreterService.initialize({
      sessionToken: this.sessionToken,
      targetLanguages: ['es', 'fr'],
      mode: 'headless'
    });
  }
 
  toggle() {
    this.interpreterService.toggleListening();
  }
 
  ngOnDestroy() {
    this.interpreterService.destroy();
  }
}

Svelte

bash
npm install @vitalvoice/interpreter-svelte
svelte
<script>
  import { createInterpreter } from '@vitalvoice/interpreter-svelte';
  import { onMount, onDestroy } from 'svelte';
 
  export let sessionToken;
 
  const interpreter = createInterpreter({
    sessionToken,
    targetLanguages: ['es', 'fr'],
    mode: 'headless'
  });
 
  const { state, isListening, interpretations } = interpreter.stores;
 
  onMount(() => interpreter.connect());
  onDestroy(() => interpreter.destroy());
</script>
 
<button on:click={() => interpreter.toggleListening()}>
  {$isListening ? 'Stop' : 'Start'}
</button>
 
<div class="transcript">
  {#each $interpretations as t}
    <p>{t.interpreted}</p>
  {/each}
</div>

Webhooks

Receive server-side notifications for session events. Configure webhook endpoints in your dashboard.

Note: Webhook configuration dashboard is not yet available. Endpoint URLs are tentative.

Available Events

EventDescription
session.startedInterpretation session began
session.endedSession completed or timed out
session.errorUnrecoverable error occurred

Payload Example

json
{
  "event": "session.ended",
  "sessionId": "sess_def456",
  "durationSeconds": 142,
  "languagePair": {
    "source": "es",
    "target": "en"
  },
  "metadata": {
    "userId": "user_123",
    "facility": "memorial_hospital"
  },
  "timestamp": "2025-01-15T12:07:22Z"
}

Verifying Signatures

All webhook payloads include a signature header for verification:

js
const crypto = require('crypto');
 
function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Error Handling

Error Types

ts
interface InterpreterError {
  code: string;
  message: string;
  recoverable: boolean;
}
CodeDescriptionRecoverable
AUTH_INVALIDSession token invalid or expiredNo - request new token
AUTH_QUOTA_EXCEEDEDAccount quota exceededNo
CONNECTION_FAILEDConnection failedYes - retry connect()
CONNECTION_LOSTConnection dropped mid-sessionYes - retry connect()
AUDIO_PERMISSION_DENIEDUser denied microphone accessYes - prompt user
AUDIO_DEVICE_ERRORMicrophone not availableYes - check device

Handling Errors

js
interpreter.on('error', (error) => {
  if (error.recoverable) {
    showRetryPrompt(error.message);
  } else if (error.code === 'AUTH_INVALID') {
    // Token expired, get a new one
    refreshSessionToken().then(token => {
      interpreter.destroy();
      initializeNewInterpreter(token);
    });
  } else {
    showErrorMessage(error.message);
  }
});

Usage & Billing

Note: Usage tracking APIs and billing details are tentative.

How Usage is Metered

  • Billed per minute of active interpretation (while audio is being processed)
  • Idle connection time is not billed
  • Minimum session charge: 15 seconds
  • All usage counts toward quota, including testing and development

Tracking Usage

bash
curl https://api.vitalvoice.ai/v1/usage \
  -H "Authorization: Bearer sk_live_..."
json
{
  "period": {
    "start": "2025-01-01T00:00:00Z",
    "end": "2025-01-31T23:59:59Z"
  },
  "usage": {
    "minutes": 1423,
    "sessions": 847
  },
  "quota": {
    "minutes": 5000,
    "remaining": 3577
  }
}

Session Metadata for Reporting

Tag sessions with metadata to segment usage in your own systems:

json
{
  "targetLanguages": ["es"],
  "metadata": {
    "department": "emergency",
    "facility_id": "hospital_123",
    "encounter_type": "intake"
  }
}

Metadata is returned in webhooks and available via the usage API for filtering.


Rate Limits

LimitDefaultEnterprise
Concurrent sessions10Custom
Sessions per minute30Custom
Max session duration30 min60 min

When rate limited, the API returns 429 Too Many Requests with a Retry-After header. Implement exponential backoff for resilience.


Testing

Note: Test API keys are not yet available. The testing workflow described here is tentative.

Test API Keys

Use test API keys (sk_test_...) during development. Test keys:

  • Use the same API as production
  • Count toward your quota (budget accordingly)
  • Are clearly labeled in usage reports for easy filtering

Request test keys from your account manager.

Debug Mode

Enable verbose logging during development:

js
const interpreter = Interpreter.create({
  sessionToken,
  container,
  mode: 'headless',
  debug: true  // Logs connection events, audio levels, and timing
});

Troubleshooting

No audio detected

  1. Check microphone permissions in browser settings
  2. Verify the correct input device with getInputDevices()
  3. Test your microphone in another application
  4. Ensure your page is served over HTTPS (required for microphone access)

High latency

  1. Check network conditions - interpretation requires stable connectivity
  2. Reduce targetLanguages to only what's needed
  3. Contact support if latency consistently exceeds 500ms

Session immediately disconnects

  1. Verify your session token hasn't expired (5 minute window)
  2. Check that your API key is active and has available quota
  3. Ensure you're not exceeding concurrent session limits

"Connection failed" errors

  1. Check for corporate firewalls blocking connections
  2. Verify the user's browser is supported (see Browser Support)
  3. Try a different network to isolate the issue

Reference

Supported Languages

57 languages are supported. Use ISO 639-1 codes when configuring targetLanguages.

CodeLanguageCodeLanguageCodeLanguage
afAfrikaanshuHungarianruRussian
arArabicidIndonesianskSlovak
azAzerbaijaniisIcelandicslSlovenian
beBelarusianitItaliansrSerbian
bgBulgarianjaJapanesesvSwedish
bsBosniankkKazakhswSwahili
caCatalanknKannadataTamil
csCzechkoKoreanthThai
cyWelshltLithuaniantlTagalog
daDanishlvLatviantrTurkish
deGermanmiMaoriukUkrainian
elGreekmkMacedonianurUrdu
enEnglishmrMarathiviVietnamese
esSpanishmsMalayzhChinese
etEstonianneNepali
faPersiannlDutch
fiFinnishnoNorwegian
frFrenchplPolish
glGalicianptPortuguese
heHebrewroRomanian
hiHindihyArmenian

Browser Support

BrowserMinimum Version
Chrome74+
Firefox66+
Safari14.1+
Edge79+

Modern JavaScript features are required. Internet Explorer is not supported.


Security

What We Protect

  • Your API key: Never exposed to browsers; only used server-to-server
  • Audio streams: Encrypted in transit, processed securely, never stored
  • Session tokens: Short-lived, single-use, scoped to one session

Your Responsibilities

  • Authenticate users before issuing session tokens
  • Set appropriate maxDurationSeconds limits
  • Monitor usage via session metadata and webhooks
  • Implement your own rate limiting if needed

FAQ

Can users customize the popover position?

In standard mode, configure via transcript.position. In headless mode, you control all rendering.

What happens when a session token expires?

The interpreter emits an AUTH_INVALID error. Request a new token from your backend and reinitialize.

Can I use multiple interpreters on one page?

Yes. Each Interpreter.create() call returns an independent instance.

How do I handle poor network conditions?

The SDK automatically handles reconnection for transient issues. For persistent failures, listen for CONNECTION_LOST errors and prompt users to retry.

Is there a way to get raw audio?

Not currently. Contact us if you have a specific use case.

Do you support mobile apps?

The SDK currently supports web browsers. Native iOS and Android SDKs are on our roadmap - contact your account manager for timeline updates.


Changelog

1.0.0 (Upcoming)

  • Initial release
  • Standard and headless modes
  • Support for 57 languages
  • React, Angular, and Svelte framework wrappers

Support

Note: Support channels listed below are tentative and not yet active.