-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathopenapi.json
More file actions
1 lines (1 loc) · 29.8 KB
/
Copy pathopenapi.json
File metadata and controls
1 lines (1 loc) · 29.8 KB
1
{"openapi":"3.1.1","info":{"title":"VoiceLabs API","version":"1.0.0","summary":"Generate speech, transcribe audio, and read your VoiceLabs data over HTTP.","description":"The VoiceLabs public API. Text-to-speech and transcription run on VoiceLabs' GPU servers; this surface is the HTTP way to reach them.\n\nAuthenticate with an API key in the `x-api-key` header, created in the developer console with the scopes it needs. Responses to an API-key request carry IETF draft-11 `RateLimit` headers, and every error is an RFC 9457 problem document whose `code` is a stable token to branch on.\n\nAn OAuth 2.1 access token is the other accepted credential, for software acting on behalf of OTHER people's VoiceLabs accounts — the same authorization server the VoiceLabs MCP server uses. Both carry the same scopes and are gated by the same check; the `RateLimit` headers describe a key's budget and are therefore absent on the OAuth lane.\n\nGeneration is asynchronous: `POST /v1/speech` returns a generation id immediately, and `GET /v1/generations/{generationId}` is polled for the finished audio. Writes accept an `Idempotency-Key` header so a retry after a lost response cannot generate twice.\n\nThis document is generated from the same schemas the server validates with, so it describes the running API rather than an account of it.","termsOfService":"https://voicelabs.now/terms","contact":{"name":"VoiceLabs support","url":"https://voicelabs.now/support"}},"servers":[{"url":"https://app.voicelabs.now","description":"Production"}],"tags":[{"name":"Voices & history","description":"Read the voices, captures, and generations on an account."},{"name":"Generation","description":"Create speech and transcribe audio."}],"paths":{"/v1/voices":{"get":{"operationId":"listVoices","summary":"List voices","description":"List the voice profiles on this account — both cloned voices and built-in presets — with language, default engine, and usage counts. A new account has none until a voice is created.\n\nRequires the `voice:read` scope.","tags":["Voices & history"],"responses":{"200":{"description":"Success.","headers":{"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"language":{"type":"string"},"voice_type":{"type":"string"},"default_engine":{"anyOf":[{"type":"string"},{"type":"null"}]},"has_personality":{"type":"boolean"},"generation_count":{"type":"number"},"sample_count":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","description","language","voice_type","default_engine","has_personality","generation_count","sample_count","created_at","updated_at"],"additionalProperties":false}},"total":{"type":"number"}},"required":["data","total"],"additionalProperties":false}}}},"401":{"description":"`unauthorized` — Unauthorized","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["unauthorized"]}}}]}}}},"403":{"description":"`insufficient_scope` — Insufficient scope","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["insufficient_scope"]}}}]}}}},"404":{"description":"`not_found` — Not found","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["not_found"]}}}]}}}},"429":{"description":"`rate_limit_exceeded` — Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["rate_limit_exceeded"]}}}]}}}},"500":{"description":"`internal_error` — Internal error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["internal_error"]}}}]}}}},"502":{"description":"`upstream_error` — Upstream error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["upstream_error"]}}}]}}}},"503":{"description":"`service_unavailable` — Service unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["service_unavailable"]}}}]}}}}},"security":[{"apiKeyHeader":[]},{"bearerToken":[]},{"oauth2":["voice:read"]}]}},"/v1/captures":{"get":{"operationId":"listCaptures","summary":"List captures","description":"List this account's recent captures with their transcripts, most-recent first. Paginated with `limit` (1-200, default 50) and `offset`.\n\nRequires the `voice:read` scope.","tags":["Voices & history"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success.","headers":{"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"language":{"anyOf":[{"type":"string"},{"type":"null"}]},"duration_ms":{"anyOf":[{"type":"number"},{"type":"null"}]},"transcript_raw":{"type":"string"},"transcript_refined":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","source","language","duration_ms","transcript_raw","transcript_refined","created_at"],"additionalProperties":false}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"],"additionalProperties":false}}}},"400":{"description":"`invalid_request` — Invalid request","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["invalid_request"]}}}]}}}},"401":{"description":"`unauthorized` — Unauthorized","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["unauthorized"]}}}]}}}},"403":{"description":"`insufficient_scope` — Insufficient scope","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["insufficient_scope"]}}}]}}}},"404":{"description":"`not_found` — Not found","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["not_found"]}}}]}}}},"429":{"description":"`rate_limit_exceeded` — Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["rate_limit_exceeded"]}}}]}}}},"500":{"description":"`internal_error` — Internal error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["internal_error"]}}}]}}}},"502":{"description":"`upstream_error` — Upstream error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["upstream_error"]}}}]}}}},"503":{"description":"`service_unavailable` — Service unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["service_unavailable"]}}}]}}}}},"security":[{"apiKeyHeader":[]},{"bearerToken":[]},{"oauth2":["voice:read"]}]}},"/v1/generations/{generationId}":{"get":{"operationId":"getGeneration","summary":"Get a generation","description":"Look up a generation by id to poll its status (generating, completed, or failed). Returns 404 for an id that does not belong to this account.\n\nRequires the `voice:read` scope.","tags":["Voices & history"],"parameters":[{"name":"generationId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"Success.","headers":{"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"profile":{"type":"string"},"has_audio":{"type":"boolean"},"audio_url":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","profile","has_audio","audio_url","error"],"additionalProperties":false}}}},"400":{"description":"`invalid_request` — Invalid request","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["invalid_request"]}}}]}}}},"401":{"description":"`unauthorized` — Unauthorized","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["unauthorized"]}}}]}}}},"403":{"description":"`insufficient_scope` — Insufficient scope","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["insufficient_scope"]}}}]}}}},"404":{"description":"`not_found` — Not found","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["not_found"]}}}]}}}},"429":{"description":"`rate_limit_exceeded` — Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["rate_limit_exceeded"]}}}]}}}},"500":{"description":"`internal_error` — Internal error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["internal_error"]}}}]}}}},"502":{"description":"`upstream_error` — Upstream error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["upstream_error"]}}}]}}}},"503":{"description":"`service_unavailable` — Service unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["service_unavailable"]}}}]}}}}},"security":[{"apiKeyHeader":[]},{"bearerToken":[]},{"oauth2":["voice:read"]}]}},"/v1/speech":{"post":{"operationId":"createSpeech","summary":"Create speech","description":"Generate speech from text in one of this account's voice profiles. Returns immediately with a generation id and status \"generating\" — poll GET /v1/generations/{id} to retrieve the audio URL once it completes. Send an Idempotency-Key header to make a retried request safe: the same key with the same body replays the original response instead of generating a second time.\n\nRequires the `voice:generate` scope.","tags":["Generation"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"An optional client-generated key that makes a retry safe. Replaying the same key with the same body returns the ORIGINAL response byte-for-byte instead of doing the work a second time; replaying it with a different body is refused with `idempotency_key_reused`.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":10000,"description":"The text to speak."},"voice_id":{"description":"Voice profile id.","type":"string","minLength":1,"maxLength":200},"voice_name":{"description":"Voice profile name.","type":"string","minLength":1,"maxLength":200},"language":{"description":"ISO language code. Defaults to the profile's own language.","type":"string","enum":["zh","en","ja","ko","de","fr","ru","pt","es","it","he","ar","da","el","fi","hi","ms","nl","no","pl","sv","sw","tr"]}},"required":["text"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","headers":{"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"voice":{"type":"string"}},"required":["id","status","voice"],"additionalProperties":false}}}},"400":{"description":"`invalid_request` — Invalid request","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["invalid_request"]}}}]}}}},"401":{"description":"`unauthorized` — Unauthorized","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["unauthorized"]}}}]}}}},"403":{"description":"`feature_not_enabled` — Feature not enabled; `insufficient_scope` — Insufficient scope","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["feature_not_enabled","insufficient_scope"]}}}]}}}},"404":{"description":"`not_found` — Not found","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["not_found"]}}}]}}}},"409":{"description":"`idempotency_key_in_progress` — Idempotency key in progress","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["idempotency_key_in_progress"]}}}]}}}},"422":{"description":"`idempotency_key_reused` — Idempotency key reused","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["idempotency_key_reused"]}}}]}}}},"429":{"description":"`quota_exhausted` — Quota exhausted; `rate_limit_exceeded` — Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["quota_exhausted","rate_limit_exceeded"]}}}]}}}},"500":{"description":"`internal_error` — Internal error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["internal_error"]}}}]}}}},"502":{"description":"`upstream_error` — Upstream error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["upstream_error"]}}}]}}}},"503":{"description":"`service_unavailable` — Service unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["service_unavailable"]}}}]}}}}},"security":[{"apiKeyHeader":[]},{"bearerToken":[]},{"oauth2":["voice:generate"]}]}},"/v1/transcriptions":{"post":{"operationId":"createTranscription","summary":"Create a transcription","description":"Transcribe a base64-encoded audio clip to text. Returns the transcript along with the id of the capture it created, which stays retrievable through GET /v1/captures. Send an Idempotency-Key header to make a retried request safe.\n\nRequires the `voice:generate` scope.","tags":["Generation"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"An optional client-generated key that makes a retry safe. Replaying the same key with the same body returns the ORIGINAL response byte-for-byte instead of doing the work a second time; replaying it with a different body is refused with `idempotency_key_reused`.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"audio":{"type":"string","minLength":1,"maxLength":10485760,"format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$","description":"The audio clip, base64-encoded (up to 10 MiB of base64 text)."},"language":{"description":"ISO language code. Auto-detected when omitted.","type":"string","enum":["zh","en","ja","ko","de","fr","ru","pt","es","it","he","ar","da","el","fi","hi","ms","nl","no","pl","sv","sw","tr"]}},"required":["audio"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","headers":{"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"language":{"anyOf":[{"type":"string"},{"type":"null"}]},"duration_ms":{"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["id","text","language","duration_ms"],"additionalProperties":false}}}},"400":{"description":"`invalid_request` — Invalid request","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["invalid_request"]}}}]}}}},"401":{"description":"`unauthorized` — Unauthorized","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["unauthorized"]}}}]}}}},"403":{"description":"`feature_not_enabled` — Feature not enabled; `insufficient_scope` — Insufficient scope","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["feature_not_enabled","insufficient_scope"]}}}]}}}},"404":{"description":"`not_found` — Not found","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["not_found"]}}}]}}}},"409":{"description":"`idempotency_key_in_progress` — Idempotency key in progress","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["idempotency_key_in_progress"]}}}]}}}},"422":{"description":"`idempotency_key_reused` — Idempotency key reused","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["idempotency_key_reused"]}}}]}}}},"429":{"description":"`quota_exhausted` — Quota exhausted; `rate_limit_exceeded` — Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit":{"description":"This credential's current state, as an RFC 8941 structured field: `\"default\";r=<requests remaining>;t=<seconds until reset>`. Absent when the credential has no rate limit configured.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The standing policy: `\"default\";q=<requests per window>;w=<window seconds>`. Defaults to 600 requests per hour.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["quota_exhausted","rate_limit_exceeded"]}}}]}}}},"500":{"description":"`internal_error` — Internal error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["internal_error"]}}}]}}}},"502":{"description":"`upstream_error` — Upstream error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["upstream_error"]}}}]}}}},"503":{"description":"`service_unavailable` — Service unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["service_unavailable"]}}}]}}}}},"security":[{"apiKeyHeader":[]},{"bearerToken":[]},{"oauth2":["voice:generate"]}]}},"/v1/audio/{generationId}":{"get":{"operationId":"getGenerationAudio","summary":"Download generated audio","description":"Download the audio of a completed generation. This URL is not called directly — it is the `audio_url` returned by GET /v1/generations/{generationId}, already signed and ready to follow. The signature grants access to this one generation for about 15 minutes, so no API key is sent (and none is accepted): the link can be handed straight to a media player, a download, or an <audio> tag that cannot attach an Authorization header. Links expire — poll the generation again to mint a fresh one rather than storing this URL.\n\nAuthenticated by the signature in the URL, not by an API key.","tags":["Voices & history"],"parameters":[{"name":"generationId","in":"path","required":true,"description":"The generation whose audio to download.","schema":{"type":"string","minLength":1}},{"name":"sig","in":"query","required":true,"description":"The capability signature. Supplied by `audio_url`; do not construct it.","schema":{"type":"string"}}],"responses":{"200":{"description":"The generated audio, streamed through from the generation service.","content":{"audio/*":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"`unauthorized` — Unauthorized","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["unauthorized"]}}}]}}}},"404":{"description":"`not_found` — Not found","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["not_found"]}}}]}}}},"502":{"description":"`upstream_error` — Upstream error","content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["upstream_error"]}}}]}}}},"503":{"description":"`service_unavailable` — Service unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"enum":["service_unavailable"]}}}]}}}}},"security":[]}}},"components":{"securitySchemes":{"apiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"A VoiceLabs API key, sent in the `x-api-key` header. Keys begin with `vl_sandbox_`. This is the simplest way to authenticate and is what most callers should use.\n\nCreate one in the developer console at https://voicelabs.now/connections, on the **API keys** tab, choosing the scopes it carries. A key does exactly what its scopes allow: one without `voice:generate` is answered `403 insufficient_scope` on the generation operations and cannot spend the account's allowance. The secret is shown once, at creation; revoking a key takes effect on its very next request."},"bearerToken":{"type":"http","scheme":"bearer","description":"The same API key, sent as `Authorization: Bearer <key>` for clients whose HTTP layer only supports bearer auth. An OAuth 2.1 access token is also accepted here — the two are told apart by shape, never by guessing."},"oauth2":{"type":"oauth2","description":"OAuth 2.1 (authorization code with PKCE and dynamic client registration) — the same authorization server the VoiceLabs MCP server uses. Use this when an application acts on behalf of ITS OWN users, so each of them consents and can revoke independently. Use an API key when the application acts on behalf of the account that issued the key.","flows":{"authorizationCode":{"authorizationUrl":"https://app.voicelabs.now/api/auth/oauth2/authorize","tokenUrl":"https://app.voicelabs.now/api/auth/oauth2/token","refreshUrl":"https://app.voicelabs.now/api/auth/oauth2/token","scopes":{"voice:generate":"Generate speech and transcribe audio on your behalf.","voice:read":"Read your voices, profiles, and past generations."}}}}},"schemas":{"Problem":{"type":"object","description":"An RFC 9457 problem document. `code` is an extension member and is the field to branch on: it is a stable enum token, whereas `detail` is human-readable prose that may be reworded, and `status` alone cannot distinguish two problems that share it.","properties":{"type":{"type":"string","format":"uri","description":"A URI identifying the problem type, under https://voicelabs.now/errors/."},"title":{"type":"string","description":"A short, stable summary of the problem type."},"status":{"type":"integer","description":"The HTTP status code, repeated in the body."},"detail":{"type":"string","description":"A human-readable explanation of this occurrence."},"instance":{"type":"string","description":"The request path this problem occurred on."},"code":{"type":"string","description":"The stable machine-readable error code. Branch on this.","enum":["feature_not_enabled","idempotency_key_in_progress","idempotency_key_reused","insufficient_scope","internal_error","invalid_request","method_not_allowed","not_found","quota_exhausted","rate_limit_exceeded","service_unavailable","unauthorized","upstream_error"]},"required_scope":{"type":"string","description":"On `insufficient_scope`: the scope the credential was missing."},"settings_url":{"type":"string","format":"uri","description":"On quota and entitlement problems: where the account owner resolves it. Present only on problems a human can actually fix from a settings page."}},"required":["type","title","status","detail","code"]}}},"externalDocs":{"description":"VoiceLabs developer documentation","url":"https://voicelabs.now/developers"}}