The Hakim TTS family

Three tiers, one API. Pick a tier by setting model on POST /v1/audio/speech. Names are Arabic adjectives that ladder up alongside the capability set:

  • Hakim Saree' v1.3 (hakim-fast-v1) · swift. Sub-120 ms streaming TTFB, 32 supported languages. The default for new code. Speed-tuned; no inline tags, no voice prompting.
  • Hakim Faseeh v2 (hakim-v2) · eloquent. Premium quality, non-verbal tag support, 41 languages. Use when naturalness matters more than the lowest latency.
  • Hakim Mulhim v3 (hakim-v3) · inspiring. Premium quality, tags plus voice generation from a free-form prompt, 41 languages. The full capability set; pair with voice_prompt on /v1/audio/speech or with POST /v1/audio/voices/design to conjure a fresh voice from text.

Capability matrix

CapabilitySaree'FaseehMulhim
Streaming TTFB ≤ 120 ms✅··
Premium quality·✅✅
Non-verbal tags ([laugh], [breath], …)·✅✅
Voice prompt (voice_prompt field)··✅
Voice design endpoint (/v1/audio/voices/design)··✅
Languages supported324141

Pricing

Usage is billed per input character, in credits. The premium tiers use more credits per character than the default tier:

TierModelCredits per character
Saree'hakim-fast-v11.0
Faseehhakim-v21.5
Mulhimhakim-v32.0

Billing is computed on the text the model actually receives. Unsupported tags and prompts are stripped first, so text that is ignored is never billed. The same rates apply on POST /v1/audio/speech and on the realtime stream, where you can also pick the tier per session or per utterance with model.

Picking a tier

A few common shapes:

  • Live agent / IVR / voicebot · pick hakim-fast-v1. The streaming TTFB budget matters more than expressive flourishes.
  • Podcasts, audiobooks, branded narration · pick hakim-v2 and use non-verbal tags (laughs, sighs, hesitations) to add realism.
  • Creative or marketing video where voice identity is the differentiator · pick hakim-v3 and either set voice_prompt on the speech call or design a voice from scratch and pin it to your library.

Graceful degradation

The API parser strips capabilities your tier doesn't advertise rather than rejecting the request. A [laugh] tag inside input on hakim-fast-v1 plays clean · the bracketed token is removed before synthesis, the audio is unchanged from "hello world" with the tag absent, and the response carries x-hakim-warnings: tags_stripped_by_model_capability.

Same posture for an unsupported voice_prompt (dropped + flagged via voice_prompt_dropped_by_model_capability). The exception is POST /v1/audio/voices/design, which does reject with 422 · there's no graceful fallback when the prompt is the whole request.

Sniff the x-hakim-warnings header to detect the strip:

curl -i https://api.tryhakim.ai/v1/audio/speech \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hakim-fast-v1",
    "input": "Hello [laugh] world",
    "voice": "layla-egyptian"
  }' \
  --output speech.mp3 \
  | grep -i x-hakim-warnings
# x-hakim-warnings: tags_stripped_by_model_capability

Legacy id

hakim-flash-v1 is the pre-launch codename of the speed tier; the API still accepts it and normalises every request body, audit log, and metric label to the canonical hakim-fast-v1. New code should pick the canonical id; legacy integrations don't need to change.

Cookbook

A collection of common patterns. Each recipe names the tier it needs up front so you can scan and pick.

Recipe 1 · Pick the right tier (decision tree)

Three honest questions in order:

  1. Is your latency budget under 300 ms wall-clock? (voicebots, IVR, in-game characters, interactive agents) → Saree' v1.3. The streaming TTFB is the binding spec.
  2. Are you embedding non-verbal cues ([laugh], [breath], [whisper], …) in narration, or do you need premium-quality prosody on long-form audio (podcasts, audiobooks, video voiceover)? → Faseeh v2.
  3. Are you generating a voice from a free-form description rather than picking one off the shelf? → Mulhim v3.

If two answers say yes, pick the tier furthest up the ladder; you can always override per request. The default if you don't pass model is hakim-fast-v1.

# Saree' (default) · streaming voicebot
curl https://api.tryhakim.ai/v1/audio/speech \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"hakim-fast-v1","input":"Press one for sales.","voice":"alex","response_format":"pcm","stream":true}'

# Faseeh · premium narration with tags
curl https://api.tryhakim.ai/v1/audio/speech \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"hakim-v2","input":"Wait. [breath] Did that just happen?","voice":"layla-egyptian","response_format":"mp3"}'

# Mulhim · voice design from a prompt
curl https://api.tryhakim.ai/v1/audio/voices/design \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description":"warm raspy elderly woman, low-pitched","sample_text":"Welcome to the test of voice design.","save_as_voice":{"name":"Grandma Demo"}}'

Recipe 2 · Bilingual content (Arabic + English in one sentence)

Tier: any. Code-switching is a model-side capability, not a tier-gated feature. Every Hakim voice can read mixed Arabic + English without explicit language hints · the renderer picks up the script and stays in the chosen voice without flipping mid-sentence.

curl https://api.tryhakim.ai/v1/audio/speech \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hakim-fast-v1",
    "input": "السلام عليكم، this is Aya. Welcome to the platform.",
    "voice": "cmokbc2b1001pvu39wmj61b7h",
    "response_format": "mp3"
  }' \
  --output bilingual.mp3

Tips:

  • Pick the language for the dominant register. A 70/30 Arabic/English clip reads more natural on a Khaleeji or Egyptian voice than on a French one, even if the speaker would technically pronounce both correctly.
  • Punctuation matters. A comma inside the code-switch zone gives the renderer a beat to settle into the second language. Hello، this is Aya (Arabic comma) and Hello, this is Aya (Latin comma) both work; pick the one your localisation pipeline emits.
  • For tags ([laugh] etc.), use Faseeh or Mulhim · tags are stripped on Saree' with a warning header but the speech still plays.

Recipe 3 · Clone an employee's voice and reuse across tiers

Tier: any. A cloned voice is a Voice row, addressable by its voice id on every tier the same way a preset voice is. Clone once on Faseeh's audio quality bar, then reuse the same voice id on Saree' for runtime synthesis when latency matters.

# 1. Capture the consent + sample (one-time, ~10 s of clean audio)
curl -X POST https://api.tryhakim.ai/v1/audio/voices/clone \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -F "name=Sarah, narrator" \
  -F "language=ar" \
  -F "consent_confirmed=true" \
  -F "file=@./sarah-10s.wav"
# Returns: { "voice": { "id": "voi_01HX...", "status": "processing" } }

# 2. (Wait a few seconds, or subscribe to `voice_clone.ready` via webhook)

# 3. Use the cloned voice on whichever tier fits the task:
curl https://api.tryhakim.ai/v1/audio/speech \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hakim-fast-v1",
    "input": "Welcome to your dashboard.",
    "voice": "voi_01HX...",
    "stream": true
  }'

The cloned voice carries the same dialect, register, and timbre across all three tiers. What changes is the tier's posture: same voice, faster first byte on Saree', tag-aware prosody on Faseeh, prompt-overlay on Mulhim. See the voice cloning reference for the consent + retention contract.

Recipe 4 · Graceful tier downgrade for old integrations

Tier: Saree' (the always-on default). When a request from an older client includes a voice_prompt field or an inline [laugh] tag, the API strips the unsupported bits and returns 200 · your audio still plays. The x-hakim-warnings response header tells you what was dropped:

curl -i https://api.tryhakim.ai/v1/audio/speech \
  -H "Authorization: Bearer $HAKIM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hakim-fast-v1",
    "input": "Hello [laugh] world",
    "voice": "alex",
    "voice_prompt": "elderly woman with raspy voice"
  }' \
  --output speech.mp3 \
  | grep -i x-hakim-warnings
# x-hakim-warnings: tags_stripped_by_model_capability, voice_prompt_dropped_by_model_capability

Sniff the header in your client to detect strips and promote to Faseeh / Mulhim on the next call if your product surface expects the full capability set. Server-Sent Events streaming clients receive the same header on the initial 200 OK.

Recipe 5 · Migrate from another vendor's tag set

Tier: Faseeh or Mulhim (Saree' strips tags silently). Map common non-verbal tokens from other vendors to Hakim's allowlist:

Other vendor tokenHakim equivalentNotes
<break time="500ms"/>[breath]SSML pause, but tighter to natural breath cadence
<emphasis>(inline **)Use Markdown bold inside Faseeh / Mulhim input
[Question-ah][ask]Question intonation cue
[Surprise-yo][wow]Surprise cue
<say-as interpret-as="cardinal">42</say-as>(literal)We disambiguate inline numerics automatically
[Laughter] / [Chuckle][laugh]Hakim's single laugh token covers both registers

Anything outside the allowlist is silently stripped and surfaced via x-hakim-warnings: tags_stripped_by_model_capability. Run a one-off preprocessing pass in your code to rewrite tokens before sending; the diff is a regex per vendor.

Recipe 6 · A/B a new tier without changing your client

If you ship Saree' today and want to try Faseeh on a slice of traffic, pass model per request from your backend. The wire shape is identical:

import { HakimClient } from '@hakim/node';

const client = new HakimClient({ apiKey: process.env.HAKIM_API_KEY });

async function speak(text: string, userId: string): Promise<ReadableStream> {
  // Cohort 10% of users to the premium tier; everyone else stays on Saree'.
  const tier = hash(userId) % 100 < 10 ? 'hakim-v2' : 'hakim-fast-v1';
  const { stream } = await client.audio.speech.stream({
    model: tier,
    input: text,
    voice: 'layla-egyptian',
    response_format: 'mp3',
  });
  return stream;
}

Quality posture is the marketing pitch on Faseeh / Mulhim, so measure the listen-through rate rather than only TTFB. A 50 ms cost on first audio is trivial if it lifts retention on a 20-minute podcast.

Next steps

  • Non-verbal tags · full token list with examples for Faseeh + Mulhim.
  • Voice design · the design endpoint, prompt structure, and the save-as-voice flow on Mulhim.
  • Streaming · chunked HTTP audio for sub-120 ms TTFB on Saree'.
  • Errors · the x-hakim-warnings header, retry strategy, and idempotency keys.