Docs
One endpoint. Send what your user said, get back what to say. There is no SDK to install and nothing to keep updated — if you can make an HTTP request, you can use Vesper.
1Quick start
Create a key in the console, then make one request. That is the whole integration.
# Ask her something
curl -X POST https://vesper-api.danielflowers2505.workers.dev/v1/say \
-H "Authorization: Bearer vsk_live_…" \
-H "Content-Type: application/json" \
-d '{"message":"what have I missed?"}'
# → {"text":"Not much. A couple of messages from Sarah, and your
# four o'clock reminder.","cached":false}JavaScript
const r = await fetch("https://vesper-api.danielflowers2505.workers.dev/v1/say", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.VESPER_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ message: userSaid })
});
if (!r.ok) {
// She is unavailable. Carry on without her rather than breaking.
return fallbackReply();
}
const { text } = await r.json();2Authentication
Every request carries your key as a bearer token. Nothing else is needed — no signing, no session, no expiry to refresh.
Keys are secrets. They belong on your server, in an environment variable. Never ship one inside a mobile app or a web page — anyone who unpacks your bundle has your key and spends your allowance.
A vsk_test_ key behaves identically but
never spends and never speaks aloud. Use it in development.
3POST /v1/say
Request body
| Field | Type | Notes |
|---|---|---|
| message | string | Required. What your user said. Up to 2,000 characters. |
| voice | boolean | Ask for spoken audio. Returns 501 today — see below. |
Response
| Field | Type | Notes |
|---|---|---|
| text | string | What she says. One or two sentences, written to be spoken. |
| cached | boolean | Whether the audio came from cache. Always false without voice. |
She is told to answer in British English, in one or two short sentences, with no lists, markdown or emoji — because it is meant to be heard, not read. What you set under How she appears in the console shapes her name, her manner and what she knows about your users.
4Errors
Every error is JSON with an error code
you can branch on and a message written
for a human.
| Status | Code | What happened |
|---|---|---|
| 400 | no_message | You did not send a message. |
| 400 | message_too_long | Over 2,000 characters. |
| 400 | bad_json | The body was not valid JSON. |
| 401 | no_key | No bearer token, or it is malformed. |
| 401 | bad_key | The key is not recognised. |
| 403 | key_revoked | That key was revoked. Create another. |
| 403 | account_suspended | Get in touch. |
| 429 | allowance_used | Month's allowance spent. Resets on the 1st. |
| 429 | upstream_quota | Busy. Retry shortly. |
| 501 | voice_unavailable | Spoken replies are not being served yet. |
| 502 | upstream | She could not answer. Retry once. |
| 503 | unavailable | We could not check your key. Retry. |
Treat any non-200 as “carry on without her”. An assistant that breaks your app when it is unavailable is a design problem we cannot fix from our side.
5Allowances
Your plan includes a monthly allowance, counted per calendar month and reset on the 1st, London time. Usage appears in the console the moment a request lands.
| Plan | Spoken | Text |
|---|---|---|
| Pilot | 5,000 | 50,000 |
| Studio | 25,000 | 250,000 |
| Platform | 75,000 | 1,000,000 |
| Enterprise | 500,000 | 5,000,000 |
Past your allowance you get 429. If you have set a spend cap, she refuses rather than exceeding it — so write your integration to cope with being told no.
6Spoken replies
Sending "voice": true currently returns
501 voice_unavailable. Text generation is
live; serving her synthesised audio through this endpoint is not yet.
Until it is, ask for text and speak it with the device's own voice.
When spoken replies arrive, the response simply gains an
audio field — base64 MP3 —
and nothing you have written will break.
Status says when that changes.
7Health check
No key needed. Returns
{"ok":true} when the service is up. Safe
to poll from your own monitoring.
8Doing it properly
- Call from your server, never from the client. A key in an app bundle is a key in somebody else's hands.
- Set a timeout of about five seconds and fall back rather than leaving a user waiting.
- Retry once on 502 and 503, with a short pause. Never retry a 4xx — it will fail identically.
- Send only what she needs. She answers what somebody said; she does not need their name, location or payment details.
- Do not depend on exact wording. She improves over time, and her phrasing will change.
- Use a test key in development so your staging traffic never touches your allowance.