Building Blocks / Voice
Text-to-Speech
Turn text into a recording with a stock or cloned voice.
This block is the Text-to-speech API. The full product reference is the Text-to-speech API reference. This page is the short version: when to use it, one working request, and its limits. There is no widget to embed.
When to use this vs REST
This block is the REST API. Call it from your server with your API key, or from a page with a site token that has the voice scope. There is no browser widget.
Do not rebuild
- Voice hosting or a voice picker. List voices with GET /voice/public/voices.
- Audio storage. The response carries a playback URL with an expiry.
Drop-in
POST text and a voice_id. List voices with GET /voice/public/voices. There is no browser widget for this block; a page can call the same route with a site token that has the voice scope.
curl -X POST https://api-v2.dropcowboy.com/voice/public/tts/synthesize \
-H "x-key: $KEY" -H "x-secret: $SECRET" \
-H "Content-Type: application/json" \
-d '{"text":"Hello from Acme","voice_id":"e2b7c9d4-3f1a-4c8e-9b6d-7a5f0e1c2d3b"}'
From Node on your server:
async function synthesizeGreeting() {
const audio = await fetch('https://api-v2.dropcowboy.com/voice/public/tts/synthesize', {
method: 'POST',
headers: { 'x-key': process.env.DC_KEY, 'x-secret': process.env.DC_SECRET, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: 'Hi, this is Alex from Acme. Leave a message.', voice_id: 'e2b7c9d4-3f1a-4c8e-9b6d-7a5f0e1c2d3b' })
}).then(function (r) { return r.json(); });
return audio.data.audio_url;
}
With Twilio
Synthesize on your server, then hand Twilio the audio URL. No widget and no site token in the call flow.
const VoiceResponse = require('twilio').twiml.VoiceResponse;
app.post('/twilio/voice', async function (req, res) {
const audio = await fetch('https://api-v2.dropcowboy.com/voice/public/tts/synthesize', {
method: 'POST',
headers: { 'x-key': process.env.DC_KEY, 'x-secret': process.env.DC_SECRET, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: 'Hi, this is Alex from Acme. Leave a message.', voice_id: 'e2b7c9d4-3f1a-4c8e-9b6d-7a5f0e1c2d3b' })
}).then(function (r) { return r.json(); });
const twiml = new VoiceResponse();
twiml.play(audio.data.audio_url);
res.type('text/xml').send(twiml.toString());
});
From a browser
Mint a site token with the voice scope on your server, then call the same route with Authorization: Bearer <token>.
# On your server: trade your API key (needs numbers:write) for a site token. 1 hour max.
curl -s -X POST https://api-v2.dropcowboy.com/phone/public/embed/token \
-H "x-key: $KEY" -H "x-secret: $SECRET" \
-H "Content-Type: application/json" \
-d '{"site_id":"YOUR_SITE_ID","scope":["voice"],"ttl_seconds":900}'
JS API / HTML tag
No browser widget and no HTML tag. Routes:
| Route | Body | What it does |
|---|---|---|
POST /voice/public/tts/synthesize |
{ text, voice_id, language } |
Returns audio metadata with a playback URL. Scope voice:send. |
GET /voice/public/voices |
?include_pro_voices=true |
Stock and team voices you can pass as voice_id. Scope media:read. |
Auth and scopes
API key and secret on your server (voice:send). From a browser, send Authorization: Bearer with a site token minted with the voice scope.
Site token scope: voice. Mint it with POST https://api-v2.dropcowboy.com/phone/public/embed/token using an API key with numbers:write. Tokens last up to one hour.
Limits
- Each call checks prepaid balance and returns 402 when funds are short.
- A voice must be ready before it can speak; a voice still in checkout returns 402.
- The audio_url expires at expires_at. Copy the file if you need it longer.
Related REST
Routes are on https://api-v2.dropcowboy.com.
- Text-to-speech API reference - full reference
- POST /voice/public/tts/synthesize
- GET /voice/public/voices