Authentication and errors
Authentication and errors
Authenticate with a server-side API key. Use request IDs to trace failures and idempotency keys to retry an operation without starting it twice.
Updated October 18, 2026 · API version 1
Send a server-side Bearer key
Test keys begin with vm_test_ and live keys begin with vm_live_. Send the complete key in the Authorization header. Never embed either key in browser JavaScript, a mobile application bundle, a public repository, logs, analytics, or a URL.
Authorization: Bearer vm_test_…
Content-Type: application/jsonDeveloper generation routes do not allow browser CORS. Call the API from infrastructure you control, then return only the result your client needs.
Use idempotency for safe retries
Synchronous POST endpoints accept an optional Idempotency-Key containing 8–128 printable ASCII characters. Production asynchronous Basic POST /v1/speech/jobs requires one; asynchronous Premium remains limited to development and staging. Keep the same key only when retrying the exact same endpoint and JSON payload. VowelMarks retains the completed result or job identity for 24 hours.
- Same key and payload: replay the successful result without a second usage charge.
- Same key with a different payload:
409 idempotency_conflict. - A duplicate while the first request is still running: retryable
409 request_in_progress. - A failed validation or generation does not consume usage.
Read the rate-limit headers
Successful authenticated JSON responses include RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. The published limit is shared by every key in the same organization and environment, so adding keys does not multiply capacity. Authenticated malformed requests, idempotent replays, and job create/read/stream/cancel requests still count toward requests per minute. This request limit is an API admission ceiling; Premium Speech also depends on the speech provider's separate capacity.
X-Request-Id: 95b…
RateLimit-Limit: 20
RateLimit-Remaining: 18
RateLimit-Reset: 41RateLimit-Reset is the number of seconds until the current window resets, not a Unix timestamp. On a retryable failure, Retry-After tells your client how many seconds to wait. Neither header describes remaining speech minutes; read those from GET /v1/usage.
Handle the structured error envelope
Every API error has a request ID plus a stable machine-readable code. Branch on error.code and error.retryable rather than comparing message text. Include X-Request-Id when contacting VowelMarks.
{
"request_id": "95b…",
"error": {
"code": "service_unavailable",
"message": "The request could not be completed.",
"category": "service",
"action": "Retry the request later.",
"retryable": true
}
}| HTTP status | Meaning | What to do |
|---|---|---|
400 | Invalid JSON, input, or options | Correct the request using error.code and error.action. |
401 | Missing, invalid, or revoked API key | Check the full Bearer key and replace it if needed. |
402 | Insufficient text or speech allowance | Check usage and the approved plan. Do not loop on the same request. |
403 | Inactive access or insufficient scope | Review the organization, entitlement, and key scopes. |
404 | Unknown route or inaccessible resource | Check the URL, organization, and environment. |
409 | Request conflict | For request_in_progress, wait and retry with the same key. For idempotency_conflict, restore the original payload or use a new key for a genuinely new operation. |
413 | Request body too large | Reduce both the text and serialized JSON size. |
429 | Request rate exceeded | Wait for Retry-After; do not send parallel retries. |
5xx | Service or generation failure | Read error.retryable. Some unavailable capabilities are deliberately non-retryable. |
The table summarizes common responses, not every error code. The returned error.action gives the next step for that specific failure.
Set a complete-response deadline
Some processing origins sleep while idle, so the first request after an idle period can spend tens of seconds waiting for the service to wake. Warm latency is usually lower. Input length, the selected capability, upstream provider time, and capacity can add more variation. API v1 does not publish a latency or availability SLA.
Configure both a connection timeout and a deadline that remains active until the complete JSON response body has been read. A practical starting point is 120 seconds for text generation. The synchronous speech route may need several minutes for long passages; allow up to 15 minutes for a maximum-size request or split it into smaller sections. Tune these budgets from your own measurements.
If your deadline expires after the request was sent, treat the outcome as unknown. Do not create a new idempotency key. Wait briefly, then retry the same endpoint, body, and key so a completed result can replay safely or an in-progress request can report its state.
Retry policy
- Retry only when
retryableis true. - Honor
Retry-Afterand add random jitter before the next attempt. - Reuse the original
Idempotency-Keyand exact payload. - Do not retry validation, authentication, authorization, or quota errors until the stated action has been taken.
- Keep the deadline active while reading the complete response body, not only until response headers arrive.
- A network error or client timeout has an unknown outcome. Retry with the original key and exact payload.