REST API

POST

/api/v1/audio/speech

Text to speech. Send text, get the audio file back in the response body. The request follows OpenAI's audio.speech.create, so the OpenAI SDKs work with the Railwail base URL.

URL
https://railwail.com/api/v1/audio/speech
Key scope
audio
Returns
audio bytes (mp3 default)
Billing
per 1,000 characters or per run

Request body

JSON. Unknown fields are rejected with 400 validation_failed.

modelrequired
string
Model slug, e.g. openai-tts-1 or openai-tts-1-hd.
inputrequired
string
The text to speak, up to 50,000 characters. Per-character models bill on its length.
voice
stringmodel-dependent
Voice name, e.g. alloy for the OpenAI models. Each model page lists its voices.
voice_id
stringmodel-dependent
Voice id for models that address voices by id.
response_format
string
mp3, opus, aac, flac, wav or pcm.Default mp3
speed
numbermodel-dependent
0.25–4.
language
stringmodel-dependent
Language hint for multilingual models.
stability / similarity_boost
numbermodel-dependent
0–1, for models that expose these voice controls.
voice_sample
stringvoice-cloning models
Voice cloning: the url of a reference clip you uploaded with POST /api/v1/audio/uploads. Only your own uploads are accepted.
consent
boolean
Required with voice_sample: true confirms that you may use this voice (your own voice or the speaker's permission).
user
string
Your own end-user id, stored with the job.

OpenAI vs. other speech models

The OpenAI TTS models run directly. Other speech models in the catalog run through this endpoint when their only required input is the text; the list below contains exactly those.

Voice cloning

Models whose page shows a reference-voice input (chatterbox, qwen3-tts, openvoice-v2) speak the text in the voice of a short clip. Only clone your own voice or a voice you have permission to use; see the terms of service. Two steps:

1. Upload the clip: POST /api/v1/audio/uploads, multipart field file, key scope audio. MP3, WAV, WebM or Ogg, at most 10 MB and 60 seconds, 20 uploads per hour. The answer holds the clip's url; the file is deleted after 24 hours.

2. Pass that url as voice_sample together with consent: true. Without consent the request is refused with 400 voice_consent_required and nothing is charged. The job stores the url and the consent, never the audio.

# 1. upload the reference clip
curl https://railwail.com/api/v1/audio/uploads \
  -H "Authorization: Bearer $RAILWAIL_API_KEY" \
  -F "[email protected]"
# -> { "object": "audio.upload", "url": "https://.../audio-uploads/...wav", "duration_sec": 12.4, ... }

# 2. speak with that voice
curl https://railwail.com/api/v1/audio/speech \
  -H "Authorization: Bearer $RAILWAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "xtts-v2",
    "input": "Hello, this is my cloned voice.",
    "voice_sample": "<url from step 1>",
    "consent": true
  }' \
  --output cloned.wav

Examples

Key in RAILWAIL_API_KEY, with the audio scope. Each example writes speech.mp3.

// ESM: save as speech.mjs
import fs from "node:fs/promises";
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.RAILWAIL_API_KEY,
  baseURL: "https://railwail.com/api/v1",
});

const speech = await client.audio.speech.create({
  model: "openai-tts-1",
  voice: "alloy",
  input: "Hello from Railwail. This sentence was spoken by a text-to-speech model.",
});
await fs.writeFile("speech.mp3", Buffer.from(await speech.arrayBuffer()));

Response

HTTP 200 with the audio as the body; Content-Type matches response_format (for example audio/mpeg for mp3). Errors come back as JSON like every other endpoint. The railwail npm SDK has no speech method; use the OpenAI SDK or plain HTTP.

Models you can call here

Errors

StatusCodeWhat to do
400validation_failedA field is unknown or out of range.
400voice_consent_requiredvoice_sample without consent: true.
400invalid_voice_samplevoice_sample is not the url of your own upload from /api/v1/audio/uploads.
400voice_cloning_unsupportedThe model has no reference-voice input (message: model does not support voice cloning).
400voice_sample_requiredThe model only speaks in a cloned voice; send voice_sample and consent.
402insufficient_creditsTop up on the billing page.
402monthly_limit_exceededYour monthly spending limit is reached.
403insufficient_scopeThe key lacks the audio scope.
404model_not_foundCheck the slug in the list above.
429trial_limitTrial rules (at most 2 credits per run until the first top-up).
503model_unavailableNo verified price or the provider is not reachable; pick another model.

All codes: Error codes.