# OpenRouter APIs — Microsoft AI: MAI-Voice-2.1 (microsoft/mai-voice-2.1)

Guide for calling every confirmed OpenRouter API that serves `microsoft/mai-voice-2.1`.

Model page: https://openrouter.ai/microsoft/mai-voice-2.1
Create an API key: https://openrouter.ai/settings/keys

## Authentication

Send this header with every request:

- Authorization: Bearer $OPENROUTER_API_KEY

## Text-to-Speech API

Synthesize audio with `microsoft/mai-voice-2.1` through OpenRouter's Text-to-Speech API.

Docs: https://openrouter.ai/docs/api/api-reference/tts/create-speech

### Endpoint

POST https://openrouter.ai/api/v1/audio/speech

Headers:
- Content-Type: application/json

### Request fields (microsoft/mai-voice-2.1)

- model: string (required) — `"microsoft/mai-voice-2.1"`
- input: string (required) — text to synthesize
- voice: "cs-CZ-Grant:MAI-Voice-2.1" | "cs-CZ-Harper:MAI-Voice-2.1" | "da-DK-Grant:MAI-Voice-2.1" | "da-DK-Harper:MAI-Voice-2.1" | "de-DE-Grant:MAI-Voice-2.1" | "de-DE-Harper:MAI-Voice-2.1" | "de-DE-Klaus:MAI-Voice-2.1" | "de-DE-Mia:MAI-Voice-2.1" | "en-AU-Isla:MAI-Voice-2.1" | "en-GB-Emily:MAI-Voice-2.1" | "en-GB-Harry:MAI-Voice-2.1" | "en-IN-Dhruv:MAI-Voice-2.1" | "en-IN-Priya:MAI-Voice-2.1" | "en-US-Ethan:MAI-Voice-2.1" | "en-US-Grant:MAI-Voice-2.1" | "en-US-Harper:MAI-Voice-2.1" | "en-US-Iris:MAI-Voice-2.1" | "en-US-Jasper:MAI-Voice-2.1" | "en-US-Olivia:MAI-Voice-2.1" | "en-US-Sage:MAI-Voice-2.1" | "es-ES-Marta:MAI-Voice-2.1" | "es-MX-Alejo:MAI-Voice-2.1" | "es-MX-Grant:MAI-Voice-2.1" | "es-MX-Harper:MAI-Voice-2.1" | "es-MX-Valeria:MAI-Voice-2.1" | "fi-FI-Grant:MAI-Voice-2.1" | "fi-FI-Harper:MAI-Voice-2.1" | "fr-FR-Grant:MAI-Voice-2.1" | "fr-FR-Harper:MAI-Voice-2.1" | "fr-FR-Marc:MAI-Voice-2.1" | "fr-FR-Soleil:MAI-Voice-2.1" | "hi-IN-Arjun:MAI-Voice-2.1" | "hi-IN-Dhruv:MAI-Voice-2.1" | "hi-IN-Grant:MAI-Voice-2.1" | "hi-IN-Harper:MAI-Voice-2.1" | "hi-IN-Kavya:MAI-Voice-2.1" | "hi-IN-Priya:MAI-Voice-2.1" | "hu-HU-Bence:MAI-Voice-2.1" | "hu-HU-Grant:MAI-Voice-2.1" | "hu-HU-Harper:MAI-Voice-2.1" | "hu-HU-Levente:MAI-Voice-2.1" | "hu-HU-Lilla:MAI-Voice-2.1" | "hu-HU-Reka:MAI-Voice-2.1" | "id-ID-Grant:MAI-Voice-2.1" | "id-ID-Harper:MAI-Voice-2.1" | "it-IT-Grant:MAI-Voice-2.1" | "it-IT-Harper:MAI-Voice-2.1" | "it-IT-Luca:MAI-Voice-2.1" | "it-IT-Rosa:MAI-Voice-2.1" | "ko-KR-Grant:MAI-Voice-2.1" | "ko-KR-Haena:MAI-Voice-2.1" | "ko-KR-Harper:MAI-Voice-2.1" | "ko-KR-Junho:MAI-Voice-2.1" | "nb-NO-Grant:MAI-Voice-2.1" | "nb-NO-Harper:MAI-Voice-2.1" | "nl-NL-Grant:MAI-Voice-2.1" | "nl-NL-Harper:MAI-Voice-2.1" | "nl-NL-Sander:MAI-Voice-2.1" | "pl-PL-Grant:MAI-Voice-2.1" | "pl-PL-Harper:MAI-Voice-2.1" | "pt-BR-Caio:MAI-Voice-2.1" | "pt-BR-Grant:MAI-Voice-2.1" | "pt-BR-Harper:MAI-Voice-2.1" | "pt-BR-Luana:MAI-Voice-2.1" | "pt-BR-Pedro:MAI-Voice-2.1" | "pt-BR-Rafael:MAI-Voice-2.1" | "pt-PT-Grant:MAI-Voice-2.1" | "pt-PT-Harper:MAI-Voice-2.1" | "pt-PT-Rui:MAI-Voice-2.1" | "ro-RO-Andrei:MAI-Voice-2.1" | "ro-RO-Elena:MAI-Voice-2.1" | "ro-RO-Grant:MAI-Voice-2.1" | "ro-RO-Harper:MAI-Voice-2.1" | "ro-RO-Ioana:MAI-Voice-2.1" | "ro-RO-Radu:MAI-Voice-2.1" | "ru-RU-Grant:MAI-Voice-2.1" | "ru-RU-Harper:MAI-Voice-2.1" | "ru-RU-Lev:MAI-Voice-2.1" | "ru-RU-Masha:MAI-Voice-2.1" | "sv-SE-Grant:MAI-Voice-2.1" | "sv-SE-Harper:MAI-Voice-2.1" | "th-TH-Grant:MAI-Voice-2.1" | "th-TH-Harper:MAI-Voice-2.1" | "th-TH-Krit:MAI-Voice-2.1" | "th-TH-Nattapong:MAI-Voice-2.1" | "tr-TR-Aydin:MAI-Voice-2.1" | "tr-TR-Elif:MAI-Voice-2.1" | "tr-TR-Grant:MAI-Voice-2.1" | "tr-TR-Harper:MAI-Voice-2.1" | "vi-VN-Grant:MAI-Voice-2.1" | "vi-VN-Harper:MAI-Voice-2.1" | "zh-CN-Bo:MAI-Voice-2.1" | "zh-CN-Grant:MAI-Voice-2.1" | "zh-CN-Harper:MAI-Voice-2.1" | "zh-CN-Lan:MAI-Voice-2.1" | "zh-CN-Mei:MAI-Voice-2.1" | "zh-CN-Wei:MAI-Voice-2.1" (optional) — provider-specific voice identifier
- response_format: "mp3" | "pcm" (optional) — output audio encoding; defaults to pcm

### Response

Success returns raw audio bytes, not JSON.

- `Content-Type` identifies the audio encoding, such as `audio/mpeg` or `audio/pcm`.
- `X-Generation-Id` identifies the billed generation.
- Write the response body directly to an audio file; do not call `response.json()`.

### Examples

#### Text to Speech

```bash
curl https://openrouter.ai/api/v1/audio/speech \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  --output output.mp3 \
  -d '{
  "model": "microsoft/mai-voice-2.1",
  "input": "The warm light flows across the OpenRouter office as the evening settles in and the routing never stops. One interface, hundreds of models. Ready when you are.",
  "voice": "en-US-Harper:MAI-Voice-2.1",
  "response_format": "mp3"
}'
```

### Error differences

- 400 — malformed audio input or an audio option the routed provider does not support
- 502 — the upstream audio operation failed

## Errors

Failures return `{"error": {"code": <number>, "message": <string>}}` with the HTTP status:

- 400 — malformed request or an unsupported parameter
- 401 — missing or invalid API key
- 402 — insufficient credits
- 403 — spend limit reached, key disabled, or access blocked
- 404 — unknown model or no provider can serve the request
- 429 — rate limited; retry with backoff
- 502 — the operation failed upstream; failed generations are not billed

---

Canonical version of this document: https://openrouter.ai/microsoft/mai-voice-2.1/llms.txt
