Quick Start

Quick Start Guide

Get your API key

Your API key is available on the Settings page. Include it in every request as the X-API-Key header.

Submit a job

curl -X POST https://siren.example.com/api/jobs \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "full",
    "voiceTemplateId": "vt_template1",
    "input": { "script": "Hello world", "videoUrl": "https://..." },
    "output": { "webhookUrl": "https://your-webhook.com/done" }
  }'

Check results

Poll GET /api/jobs/{job_id} or receive a webhook callback when the job completes.

Voice Cloning & Intonation

Siren clones a voice from a short reference clip, then speaks any text in that voice. You control how it speaks with three stacking layers: expressive styles (the strongest — emotion comes from a recorded take), voice-design tags (pitch / whisper / accent), and prosody markup in the text itself.

Clone a voice

Upload a clean 5–30 second clip of one speaker. Add a reference transcript (the exact words in the clip) and a language for a higher-fidelity clone — both optional but recommended. Vietnamese (vi) routes to the dedicated Vietnamese model. You can also do this in the UI: Voices → Register Voice.

curl -X POST https://siren.nopslabs.com/api/voices/register \
  -H "X-API-Key: YOUR_KEY" \
  -F "name=Triet — Studio" \
  -F "language=en" \
  -F "ref_text=The exact words spoken in the clip." \
  -F "file=@/path/to/reference.wav"
# → { "voice_id": "bacc...", "name": "Triet — Studio", "created_at": "..." }

Add expressive styles (emotion)

A voice can store several style takes — e.g. one calm, one excited, one serious. Each is its own clip. At synthesis time you pick a styleId and the delivery inherits that take's emotion and phrasing. This is the most powerful lever — the quality of your reference takes is what gives genuine emotional range. Manage these in the UI under Voices → Manage styles.

curl -X POST https://siren.nopslabs.com/api/voices/VOICE_ID/styles \
  -H "X-API-Key: YOUR_KEY" \
  -F "label=Excited" \
  -F "ref_text=Words spoken in the excited take." \
  -F "file=@/path/to/excited_take.wav"
# → { "id": "style_2dcb...", "label": "Excited", ... }

# list / delete
curl https://siren.nopslabs.com/api/voices/VOICE_ID/styles -H "X-API-Key: YOUR_KEY"
curl -X DELETE https://siren.nopslabs.com/api/voices/VOICE_ID/styles/style_2dcb... -H "X-API-Key: YOUR_KEY"

Synthesize with intonation

Combine everything in one call to /api/audio/synthesize. All intonation fields are optional and stack: pick a styleId for emotion, add voice-design tags, and use markup in the script. (For timed subtitles, send srt instead of script — each cue is duration-locked to its window.)

curl -X POST https://siren.nopslabs.com/api/audio/synthesize \
  -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{
    "voiceId": "VOICE_ID",
    "styleId": "style_2dcb...",          // optional — clone from this expressive take
    "tts_language": "en",
    "tts_quality": "quality",
    "pitch": "high pitch",                // voice-design (validated, optional)
    "accent": "british accent",
    "whisper": false,
    "speed": 1.0,
    "script": "Wait [pause] this is the **only** way... really."
  }'
# → { "audioUrl": "https://...", "srtUrl": "https://..." }

Voice-design tags

Coarse, global shaping that layers on top of a clone. Values are validated — an unknown value returns 422 with the allowed list.

pitch

  • very low pitch
  • low pitch
  • moderate pitch
  • high pitch
  • very high pitch

accent

  • american accent
  • british accent
  • australian accent
  • canadian accent
  • indian accent
  • chinese accent
  • korean accent
  • japanese accent
  • russian accent
  • portuguese accent

whisper

true for a whispered delivery.

speed

0.5–2.0 (plain text only; SRT auto-fits each cue).

Prosody markup

Write these directly in your script for sentence-level phrasing. They compile to punctuation the model turns into real pauses — and work together with a cloned voice and a style.

MarkupEffect
**word**Emphasis — isolates the phrase so the voice lifts and breaks around it.
[pause]A short beat (≈ one ellipsis hold).
[pause 400ms]A timed hold — longer numbers give longer pauses.
...Trailing pause / hesitation (becomes a true ellipsis).
--A brief mid-sentence break (becomes a comma).

Example: "Wait [pause] this is the **only** way... really." → spoken with a beat after "Wait", emphasis on "only", and a trailing hesitation before "really".

Which lever should I use?

  • Emotion / tone → register a style take (step 2). Strongest, most natural.
  • Phrasing / pauses / emphasisprosody markup in the script.
  • Register / whisper / accentvoice-design tags. Coarse but free.

Pipeline Modes

Pipeline Modes

Choose the mode that matches your use case. Each mode accepts different inputs and produces different outputs.

Full Pipeline

full

Generates speech from text and syncs it with a video. End-to-end pipeline.

Required Inputs

  • script
  • videoUrl
  • voiceTemplateId

Example Request

{
  "type": "full",
  "voiceTemplateId": "vt_template1",
  "input": {
    "script": "Welcome to our platform",
    "videoUrl": "https://storage.example.com/video.mp4"
  },
  "output": {
    "webhookUrl": "https://your-app.com/webhook"
  }
}

Expected Outputs

  • Final video with synced audio (.mp4)
  • Generated audio (.wav)
  • Subtitle file (.srt)

TTS Only

tts_only

Converts text to speech using a voice template. No video processing.

Required Inputs

  • script
  • voiceTemplateId

Example Request

{
  "type": "tts_only",
  "voiceTemplateId": "vt_template1",
  "input": {
    "script": "Hello, this is a test."
  },
  "output": {
    "webhookUrl": "https://your-app.com/webhook"
  }
}

Expected Outputs

  • Generated audio file (.wav)

Lipsync Only

lipsync_only

Syncs existing audio with a video. Skips speech generation.

Required Inputs

  • audioUrl
  • videoUrl

Example Request

{
  "type": "lipsync_only",
  "input": {
    "audioUrl": "https://storage.example.com/audio.wav",
    "videoUrl": "https://storage.example.com/video.mp4"
  },
  "output": {
    "webhookUrl": "https://your-app.com/webhook"
  }
}

Expected Outputs

  • Final video with synced audio (.mp4)

Webhook Payloads

Webhook Payload Examples

Job Completed

job.completed
{
  "event": "job.completed",
  "job_id": "job_abc123",
  "type": "full",
  "status": "completed",
  "created_at": "2025-01-15T10:30:00Z",
  "completed_at": "2025-01-15T10:32:45Z",
  "output": {
    "video_url": "https://storage.example.com/output/job_abc123/final.mp4",
    "audio_url": "https://storage.example.com/output/job_abc123/audio.wav",
    "subtitle_url": "https://storage.example.com/output/job_abc123/subtitles.srt",
    "duration_seconds": 45.2
  }
}

Job Failed

job.failed
{
  "event": "job.failed",
  "job_id": "job_def456",
  "type": "tts_only",
  "status": "failed",
  "created_at": "2025-01-15T11:00:00Z",
  "failed_at": "2025-01-15T11:01:12Z",
  "error": {
    "code": "TTS_GENERATION_FAILED",
    "message": "Voice template not found or expired",
    "retryable": true
  }
}

Signature Verification

All webhook payloads include an X-Siren-Signature header containing an HMAC-SHA256 signature. Verify this signature using your webhook secret to ensure the payload is authentic.

import hmac
import hashlib

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Interactive API Explorer

Explore all available endpoints, try requests, and view response schemas.

Loading API explorer...