Speech Synthesis API Reference

Speech Synthesis API Reference

One text-to-speech endpoint: JSON by default (audio URL, usage and billing details), or raw audio bytes for OpenAI-compatible clients. Works with OpenAI TTS, Bailian Qwen-Audio-TTS and other speech models.

FieldValue
Base URLhttps://token.easyapi.com/v1
AuthenticationAuthorization: Bearer `API_KEY`
Example modelqwen-audio-3.0-tts-plus
FormatREST JSON (default) / raw audio (Accept: application/octet-stream)
BillingPriced by input characters/tokens and audio usage; the response includes a billing snapshot
Note: JSON is returned by default: when audio.storage=qiniu, audio.url is a file copied to the EasyAPI Qiniu bucket (upstream URLs are never exposed); if Qiniu is disabled or the copy fails, the response falls back to audio.storage=inline with base64 audio.data. To receive audio bytes, send Accept: application/octet-stream (the official OpenAI SDK does this automatically); Content-Type then follows response_format: mp3 -> audio/mpeg, wav -> audio/wav, pcm -> audio/pcm, opus -> audio/ogg. stream_format=sse always returns a binary stream. Valid voices depend on the model: Bailian Qwen-Audio-TTS voices depend on the model (qwen-audio-3.0-tts-plus uses longanlingxin / longanlufeng; 3.0-flash uses longanhuan_v3.6 and others), OpenAI TTS uses alloy / nova, so check the model voice list. Provider-specific parameters can be passed through metadata.

Example model

Examples below use qwen-audio-3.0-tts-plus (Qwen Audio TTS Plus). Replace model and adjust size, quality, etc. per console docs when switching models.

Create speech

POSThttps://token.easyapi.com/v1/audio/speech

Synthesize the input text. JSON is returned by default (audio.url or audio.data, usage, billing); audio bytes are returned for Accept: application/octet-stream or audio/*. Sentence-level streaming is not supported: stream_format=sse is answered with the complete clip.

Request parameters

NameInTypeRequiredDescription
AuthorizationheaderstringYesEasyAPI API Key. Format: Bearer `API_KEY`
Content-TypeheaderstringYesAlways application/json
AcceptstringNoOmitted or application/json: structured JSON (default); application/octet-stream or audio/*: raw audio bytes

Request body

NameTypeRequiredDescription
modelstringYesSpeech model ID, e.g. qwen-audio-3.0-tts-plus, tts-1
inputstringYesText to synthesize; SSML / LaTeX supported where the model allows it
voicestringYesVoice name, model-specific; Bailian defaults to longanhuan_v3.6
response_formatstringNoAudio encoding: mp3 (default), wav, pcm, opus
speednumberNoSpeed multiplier, mapped to Bailian rate (0.5–2.0) and clamped to that range
instructionsstringNoSynthesis instruction for dialect, emotion or role, mapped to Bailian instruction
metadataobjectNoProvider-native parameters passed through: volume(0-100), pitch(0.5-2.0), bit_rate(6-510, opus only), sample_rate, enable_ssml, word_timestamp_enabled, seed, language_hints, hot_fix, enable_aigc_tag; keys matching standard fields take precedence

Example

{
  "model": "qwen-audio-3.0-tts-plus",
  "input": "你好,欢迎使用 EasyAPI 语音合成。",
  "voice": "longanlingxin",
  "response_format": "mp3",
  "speed": 1.0,
  "instructions": "用轻松自然的语气朗读"
}

Response fields

NameTypeDescription
idstringRequest ID, same as the X-EasyAPI-Request-Id response header
objectstringAlways audio.speech
createdintegerResponse creation time (Unix seconds)
modelstringRequested model ID
voicestringVoice used for this request
audio.storagestringqiniu: uploaded to Qiniu, see audio.url; inline: base64 in audio.data
audio.formatstringAudio codec
audio.content_typestringAudio MIME type
audio.sample_rateintegerSample rate in Hz; omitted when unknown
audio.bytesintegerAudio size in bytes
audio.duration_secondsnumberDuration in seconds; 0 when it cannot be parsed
audio.urlstringQiniu CDN URL when audio.storage=qiniu
audio.datastringBase64 audio when audio.storage=inline
usage.charactersintegerBilled characters when the provider charges by character (Bailian 3.0)
usage.input_tokensintegerBilled input tokens; falls back to upstream input_tokens or a local estimate
usage.output_tokensintegerBilled output (audio) tokens; upstream output_tokens wins when present
usage.total_tokensintegerSum of input and output tokens
usage.input_sourcestringInput usage source: upstream or local_estimate
usage.output_sourcestringOutput usage source: upstream, duration_estimate or bytes_estimate
billing.modestringBilling mode: tiered_expr, ratio or price
billing.currencystringAmount currency, currently USD
billing.quotaintegerActual quota charged (500000 = 1 USD)
billing.amountnumberAmount converted from quota (USD)
billing.quota_per_unitnumberQuota units per USD
billing.group_rationumberEffective group ratio
billing.discountnumberEffective discount multiplier (0-1)
billing.model_rationumberratio mode: model ratio
billing.model_pricenumberprice mode: per-request price
billing.audio_rationumberratio mode: audio input ratio
billing.audio_completion_rationumberratio mode: audio output ratio
billing.matched_tierstringtiered_expr mode: matched tier name
billing.expressionstringtiered_expr mode: billing expression
billing.expression_costnumbertiered_expr mode: expression result before quota conversion
billing.cost_multipliernumbertiered_expr mode: cost multiplier (e.g. peak hours)
billing.inputsobjecttiered_expr mode: variables passed to the expression (p, c, ai, ao, len)

Default response (JSON with a Qiniu URL)

{
  "id": "2026110206055130815495705874a1XipEBXYs",
  "object": "audio.speech",
  "created": 1793599552,
  "model": "qwen-audio-3.0-tts-plus",
  "voice": "longanlingxin",
  "audio": {
    "storage": "qiniu",
    "format": "mp3",
    "content_type": "audio/mpeg",
    "sample_rate": 24000,
    "bytes": 258048,
    "duration_seconds": 4.032,
    "url": "https://qiniu.easyapi.com/easyapi-ai/audio/2026/11/02/2026110206055130815495705874a1XipEBXYs.mp3"
  },
  "usage": {
    "characters": 15,
    "input_tokens": 15,
    "output_tokens": 67,
    "total_tokens": 82,
    "input_source": "upstream",
    "output_source": "duration_estimate"
  },
  "billing": {
    "mode": "tiered_expr",
    "currency": "USD",
    "quota": 79,
    "amount": 0.000158,
    "quota_per_unit": 500000,
    "group_ratio": 1,
    "discount": 0.5,
    "matched_tier": "speech",
    "expression": "tier(\"speech\", p * 20.9895)",
    "expression_cost": 314.8425,
    "cost_multiplier": 1,
    "inputs": { "p": 15, "c": 67, "ai": 0, "ao": 67, "len": 15 }
  }
}

Binary response (Accept: application/octet-stream)

HTTP/1.1 200 OK
Content-Type: audio/mpeg
Content-Length: 258048
X-EasyAPI-Audio-Bytes: 258048
X-EasyAPI-Audio-Seconds: 4.032
X-EasyAPI-Audio-Format: mp3
X-EasyAPI-Audio-Sample-Rate: 24000

<二进制音频数据>

Status codes

Status codeMeaningDescriptionData model
200OKJSON by default (audio.url or audio.data + usage + billing); raw audio bytes when Accept requests a binary typeAudioSpeechResponse | audio/*
400Bad requestInvalid parameter or rejected by upstream, e.g. unknown voice or empty textErrorResponse
401UnauthorizedMissing or invalid API keyErrorResponse
402Insufficient quotaAccount balance cannot cover this synthesisErrorResponse
429Rate limitedToo many requests, retry laterErrorResponse
500Server errorUpstream or gateway failure, safe to retryErrorResponse
Response: Billing matches the admin usage log: billing.inputs are the variables the expression actually saw, and billing.quota is the final charged quota. billing is a whitelist and never includes channel-internal data.