sphoroVOICEdocs
Markdown

SDKs

The API is plain JSON over HTTPS and every language can call it directly. Where a client saves you real work, it is because of the parts that are not plain requests: the audio graph in a browser, signature verification, retries and idempotency.

What you can install today

ClientInstallFor
Node
@sphoro/voice
npm i @sphoro/voiceServer-side: agents, calls, knowledge, webhooks, minting call tokens.
Browser
@sphoro/voice-web
npm i @sphoro/voice-webTalking to an agent from a page: microphone, playback, the realtime protocol, barge-in.
Python, Go and Java clients exist and are not on a public registry. They are handed out per account rather than published, so this page does not print an install line that would fail. Ask us if you want one — and in the meantime, the API is nine endpoints for most integrations and a hand-written client is an afternoon.

Node

Shell
npm install @sphoro/voice
Node
import { Sphoro } from "@sphoro/voice";

const sphoro = new Sphoro({ apiKey: process.env.SPHORO_API_KEY, baseUrl: "https://voice.sphoro.com" });

const agent = await sphoro.agents.create({
  name: "Acme Clinic reception",
  languages: [{ code: "en-IN", greeting: "Thanks for calling Acme Clinic.",
                system_prompt: "You are the receptionist for Acme Clinic…" }],
});

const call = await sphoro.calls.create({
  agentId: agent.id,
  to: "+919876543210",
  callVariables: { first_name: "Priya" },
});

console.log(call.id, call.status);   // call_…  queued

Verifying a webhook

The one piece of this that is genuinely easy to get subtly wrong by hand — the timestamp is part of what is signed, and the comparison has to be constant-time.

Node
import { verifyWebhook } from "@sphoro/voice";

app.post("/hooks/sphoro", express.raw({ type: "application/json" }), (req, res) => {
  // The RAW body. Re-serialised JSON will not verify.
  const event = verifyWebhook(req.body, req.headers, process.env.SPHORO_WEBHOOK_SECRET);
  if (event.type === "call.analysed") {
    save(event.call_id, event.data.summary, event.data.extracted);
  }
  res.sendStatus(200);
});

See webhooks for the scheme and the traps.

Browser

Shell
npm install @sphoro/voice-web
Node
import { connect } from "@sphoro/voice-web";

// The url comes from YOUR server, which mints it with your API key.
// Never ship an API key to a page.
const { url } = await fetch("/api/voice-token", { method: "POST" }).then(r => r.json());

const call = await connect({ url });
call.on("state", s => setIndicator(s));            // listening | thinking | speaking
call.on("transcript", t => appendLine(t.role, t.text));
call.on("ended", e => showSummary(e.end_reason));

document.querySelector("#hangup").onclick = () => call.end();

It handles the microphone, playback, the wideband format negotiation, barge-in and the heartbeat — all of which are on the list of things a hand-written client gets wrong. See talk from a browser for the server half, and the realtime protocol for what is underneath.

Without a bundler

The browser client is also served by this deployment, so a page can load it with a plain script tag and no build step at all. The tag to paste, and the one server route behind it, are on talk from a browser.

GET/v1/embed/

Writing your own client

Perfectly reasonable, and for a server integration usually less work than evaluating a dependency. Four things to implement, in order of how much they matter:

  1. Send Idempotency-Key on every POST /v1/calls. Without it a retry places a second call to a real person.
  2. Retry 429 and 5xx with backoff; never retry a 4xx. The response says how long to wait.
  3. Verify webhook signatures against the raw body.
  4. Follow pagination rather than assuming one page. See using your API key.
Generate one instead. This deployment serves its own OpenAPI description at openapi.json, which most generators take directly. It is produced by the running server, so it describes the version you are actually talking to. See API reference.

What every client does the same way

Base URLhttps://voice.sphoro.com, overridable, so one build can point at more than one deployment.
CredentialAn API key for anything server-side; a short-lived call token for anything a browser holds.
ErrorsRaised with the status, the machine-readable code, and the field-level problems where there are any.
IdentifiersOpaque strings. Store them whole.