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: wait retry_after_seconds and 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.

Next: combine reusable phrases with live speech.