Add speech to a web app
A server route that speaks text and a page that plays it, without exposing your API key.
Your API key must stay on a server. The browser asks your server to speak a sentence; the server calls Speakvora and returns the audio link.
1. Server route (Node 18+, Express)
server.js
import express from "express";
const app = express(); app.use(express.json());
app.post("/api/speak", async (req, res) => {
const text = String(req.body.text || "").slice(0, 500);
const r = await fetch("https://speakvora.com/api/v1/speak", {
method: "POST",
headers: { "x-api-key": process.env.SPEAKVORA_KEY, "content-type": "application/json" },
body: JSON.stringify({ text, voice: "af_heart", lang: "en" }),
});
const j = await r.json();
res.status(r.status).json(r.ok ? { url: j.url } : { error: j.error });
});
app.listen(3000);2. Browser
page.js
async function say(text) {
const r = await fetch("/api/speak", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ text }) });
const j = await r.json();
if (!r.ok) return console.error(j.error);
new Audio(j.url).play(); // must follow a user gesture such as a click
}
document.querySelector("#go").onclick = () => say("Welcome back.");3. Handle the errors that matter
402 free_allowance_used: the free 100,000 characters are spent.429 rate_limited: waitretry_after_secondsand retry.404 not_in_library/voice_not_available_for_text: that voice only plays library sentences; choose a live voice or a library line.
Notes
- New sentences take seconds; repeats are quick. Show a loading state.
- Cache the returned link in your own app if you replay the same line, and keep the returned URL rather than rebuilding it.
- For voice agents only, Speakvora can mint a browser token (10 minutes, one agent). See agents.