Senova API
API reference
Senova's models over HTTPS, in both OpenAI and Anthropic request formats, so existing SDKs work by changing the base URL and key. Create a key in the console and check your API credit under Billing (self-serve purchases are coming soon; contact us to add credit).
Authentication
Base URL https://senovasys.com/v1. Send your key as Authorization: Bearer sk-sen-… or x-api-key: sk-sen-…. Keys are shown once; Senova stores only a hash. Keep keys on your server: the API doesn't accept browser requests from other sites. Revoke a leaked key in the console; it stops working immediately.
Live, test and publishable keys
- Live (
sk-sen-…): for your servers. Works anywhere and is paid from your prepaid API credit at the prices below. - Test (
sk-sen-test-…): for building on your own computer, free to create on any plan. Calls spend your plan's usage, like chatting in Senova, not credit. A request that carries anOrigin(orReferer) must come from local development:localhost,127.0.0.1,[::1],*.localhostor*.test; any other site is refused with403 test_key_origin. Scripts and servers on your machine send no origin and are allowed. Test keys are capped at 20 requests a minute, 200 requests a day and 2,048 output tokens per reply, can't use voice, and stop at your plan's limits, so they can't carry production traffic. Switch to a live key when you ship. - Publishable (
pk-sen-…): safe to put in a web page. It only runs one agent's website widget, only from the sites you list on the key (CORS answers no other site), with its own per-minute and monthly caps. It can't call/v1. Widget traffic from your listed live sites is paid from prepaid credit; listed local development sites use your plan.
POST /v1/chat/completions (OpenAI format)
curl https://senovasys.com/v1/chat/completions \
-H "Authorization: Bearer $SENOVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"suite","messages":[{"role":"user","content":"Hello"}],"max_tokens":512}'Fields: model, messages (roles system, developer, user, assistant; text content), max_tokens or max_completion_tokens, temperature (0–2), top_p, stop (up to 4), stream. Streaming sends chat.completion.chunk events, a final chunk with usage, then data: [DONE]. Works with the OpenAI SDKs:
from openai import OpenAI
client = OpenAI(base_url="https://senovasys.com/v1", api_key=os.environ["SENOVA_API_KEY"])
reply = client.chat.completions.create(model="suite", messages=[{"role": "user", "content": "Hello"}])POST /v1/messages (Anthropic format)
curl https://senovasys.com/v1/messages \
-H "x-api-key: $SENOVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"suite","max_tokens":512,"system":"Be brief.","messages":[{"role":"user","content":"Hello"}]}'Fields: model, max_tokens (required), system, messages (user/assistant, text), temperature (0–1), top_p, stop_sequences, stream. Streaming sends message_start, content_block_delta, message_delta and message_stop events. Text only for now: image and tool blocks are rejected.
Answering from your knowledge bases
Both chat endpoints accept knowledge_base_ids (up to 10), or the same inside a senova object with cite (default true). Senova searches those knowledge bases for the last user message, as the person who created the key, and gives the passages to the model as reference data with your "How to answer" instructions. The key needs the knowledge scope, and each id must be one of its creator's own knowledge bases (others return 404). Each request counts one question against your plan's knowledge allowance.
curl https://senovasys.com/v1/chat/completions \
-H "Authorization: Bearer $SENOVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"suite","messages":[{"role":"user","content":"What is the refund window?"}],
"senova":{"knowledge_base_ids":["<knowledge base id>"],"cite":true}}'The reply carries senova.citations: [{"n":1,"title":"Policies.pdf, p. 3","knowledge_base_id","knowledge_base","source","url","excerpt"}]. The answer cites them as [1], [2]. When streaming, citations arrive on the final chat.completion.chunk (OpenAI format) or the message_delta event (Anthropic format).
Website widget
Put an agent on your own site with one line before </body>. Make it from a knowledge base (Knowledge, then Put on your website), or from an agent with its website widget on and a publishable key from the console:
<script src="https://senovasys.com/a/<agent address>/widget.js" data-key="pk-sen-…" async></script>
The bubble takes your colour and greeting, answers with its sources, and lets visitors leave an email to talk to a person, which is sent to you. It only works on the sites listed on the key. Your site's Content-Security-Policy needs script-src and connect-src to allow https://senovasys.com.
GET /v1/models and prices
| id | Model | Input / 1M tokens | Output / 1M tokens | Context |
|---|---|---|---|---|
| prelude | Prelude 1 | $0.20 | $0.80 | 32,000 |
| suite | Suite 1 | $0.25 | $2.40 | 64,000 |
| fugue | Fugue 1 | $0.15 | $0.30 | 64,000 |
| symphony | Symphony 1 | $1.05 | $7.50 | 64,000 |
Each request is charged from your prepaid credit by the tokens it used. Prices may change with notice; the console shows what each key spent.
Voice: /v1/audio
Text to speech (POST /v1/audio/speech), speech to text (POST /v1/audio/transcriptions) and the voice list (GET /v1/audio/voices), OpenAI-compatible, for keys with the audio scope. Examples, voices, limits and prices: voice API docs.
Errors
/v1/chat/completions returns {"error":{"message","type","code"}}; /v1/messages returns {"type":"error","error":{"type","message"}}. Status codes: 400 invalid request, 401 bad key, 402 credit too low, 403 key scope or suspended organization, 404 unknown model, 413 too large, 429 rate or spend limit, 502 the model didn't finish (retry), 503 at capacity (retry with backoff).
Rate and spend limits
Each key has a requests-per-minute limit (default 60) and an optional monthly spend limit; each organization has an overall requests-per-minute limit (default 120, set under Logs). Test keys are held to 20 a minute and 200 a day. Publishable keys start at 30 a minute and $25 a month. Requests stop when credit runs out. Set a low-credit alert to get a usage.threshold webhook.
Webhooks
Add HTTPS endpoints under Webhooks. Events: usage.threshold, key.created, key.revoked (and webhook.test from the console). Body: {"id","type","created","data"}. Senova retries failures after 1, 5, 30, 120, 360, 720 and 1440 minutes; use id to ignore duplicates. Respond with any 2xx within 10 seconds. Redirects aren't followed.
Verify every delivery: the Senova-Signature header is t=<unix time>,v1=<hex HMAC-SHA256> over <t>.<raw body> with your endpoint's signing secret. Reject it if the HMAC differs or t is more than 5 minutes old.
import crypto from "node:crypto"
export function verifySenova(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")))
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex")
return parts.v1?.length === expected.length && crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))
}Data handling
Prompts and replies are sent to the model providers that run Senova's models to produce the answer. Senova doesn't keep API request bodies unless you turn on request logging (1–30 days, then deleted). Usage records (tokens, model, time, key) are kept for billing. See the Privacy Policy.
Senova