MAI Voice 2 API, MAI Transcribe 1.5 API: Pricing, Documentation
by Microsoft
MAI Voice 2 API provides developers with a robust, enterprise-ready infrastructure designed to programmatically generate highly expressive and lifelike speech across diverse applications. Operating through a unified endpoint, this advanced audio intelligence tool enables seamless text-to-speech conversion, instant high-fidelity voice cloning, and multilingual narration without requiring extensive fine-tuning or localized hardware setup. It features automatic language detection and nuanced prosody control, making it exceptionally suited for driving interactive virtual assistants, dynamic e-learning modules, accessibility voiceovers, and complex interactive voice response architectures.

Models Version
Get $5 Free Credit on First Payment
No strings attached — add funds and get $5 bonus instantly
MAI Voice 2 API Documentation
Generate expressive speech from text with Microsoft MAI-Voice-2 on Azure Speech. Asynchronous: submit returns a request_id; poll the status endpoint until the request is COMPLETED. The speech is returned as a 24 kHz mono MP3 file.
POST https://gateway.pixazo.ai/mai-voice-2/v1/text-to-speechAuthentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Text to Speech - Microsoft MAI Voice 2
Request Code
POST https://gateway.pixazo.ai/mai-voice-2/v1/text-to-speech
Content-Type: application/json
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"text": "Hello from Pixazo. This is MAI Voice 2.",
"voice": "en-US-Harper:MAI-Voice-2",
"style": "excited",
"styledegree": 1
}import requests
url = "https://gateway.pixazo.ai/mai-voice-2/v1/text-to-speech"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
data = {
"text": "Hello from Pixazo. This is MAI Voice 2.",
"voice": "en-US-Harper:MAI-Voice-2",
"style": "excited",
"styledegree": 1
}
resp = requests.post(url, json=data, headers=headers)
print(resp.json())const res = await fetch("https://gateway.pixazo.ai/mai-voice-2/v1/text-to-speech", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
"text": "Hello from Pixazo. This is MAI Voice 2.",
"voice": "en-US-Harper:MAI-Voice-2",
"style": "excited",
"styledegree": 1
})
});
console.log(await res.json());curl -X POST 'https://gateway.pixazo.ai/mai-voice-2/v1/text-to-speech' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
--data-raw '{"text": "Hello from Pixazo. This is MAI Voice 2.", "voice": "en-US-Harper:MAI-Voice-2", "style": "excited", "styledegree": 1}'Output
{
"request_id": "microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Webhook (Optional)
Instead of polling, you can receive a Webhook callback when the request reaches a terminal state. Provide a Webhook URL via header on the submit request.
| Header | Required | Description |
|---|---|---|
| X-Webhook-URL | To enable | HTTPS URL to receive the Webhook callback. |
| X-Webhook-Mode | No | terminal (default, one callback on COMPLETED/ERROR) or sync (per-poll callbacks). |
Example: enable Webhook
curl -X POST 'https://gateway.pixazo.ai/mai-voice-2/v1/text-to-speech' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
-H 'X-Webhook-URL: https://your-server.com/webhook' \
--data-raw '{"text": "Hello from Pixazo. This is MAI Voice 2.", "voice": "en-US-Harper:MAI-Voice-2", "style": "excited", "styledegree": 1}'Callback Payload (success)
{
"request_id": "microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "microsoft-mai-voice-2",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.mp3",
"media_type": "audio/mpeg"
},
"created_at": "2026-07-31T11:34:16.102Z",
"completed_at": "2026-07-31T11:34:20.123Z"
}Failure callback shape
{
"request_id": "microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"model_id": "microsoft-mai-voice-2",
"error": "Description of the failure"
}Delivery semantics
- terminal mode: one Webhook callback when the request is COMPLETED or ERROR.
- sync mode: a Webhook callback on each status change.
- Callbacks are idempotent on
request_id— de-duplicate on it. - Respond
200within a few seconds; the Webhook endpoint must be HTTPS.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
text | Yes | string | — | 1–8000 characters | The text to speak. Billing counts these characters, rounded up to the next 1000. |
voice | No | string | en-US-Harper:MAI-Voice-2 | any prebuilt MAI-Voice-2 voice id | Which voice speaks the text. 47 prebuilt MAI-Voice-2 voices are available across 18 locales; every id ends in :MAI-Voice-2, for example es-MX-Valeria:MAI-Voice-2. See Voices and Styles below. |
style | No | string | — (neutral) | voice-specific — e.g. excited, happy, sad, angry, whispering, shouting | Speaking style, applied as the SSML mstts:express-as style. The supported set varies by voice and some voices support no styles at all. Microsoft specifies that when the style is missing or invalid the whole expressive block is ignored and the voice uses its default neutral speech. |
styledegree | No | number | 1 | 0.01–2 inclusive | Intensity of the chosen style; applies only when style is set. 1 is the predefined style intensity and 2 doubles it. Microsoft specifies that if the value is missing or the voice does not support it, the attribute is ignored. |
Text limits
textis required and must be a non-empty string of at most 8000 characters. Longer text is rejected at submit.- Send plain text, not SSML —
voice,styleandstyledegreeare applied for you. - Cost scales with the number of characters you submit (see Pricing).
Voices and Styles
47 prebuilt MAI-Voice-2 voices are available across 18 locales (de-DE, en-AU, en-US, es-ES, es-MX, fr-FR, hi-IN, hu-HU, it-IT, ko-KR, nl-NL, pt-BR, pt-PT, ro-RO, ru-RU, th-TH, tr-TR, zh-CN). Pass the full voice id in voice; every id ends in :MAI-Voice-2. The current list is maintained by Microsoft in the MAI-Voice documentation.
| Example voice | Locale | Gender |
|---|---|---|
en-US-Harper:MAI-Voice-2 | en-US | Female |
en-US-Ethan:MAI-Voice-2 | en-US | Male |
en-AU-Lisa:MAI-Voice-2 | en-AU | Female |
es-MX-Valeria:MAI-Voice-2 | es-MX | Female |
fr-FR-Marc:MAI-Voice-2 | fr-FR | Male |
hi-IN-Kavya:MAI-Voice-2 | hi-IN | Female |
zh-CN-Mei:MAI-Voice-2 | zh-CN | Female |
Styles
Supported styles are per voice. Most voices support the expressive set angry, confused, determined, disgusted, embarrassed, excited, fearful, happy, hopeful, jealous, joyful, regretful, relieved, sad, shouting, softvoice, surprised, whispering. Some voices instead support a narrative set (adventurous, caring, empathy, curious, encouraging, excited, friendly, cheerful, nostalgic, reflective, sad, disappointed, serious), and a few voices support no styles at all. Check the voice you are using against Microsoft’s per-voice style table before relying on a style.
Output
The completed request returns output.media_url, a 24 kHz mono MP3 (audio/mpeg). Fetch that URL to download the audio.
{
"text": "Welcome to Microsoft Build. MAI Voice 2 supports multilingual expressive synthesis.",
"voice": "en-US-Harper:MAI-Voice-2",
"style": "happy",
"styledegree": 1.2
}Example Request
{
"text": "Hello from Pixazo. This is MAI Voice 2.",
"voice": "en-US-Harper:MAI-Voice-2",
"style": "excited",
"styledegree": 1
}Example Response
{
"request_id": "microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Request Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| X-Webhook-URL | No | Enable Webhook callbacks (see Webhook section). |
Response Handling
| Status Code | Meaning |
|---|---|
| 202 | Accepted — request queued; returns request_id and polling_url. |
| 400 | Bad request — missing text, text longer than 8000 characters, or a malformed JSON body. |
| 401 | Unauthorized — missing or invalid subscription key. |
| 402 | Insufficient balance. |
| 429 | Too many requests. |
| 500 | Internal server error. |
A failure during synthesis is reported through the status endpoint as status: "ERROR", not as a synchronous error. Failed requests are not billed.
Retrieving Results
Poll the status endpoint with the request_id from the submit response until status is COMPLETED (or FAILED/ERROR), then fetch output.media_url for the audio.
curl 'https://gateway.pixazo.ai/v2/requests/status/microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY'Completed response
{
"request_id": "microsoft-mai-voice-2_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "microsoft-mai-voice-2",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.mp3",
"media_type": "audio/mpeg"
},
"created_at": "2026-07-31T11:34:16.102Z",
"completed_at": "2026-07-31T11:34:20.123Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique request identifier. |
| status | string | QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR. |
| model_id | string | The model that handled the request. |
| output.media_url | string | URL of the generated MP3 audio file. |
| output.media_type | string | audio/mpeg. |
| created_at | string | Request creation timestamp. |
| completed_at | string | Completion timestamp. |
| error | string | Error message when status is FAILED/ERROR. |
Status Values & Flow
QUEUED → PROCESSING → COMPLETED (success) or FAILED/ERROR (failure).
Pricing
Billed at $0.022 per 1000 characters of input text, rounded up to the next 1000 characters. Billing is based on the text you submit, not on the length of the audio produced.
| Characters submitted | Billed units (1000 chars) | Cost |
|---|---|---|
| 250 | 1 | $0.022 |
| 1000 | 1 | $0.022 |
| 1001 | 2 | $0.044 |
| 8000 (maximum) | 8 | $0.176 |
Because the character count is known when you submit, the cost of a request is determined at submit time. Failed requests are not billed.
MAI Voice 2 API Pricing
| Resolution | Price (USD) |
|---|---|
| Per 1,000 characters of input text | $0.022 |
MAI Transcribe 1.5 API Documentation
Transcribe audio into text with Microsoft's MAI-Transcribe-1.5 model, with automatic language detection across 43 languages. Asynchronous: submit returns a request_id; poll the status endpoint until the request is COMPLETED. The transcript is returned as a JSON file.
POST https://gateway.pixazo.ai/mai-transcribe/v1/speech-to-textAuthentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Speech to Text - Microsoft MAI Transcribe
Request Code
POST https://gateway.pixazo.ai/mai-transcribe/v1/speech-to-text
Content-Type: application/json
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"locales": ["en"],
"transcribe_style": "verbatim",
"phrase_list": ["Acme Corp", "Dr. Yamada"]
}import requests
url = "https://gateway.pixazo.ai/mai-transcribe/v1/speech-to-text"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
data = {
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"locales": ["en"],
"transcribe_style": "verbatim",
"phrase_list": ["Acme Corp", "Dr. Yamada"]
}
resp = requests.post(url, json=data, headers=headers)
print(resp.json())const res = await fetch("https://gateway.pixazo.ai/mai-transcribe/v1/speech-to-text", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"locales": ["en"],
"transcribe_style": "verbatim",
"phrase_list": ["Acme Corp", "Dr. Yamada"]
})
});
console.log(await res.json());curl -X POST 'https://gateway.pixazo.ai/mai-transcribe/v1/speech-to-text' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
--data-raw '{"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3", "locales": ["en"], "transcribe_style": "verbatim", "phrase_list": ["Acme Corp", "Dr. Yamada"]}'Output
{
"request_id": "microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Webhook (Optional)
Instead of polling, you can receive a Webhook callback when the request reaches a terminal state. Provide a Webhook URL via header on the submit request.
| Header | Required | Description |
|---|---|---|
| X-Webhook-URL | To enable | HTTPS URL to receive the Webhook callback. |
| X-Webhook-Mode | No | terminal (default, one callback on COMPLETED/ERROR) or sync (per-poll callbacks). |
Example: enable Webhook
curl -X POST 'https://gateway.pixazo.ai/mai-transcribe/v1/speech-to-text' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
-H 'X-Webhook-URL: https://your-server.com/webhook' \
--data-raw '{"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3", "locales": ["en"], "transcribe_style": "verbatim", "phrase_list": ["Acme Corp", "Dr. Yamada"]}'Callback Payload (success)
{
"request_id": "microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "microsoft-mai-transcribe",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.json",
"media_type": "application/json"
},
"created_at": "2026-07-31T11:34:16.102Z",
"completed_at": "2026-07-31T11:34:20.123Z"
}Failure callback shape
{
"request_id": "microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"model_id": "microsoft-mai-transcribe",
"error": "Description of the failure"
}Delivery semantics
- terminal mode: one Webhook callback when the request is COMPLETED or ERROR.
- sync mode: a Webhook callback on each status change.
- Callbacks are idempotent on
request_id— de-duplicate on it. - Respond
200within a few seconds; the Webhook endpoint must be HTTPS.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
audio_url | Yes | string | — | http(s) URL; WAV, MP3 or FLAC, under 50 MB | Public URL of the audio to transcribe. The file is fetched by the gateway, so the URL must be reachable without authentication. |
locales | No | array of string | — (multilingual auto-detect) | ISO language codes, e.g. ["en"], ["hi"], ["zh"] | Optional. Force recognition into a single language. Omit it and the model runs in multilingual mode across the 43 supported languages. |
transcribe_style | No | string | — (readability-optimised) | verbatim | Optional. Set to verbatim to preserve the original spoken content including filler words and disfluencies. The default output is cleaned up for readability. |
phrase_list | No | array of string | — | list of short phrases, e.g. ["Contoso", "Jessie"] | Names, product terms, acronyms or jargon that appear in the audio. Biases recognition towards this vocabulary, which improves accuracy on proper nouns and domain terminology. |
Audio limits
- The audio file must be under 50 MB and in WAV, MP3 or FLAC format.
audio_urlmust be anhttporhttpsURL and must be publicly reachable.- Speaker diarization is not supported — the transcript is not split by speaker.
- Prompt-tuning is not supported. Use
phrase_listto bias recognition instead. - Cost scales with the length of the audio (see Pricing).
Transcript Format
The completed request returns output.media_url, a JSON file containing the transcript. Fetch that URL to read the result.
{
"text": "From Pixazo, this is MAI Voice 2 running through our own gateway.",
"phrases": [
{
"offsetMilliseconds": 0,
"durationMilliseconds": 5856,
"text": "From Pixazo, this is MAI Voice 2 running through our own gateway.",
"locale": "en",
"confidence": 0
}
],
"duration_ms": 5860
}| Field | Type | Description |
|---|---|---|
| text | string | The full transcript, with punctuation and capitalisation. |
| phrases | array of object | Recognised segments in order. Each entry has text, offsetMilliseconds, durationMilliseconds, locale (the language detected for that segment) and confidence. |
| duration_ms | number | Length of the transcribed audio in milliseconds. This is the quantity you are billed on. |
Timestamps are returned per phrase, not per word: each entry in phrases carries offsetMilliseconds and durationMilliseconds.
Example Request
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"locales": ["en"],
"transcribe_style": "verbatim",
"phrase_list": ["Acme Corp", "Dr. Yamada"]
}Example Response
{
"request_id": "microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Request Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| X-Webhook-URL | No | Enable Webhook callbacks (see Webhook section). |
Response Handling
| Status Code | Meaning |
|---|---|
| 202 | Accepted — request queued; returns request_id and polling_url. |
| 400 | Bad request — missing audio_url, a non-http(s) URL, or an audio format that could not be determined from the URL and was not supplied. |
| 401 | Unauthorized — missing or invalid subscription key. |
| 402 | Insufficient balance. |
| 429 | Too many requests. |
| 500 | Internal server error. |
An unreachable audio_url, an oversized file, or audio containing no detectable speech is reported through the status endpoint as status: "ERROR", not as a synchronous error. Failed requests are not billed.
Retrieving Results
Poll the status endpoint with the request_id from the submit response until status is COMPLETED (or FAILED/ERROR), then fetch output.media_url for the transcript.
curl 'https://gateway.pixazo.ai/v2/requests/status/microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY'Completed response
{
"request_id": "microsoft-mai-transcribe_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "microsoft-mai-transcribe",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.json",
"media_type": "application/json"
},
"created_at": "2026-07-31T11:34:16.102Z",
"completed_at": "2026-07-31T11:34:20.123Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique request identifier. |
| status | string | QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR. |
| model_id | string | The model that handled the request. |
| output.media_url | string | URL of the transcript JSON file. |
| output.media_type | string | application/json. |
| created_at | string | Request creation timestamp. |
| completed_at | string | Completion timestamp. |
| error | string | Error message when status is FAILED/ERROR. |
Status Values & Flow
QUEUED → PROCESSING → COMPLETED (success) or FAILED/ERROR (failure).
Pricing
Billed at $0.006 per minute of audio ($0.36 per audio hour), rounded up to the next whole minute. Billing is based on the length of the audio you submit, not on the size of the transcript.
| Audio length | Billed minutes | Cost |
|---|---|---|
| 20 seconds | 1 | $0.006 |
| 90 seconds | 2 | $0.012 |
| 10 minutes | 10 | $0.06 |
| 1 hour | 60 | $0.36 |
A hold is placed when the request is submitted, because the audio length is not known until transcription completes. The hold is reduced to the real cost once the duration is known, and released in full if the request fails.
MAI Transcribe 1.5 API Pricing
| Resolution | Price (USD) |
|---|---|
| Per minute of audio (rounded up to the next full minute) | $0.006 |
⚡ Performance
Live usage measured on Pixazo's gateway, split by model version. Generation time is how long a generation takes end-to-end (lower is better). Success rate is the percent of generations that complete (higher is better).
〰 Uptime
Percent of generations that succeeded over the selected period, per model version.