PageSourceSearch

https://app.anvevoice.app/assets/DeveloperApiReference-kF4Aw43r.js

js anvevoice.app collected 2026-10-02 03:41:06 UTC 36,757 bytes, 97 lines download raw bytes

1import{c as k,r as y,j as e,H as R,L as S,B as F,X as C,g as x}from"./index-BKInu8Gb.js";import{B as N}from"./badge-kNeQxzMw.js";import{C as q,d as M}from"./card-BP0uVGrg.js";import{u as I}from"./use-mobile-B56nXrIv.js";import{A as E}from"./arrow-left-0nCR_9p3.js";import{B as T}from"./book-open-B7aoqn43.js";import{M as O}from"./menu-d-k1676P.js";import{C as A}from"./chevron-right-nAIXCcl1.js";import{K as L}from"./key-BFhf5D2A.js";import{S as W}from"./shield-check-BVSk9h-w.js";import{G as H}from"./gauge-4O4fAN_Z.js";import{C as G}from"./circle-alert-CzrNrOzW.js";import{V}from"./volume-2-B0eIpVPc.js";import{M as z}from"./mic-B5-9VpyI.js";import{R as B}from"./radio-K3awUsMR.js";import{Z as U}from"./zap-Pd2rkksN.js";import{C as D}from"./clock-C42o-YdA.js";/**
2 * @license lucide-react v0.462.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const K=k("List",[["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M3 18h.01",key:"1tta3j"}],["path",{d:"M3 6h.01",key:"1rqtza"}],["path",{d:"M8 12h13",key:"1za7za"}],["path",{d:"M8 18h13",key:"1lx6n3"}],["path",{d:"M8 6h13",key:"ik3vkj"}]]);/**
7 * @license lucide-react v0.462.0 - ISC
8 *
9 * This source code is licensed under the ISC license.
10 * See the LICENSE file in the root directory of this source tree.
11 */const J=k("Speaker",[["rect",{width:"16",height:"20",x:"4",y:"2",rx:"2",key:"1nb95v"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["circle",{cx:"12",cy:"14",r:"4",key:"1jruaj"}],["path",{d:"M12 14h.01",key:"1etili"}]]),_=[{id:"overview",label:"Overview",icon:T},{id:"authentication",label:"Authentication",icon:L},{id:"scopes-plans",label:"Scopes & Plans",icon:W},{id:"rate-limits",label:"Rate limits & quotas",icon:H},{id:"errors",label:"Error format",icon:G},{id:"endpoint-voices",label:"Voices",icon:K},{id:"endpoint-tts",label:"Text-to-Speech",icon:V},{id:"endpoint-stt",label:"Speech-to-Text",icon:z},{id:"endpoint-stt-stream",label:"Speech-to-Text (stream)",icon:B},{id:"endpoint-live",label:"Live (conversational)",icon:U},{id:"voice-catalog",label:"Voice catalog",icon:J},{id:"changelog",label:"Changelog",icon:D}];function u({id:t,children:r}){return e.jsxs("div",{className:"mt-16 mb-6 scroll-mt-24 first:mt-0",id:t,children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-1 h-7 rounded-full bg-gradient-to-b from-primary to-secondary"}),e.jsx("h2",{className:"text-2xl font-bold text-foreground tracking-tight",children:r})]}),e.jsx("div",{className:"mt-3 h-px bg-gradient-to-r from-border via-border/50 to-transparent"})]})}function h({children:t,id:r}){return e.jsxs("h3",{id:r,className:"text-lg font-semibold text-foreground mt-10 mb-3 flex items-center gap-2",children:[e.jsx(A,{className:"h-4 w-4 text-primary/60"}),t]})}function n({children:t}){return e.jsx("h4",{className:"text-xs font-semibold text-muted-foreground uppercase tracking-wider mt-5 mb-2",children:t})}function a({children:t}){return e.jsx("p",{className:"text-muted-foreground leading-[1.8] mb-5 text-[15px]",children:t})}function s({children:t}){return e.jsx("code",{className:"px-1.5 py-0.5 rounded-md bg-muted/60 border border-border/50 text-[13px] font-mono text-foreground/90",children:t})}function i({code:t,language:r="bash"}){return e.jsxs("div",{className:"relative group mb-5",children:[e.jsxs("div",{className:"absolute top-0 left-0 right-0 h-8 bg-muted/80 rounded-t-xl border border-b-0 border-border/60 flex items-center px-3 gap-1.5",children:[e.jsx("div",{className:"w-2.5 h-2.5 rounded-full bg-destructive/40"}),e.jsx("div",{className:"w-2.5 h-2.5 rounded-full bg-warning/40"}),e.jsx("div",{className:"w-2.5 h-2.5 rounded-full bg-success/40"}),e.jsx("span",{className:"ml-2 text-[10px] uppercase tracking-wider text-muted-foreground/60 font-medium",children:r})]}),e.jsx("pre",{className:"bg-card/80 border border-border/60 rounded-xl pt-11 pb-4 px-4 overflow-x-auto text-[13px] font-mono leading-relaxed text-foreground/90 backdrop-blur-sm",children:e.jsx("code",{children:t})})]})}function d({headers:t,rows:r}){return e.jsx("div",{className:"overflow-x-auto mb-6 rounded-xl border border-border/60 bg-card/40 backdrop-blur-sm",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsx("tr",{className:"border-b border-border/60 bg-muted/30",children:t.map((o,c)=>e.jsx("th",{className:"p-3.5 text-left font-semibold text-foreground text-xs uppercase tracking-wider",children:o},c))})}),e.jsx("tbody",{className:"text-muted-foreground text-sm",children:r.map((o,c)=>e.jsx("tr",{className:"border-b border-border/30 last:border-0 hover:bg-muted/20 transition-colors align-top",children:o.map((g,f)=>e.jsx("td",{className:x("p-3.5",f===0&&"font-medium text-foreground
11/80"),children:g},f))},c))})]})})}function v({variant:t="info",children:r}){const o={info:"💡",warning:"⚠️",tip:"✨"}[t],c={info:"border-primary/20 bg-primary/5",warning:"border-warning/20 bg-warning/5",tip:"border-success/20 bg-success/5"}[t];return e.jsxs("div",{className:x("rounded-xl border p-4 mb-5 flex items-start gap-3",c),children:[e.jsx("span",{className:"text-base mt-0.5",children:o}),e.jsx("div",{className:"text-sm text-muted-foreground leading-relaxed",children:r})]})}function w({method:t}){const r={GET:"bg-blue-500/10 text-blue-500 border-blue-500/20",POST:"bg-primary/10 text-primary border-primary/20",WSS:"bg-amber-500/10 text-amber-500 border-amber-500/20"};return e.jsx(N,{className:x("font-mono font-semibold border",r[t]),children:t})}function b({id:t,method:r,path:o,title:c,blurb:g}){return e.jsxs(e.Fragment,{children:[e.jsx(u,{id:t,children:c}),e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx(w,{method:r}),e.jsx("span",{className:"font-mono text-sm text-foreground/90",children:o})]}),e.jsx(a,{children:g})]})}function j({items:t}){return e.jsx(q,{className:"mb-5 bg-card/40 border-border/60",children:e.jsx(M,{className:"grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-3 py-4",children:t.map(r=>e.jsxs("div",{className:"flex items-baseline gap-2 text-sm",children:[e.jsx("span",{className:"text-xs font-semibold text-muted-foreground uppercase tracking-wider min-w-[110px]",children:r.label}),e.jsx("span",{className:"text-foreground/90",children:r.value})]},r.label))})})}function X(){return e.jsxs("div",{children:[e.jsx(u,{id:"overview",children:"Overview"}),e.jsx(a,{children:"The AnveVoice public API gives you programmatic access to the same voice stack that powers the AnveVoice widget: high-quality text-to-speech, fast speech-to-text (batch and streaming), and a real-time conversational Live endpoint that proxies audio both ways over a single WebSocket."}),e.jsxs(a,{children:["The base URL for every endpoint is ",e.jsx(s,{children:"https://api.anvevoice.app"}),". All endpoints are versioned under an implicit ",e.jsx(s,{children:"/v1/"})," prefix; no breaking changes are planned for v1 — when we need to evolve the surface we'll ship v2 alongside."]}),e.jsx(h,{children:"What's here"}),e.jsx("ul",{className:"space-y-3 text-muted-foreground mb-6 ml-1",children:[{name:"Voices",desc:"Public catalog of 12 curated voices across 5 languages.",to:"endpoint-voices"},{name:"Text-to-Speech",desc:"Synthesize speech from text. PCM 16-bit 24 kHz mono, wrapped as WAV.",to:"endpoint-tts"},{name:"Speech-to-Text",desc:"Batch transcription with two quality tiers (fast-and-cheap or top-accuracy).",to:"endpoint-stt"},{name:"Speech-to-Text (stream)",desc:"WebSocket upload of long-form audio; single final transcript.",to:"endpoint-stt-stream"},{name:"Live",desc:"Real-time conversational agent over WebSocket. Mint a session token, then connect.",to:"endpoint-live"}].map(t=>e.jsxs("li",{className:"flex items-start gap-3",children:[e.jsx("span",{className:"flex-shrink-0 w-1.5 h-1.5 mt-2.5 rounded-full bg-primary"}),e.jsxs("div",{children:[e.jsx("a",{href:`#${t.to}`,className:"font-semibold text-foreground hover:text-primary transition-colors",children:t.name})," ",e.jsxs("span",{children:["— ",t.desc]})]})]},t.to))}),e.jsxs(v,{variant:"tip",children:["Minting API keys, checking usage, and revoking keys all happen in your"," ",e.jsx(S,{to:"/developer",className:"text-primary underline-offset-2 hover:underline",children:"Developer dashboard"}),". The dashboard is the only place a raw key is ever shown — it can't be recovered after creation."]})]})}function Y(){return e.jsxs("div",{children:[e.jsx(u,{id:"authentication",children:"Authentication"}),e.jsxs(a,{children:["Every request to a protected endpoint must carry a valid AnveVoice API key. Keys are prefixed"," ",e.jsx(s,{children:"anvapi_"})," followed by ~256 bits of random entropy, base64url-encoded. Keys are stored server-side as an HMAC-SHA256 digest — even AnveVoice staff cannot recover a key from our database. If a key leaks, revoke it from the dashboard."]}),e.jsx(h,{children:"HTTP endpoints"}),e.jsxs(a,{children:["Send the key in either the ",e.jsx(s,{children:"Authorization"})," header or the ",e.jsx(s,{children:"X-API-Key"})," header. Both forms are equivalent."]}),e.jsx(i,{language:"http",code:`Authorization: Bearer anvapi_your_key_here
12# — or —
13X-API-Key: anvapi_your_key_here`}),e.jsx(h,{children:"WebSocket endpoints"}),e.jsxs(a,{children:["Browsers can't set custom headers when opening a ",e.jsx(s,{children:"new WebSocket(url)"}),". WS endpoints therefore accept the key (or, for Live, a short-lived session token) as a query-string parameter instead."]}),e.jsx(i,{language:"javascript",code:`// /v1/stt/stream — pass the long-lived API key
14new WebSocket("wss://api.anvevoice.app/functions/v1/voice-api-stt-stream?api_key=anvapi_...");
15
16// /v1/live/ws — pass the short-lived session_token from /v1/live/sessions
17new WebSocket("wss://api.anvevoice.app/functions/v1/voice-api-live-ws?session_token=anvsess_...");`}),e.jsx(v,{variant:"warning",children:"Never hard-code an API key in client-side JavaScript. For browser apps, proxy through your own backend — or (for Live specifically) mint a session token server-side and hand that to the browser; it's single-use and expires in 5 minutes."})]})}function Q(){return e.jsxs("div",{children:[e.jsx(u,{id:"scopes-plans",children:"Scopes & Plans"}),e.jsxs(a,{children:["Every API key has one or more ",e.jsx("em",{children:"scopes"}),". A scope defines which endpoints the key is authorized for; if the key is missing the required scope, the endpoint returns"," ",e.jsx(s,{children:"insufficient_scope"})," (HTTP 403). Pick scopes when you mint the key in the dashboard."]}),e.jsx(d,{headers:["Scope","Required by","Description"],rows:[["tts","POST /v1/tts","Synthesize speech from text."],["stt","POST /v1/stt, WSS /v1/stt/stream","Transcribe audio to text."],["live","POST /v1/live/sessions, WSS /v1/live/ws","Real-time conversational voice sessions."]]}),e.jsx(h,{id:"plans",children:"Plan limits"}),e.jsxs(a,{children:["The public API is available on ",e.jsx("strong",{children:"every plan"})," — Free, Growth, Scale, and Custom. Free callers get a small sampler quota (just enough to evaluate the API end-to-end); paid plans unlock the larger monthly pools and higher per-minute rate caps. The full breakdown is in the"," ",e.jsx("a",{href:"#rate-limits",className:"text-primary underline-offset-2 hover:underline",children:"Rate limits & quotas"})," ","section below. To bump to a higher tier, visit your"," ",e.jsx(S,{to:"/billing",className:"text-primary underline-offset-2 hover:underline",children:"Billing page"}),"."]})]})}function Z(){return e.jsxs("div",{children:[e.jsx(u,{id:"rate-limits",children:"Rate limits & quotas"}),e.jsxs(a,{children:["Two throttles apply to every account: a ",e.jsx("strong",{children:"per-minute rate limit"})," (a short sliding window to prevent bursts) and a ",e.jsx("strong",{children:"monthly quota"})," (rolling 30-day caps by plan). When either is exceeded the endpoint returns ",e.jsx(s,{children:"rate_limited"})," or ",e.jsx(s,{children:"quota_exceeded"})," ","(both HTTP 429)."]}),e.jsx(h,{children:"Per-minute rate limits"}),e.jsx(d,{headers:["Endpoint","Free","Growth / Scale / Custom"],rows:[["POST /v1/tts","10 / min","60 / min"],["POST /v1/stt","5 / min","20 / min"],["WSS  /v1/stt/stream","3 / min","10 / min"],["POST /v1/live/sessions","5 / min","30 / min"],["WSS  /v1/live/ws","Gated by the session-mint limit — each token = one connection",""]]}),e.jsx(h,{children:"Monthly quotas (rolling 30-day)"}),e.jsx(d,{headers:["Resource","Free","Growth","Scale / Custom"],rows:[["TTS characters","5,000","50,000","500,000"],["STT audio (batch + stream)","30 minutes","10 hours","100 hours"],["Live audio (per-session wall-clock)","15 minutes","10 hours","100 hours"]]}),e.jsx(v,{variant:"info",children:"STT batch and STT stream share a single quota pool. Live metering is based on the wall-clock duration of the WebSocket session, not the number of audio bytes you send. Free is a sampler tier — enough to evaluate the API end-to-end. Real side-projects belong on Growth or higher."})]})}function $(){return e.jsxs("div",{children:[e.jsx(u,{id:"errors",children:"Error format"}),e.jsxs(a,{children:["All non-2xx responses return a JSON body with a uniform shape. Each response also sets an"," ",e.jsx(s,{children:"X-AnveVoice-Request-Id"})," header so you can quote a specific request when reaching out to support."]}),e.jsx(i,{language:"json",code:`{
18  "error": {
19    "code": "rate_limited",
20    "message": "Too many requests. Limit is 60 per minute.",
21    "request_id": "08ecaef8-824b-4486-acc8-7e2a4e75019f"
22  }
23}`}),e.jsx(h,{children:"Canonical error codes"}),e.jsx(d,{headers:["Code","HTTP","When"],rows:[["unauthorized","401","Missing / malformed / revoked API key, or missing session_token on a WS endpoint."],["insufficient_scope","403","The key exists but wasn't granted the scope this endpoint requires."],["plan_required","403","Reserved for future use. (Before 2026-05-14 the API was gated to Growth/Scale; today every plan can call, gated by per-tier quotas.)"],["rate_limited","429","Per-minute rate limit exceeded for this user + endpoint. The limit varies by plan."],["quota_exceeded","429","Rolling 30-day plan quota exhausted. Wait for the window to roll over or upgrade."],["invali
23d_argument","400","Request body or query parameters failed validation."],["method_not_allowed","405","Wrong HTTP method (e.g., GET on a POST-only endpoint)."],["voice_not_found","404","Voice id isn't present in the public catalog."],["audio_too_large","413","Audio payload exceeds the size cap for this endpoint."],["session_expired","401","Live: session_token is past its 5-minute TTL."],["session_already_used","401","Live: session_token already consumed; single-use only."],["session_timeout","—","Live: session exceeded the 15-minute wall-clock cap. Delivered as an anve.error frame."],["upstream_error","502","Upstream voice service returned an error. Retry; escalate with request_id if persistent."],["internal_error","500","Something broke server-side. Safe to retry with exponential backoff."]]})]})}function ee(){return e.jsxs("div",{children:[e.jsx(b,{id:"endpoint-voices",method:"GET",path:"/v1/voices",title:"List voices",blurb:"Returns the public AnveVoice voice catalog. No authentication required — this endpoint is your friend when building a voice picker UI or confirming the API is reachable."}),e.jsx(j,{items:[{label:"Auth",value:e.jsx("span",{children:"None required"})},{label:"Plan",value:e.jsx("span",{children:"Any"})},{label:"Rate limit",value:e.jsx("span",{children:"No per-user limit (public)"})},{label:"Response",value:e.jsx(s,{children:"application/json"})}]}),e.jsx(n,{children:"Example"}),e.jsx(i,{language:"bash",code:"curl https://api.anvevoice.app/functions/v1/voice-api-voices"}),e.jsx(n,{children:"Response"}),e.jsx(i,{language:"json",code:`{
24  "voices": [
25    {
26      "id": "voice_calm_female_01",
27      "display_name": "Aria",
28      "language": "en-US",
29      "gender": "female",
30      "style_tags": ["calm", "professional"]
31    },
32    { "...": "11 more" }
33  ]
34}`}),e.jsx(v,{variant:"info",children:"Only display-safe columns are returned. The underlying provider mapping stays server-side and is never exposed to clients."})]})}function se(){return e.jsxs("div",{children:[e.jsx(b,{id:"endpoint-tts",method:"POST",path:"/v1/tts",title:"Text-to-Speech",blurb:"Synthesizes speech from text using the selected voice. Returns raw WAV bytes (PCM 16-bit, 24 kHz, mono) in the response body."}),e.jsx(j,{items:[{label:"Auth",value:e.jsxs(e.Fragment,{children:["Scope ",e.jsx(s,{children:"tts"})]})},{label:"Plans",value:e.jsx(e.Fragment,{children:"All (Free / Growth / Scale / Custom)"})},{label:"Rate limit",value:"10 / 60 / 60 / 60 req per minute (Free / Growth / Scale / Custom)"},{label:"Quota",value:"5K / 50K / 500K / 500K characters per 30 days (Free / Growth / Scale / Custom)"},{label:"Response",value:e.jsx(s,{children:"audio/wav"})},{label:"Max text",value:"5,000 characters"}]}),e.jsx(n,{children:"Request body"}),e.jsx(d,{headers:["Field","Type","Required","Description"],rows:[[e.jsx(s,{children:"text"}),"string","Yes","The text to speak. ≤ 5,000 characters."],[e.jsx(s,{children:"voice"}),"string","Yes",e.jsxs(e.Fragment,{children:["An id from the ",e.jsx("a",{href:"#voice-catalog",className:"text-primary hover:underline",children:"voice catalog"}),"."]})],[e.jsx(s,{children:"format"}),"string","No",e.jsxs(e.Fragment,{children:["Defaults to ",e.jsx(s,{children:'"wav"'}),". Only ",e.jsx(s,{children:'"wav"'})," is supported at launch; any other value returns ",e.jsx(s,{children:"invalid_argument"}),"."]})]]}),e.jsx(n,{children:"Example"}),e.jsx(i,{language:"bash",code:`curl -X POST https://api.anvevoice.app/functions/v1/voice-api-tts \\
35  -H "Authorization: Bearer anvapi_your_key_here" \\
36  -H "Content-Type: application/json" \\
37  -d '{"text":"Hello from AnveVoice","voice":"voice_calm_female_01","format":"wav"}' \\
38  --output hello.wav`}),e.jsx(n,{children:"Response"}),e.jsxs(a,{children:["Raw ",e.jsx(s,{children:"audio/wav"})," bytes. Save to disk or stream directly to an audio player. On error, the response is a JSON envelope with the shape described in"," ",e.jsx("a",{href:"#errors",className:"text-primary hover:underline",children:"Error format"}),"."]})]})}function te(){return e.jsxs("div",{children:[e.jsx(b,{id:"endpoint-stt",method:"POST",path:"/v1/stt",title:"Speech-to-Text (batch)",blurb
38:"Transcribes a single audio payload in one request. Use this for audio files up to about a few minutes long. For longer audio, use the streaming endpoint."}),e.jsx(j,{items:[{label:"Auth",value:e.jsxs(e.Fragment,{children:["Scope ",e.jsx(s,{children:"stt"})]})},{label:"Plans",value:e.jsx(e.Fragment,{children:"All (Free / Growth / Scale / Custom)"})},{label:"Rate limit",value:"5 / 20 / 20 / 20 req per minute (Free / Growth / Scale / Custom)"},{label:"Quota",value:"30 min / 10 h / 100 h / 100 h audio per 30 days (Free / Growth / Scale / Custom, shared with stream)"},{label:"Response",value:e.jsx(s,{children:"application/json"})},{label:"Max audio",value:"25 MB base64 (~18 MB raw)"}]}),e.jsx(n,{children:"Request body"}),e.jsx(d,{headers:["Field","Type","Required","Description"],rows:[[e.jsx(s,{children:"audio_base64"}),"string","Yes","Base64-encoded audio bytes."],[e.jsx(s,{children:"encoding"}),"string","Yes",e.jsxs(e.Fragment,{children:[e.jsx(s,{children:"LINEAR16"}),", ",e.jsx(s,{children:"MP3"}),", ",e.jsx(s,{children:"OGG_OPUS"}),", or ",e.jsx(s,{children:"FLAC"}),"."]})],[e.jsx(s,{children:"sample_rate_hz"}),"number","For LINEAR16","Sample rate of the PCM input. 8,000–48,000. Required only when encoding is LINEAR16."],[e.jsx(s,{children:"language"}),"string","No",e.jsxs(e.Fragment,{children:["BCP-47 code (e.g. ",e.jsx(s,{children:'"en-US"'}),"). Hint only — the model auto-detects language."]})],[e.jsx(s,{children:"model"}),"string","No",e.jsxs(e.Fragment,{children:[e.jsx(s,{children:'"lite"'})," (default, fast & cheap) or ",e.jsx(s,{children:'"pro"'})," (best accuracy on proper nouns / accents; ~3× slower)."]})],[e.jsx(s,{children:"include_word_timings"}),"boolean","No","Accepted but currently a no-op — the response never includes word offsets."]]}),e.jsx(n,{children:"Example"}),e.jsx(i,{language:"bash",code:`curl -X POST https://api.anvevoice.app/functions/v1/voice-api-stt \\
39  -H "Authorization: Bearer anvapi_your_key_here" \\
40  -H "Content-Type: application/json" \\
41  -d '{
42    "audio_base64": "UklGRi4AAABXQVZF...",
43    "encoding": "LINEAR16",
44    "sample_rate_hz": 24000,
45    "language": "en-US",
46    "model": "lite"
47  }'`}),e.jsx(n,{children:"Response"}),e.jsx(i,{language:"json",code:`{
48  "text": "Hello from AnveVoice.",
49  "duration_ms": 1520
50}`}),e.jsxs(v,{variant:"tip",children:["If your audio is already a WAV file (RIFF header present), you can still send it with"," ",e.jsx(s,{children:'encoding: "LINEAR16"'})," — the server detects the header and passes the WAV through unchanged rather than double-wrapping it."]})]})}function re(){return e.jsxs("div",{children:[e.jsx(b,{id:"endpoint-stt-stream",method:"WSS",path:"/v1/stt/stream",title:"Speech-to-Text (streaming)",blurb:"Upload long-form audio over a WebSocket. The server accumulates the stream and returns one final transcript when you signal end-of-audio."}),e.jsx(j,{items:[{label:"Auth",value:e.jsxs(e.Fragment,{children:[e.jsx(s,{children:"?api_key=anvapi_…"}),", scope ",e.jsx(s,{children:"stt"})]})},{label:"Plans",value:e.jsx(e.Fragment,{children:"All (Free / Growth / Scale / Custom)"})},{label:"Rate limit",value:"3 / 10 / 10 / 10 new connections per minute (Free / Growth / Scale / Custom)"},{label:"Quota",value:"Shared pool with batch STT"},{label:"Max session",value:"10 minutes wall-clock"},{label:"Max buffer",value:"50 MB of concatenated audio"}]}),e.jsx(n,{children:"Protocol — client → server"}),e.jsxs("ol",{className:"space-y-3 text-muted-foreground mb-6 ml-1 text-[15px]",children:[e.jsxs("li",{className:"flex items-start gap-3",children:[e.jsx("span",{className:"flex-shrink-0 w-7 h-7 rounded-lg bg-primary/10 border border-primary/20 flex items-center justify-center text-xs font-bold text-primary",children:"1"}),e.jsxs("div",{children:[e.jsx("strong",{className:"text-foreground",children:"Config frame"})," (JSON, send first):"," ",e.jsx(s,{children:'{type:"config", encoding, sample_rate_hz?, language?, model?, include_word_timings?}'})]})]}),e.jsxs("li",{className:"flex items-start gap-3",children:[e.jsx("span",{className:"flex-shrink-0 w-7 h-7 rounded-lg bg-primary/10 border border-primary/20 flex items-center justify-center text-xs font-bold text-primary",children:"2"}),e.jsxs("div",{children:[e.jsx("strong",{className:"text-foreground",children:"Audio frames"})," (binary): raw audio bytes, any chunk size. The server concatenates them server-side."]})]}),e.jsxs("li",{className:"flex items-start gap-3",children:[e.jsx("span",{className:"flex-shrink-0 w-7 h-7 rounded-lg bg-primary/10 border border-primary/20 flex items-center justify-center text-xs font-bold text-primary",children:"3"}),e.jsxs("div",{children:[e.jsx("strong",{className:"text-foreground",children:"End frame"})," (JSON): ",e.jsx(s,{children:'{type:"end"}'}),". Triggers the final recognize call."]})]})]}),e.jsx(n,{children:"Protocol — server → client"}),e.jsx(d,{headers:["Frame","When"],rows:[[e.jsx(s,{children:'{type:"ready", session_id}'}),"Emitted after your config frame is accepted. Start sending audio."],[e.jsx(s,{children:'{type:"transcript", is_final:true, text, duration_ms}'}),"One final transcript after the end frame."],[e.jsx(s,{children:'{type:"error", code, message, request_id}'}),"On any failure. Socket will close next."]]}),e.jsx(n,{children:"Example (Node)"}),e.jsx(i,{language:"javascript",code:`import WebSocket from "ws";
51import fs from "node:fs";
52
53const ws = new WebSocket(
54  "wss://api.anvevoice.app/functions/v1/voice-api-stt-stream?api_key=anvapi_..."
55);
56
57ws.on("open", () => {
58  ws.send(JSON.stringify({
59    type: "config",
60    encoding: "LINEAR16",
61    sample_rate_hz: 16000,
62    language: "en-US",
63    model: "lite",
64  }));
65  const audio = fs.readFileSync("speech.pcm");
66  const CHUNK = 8 * 1024;
67  for (let i = 0; i < audio.length; i += CHUNK) ws.send(audio.subarray(i, i + CHUNK));
68  ws.send(JSON.stringify({ type: "end" }));
69});
70
71ws.on("message", (buf) => console.log(JSON.parse(buf.toString())));`})]})}function ne(){return e.jsxs("div",{children:[e.jsx(b,{id:"endpoint-live",method:"POST",path:"/v1/live/sessions  →  WSS /v1/live/ws",title:"Live (conversational)",blurb:"Real-time bidirectional voice agent. The flow is two-step: mint a short-lived session token over HTTPS, then open a WebSocket using that token. The WebSocket streams microphone audio up and model audio down, with the customer-supplied system prompt shaping the agent's behavior."}),e.jsx(j,{items:[{label:"Auth",value:e.jsxs(e.Fragment,{children:["Scope ",e.jsx(s,{children:"live"})]})},{label:"Plans",value:e.jsx(e.Fragment,{children:"All (Free / Growth / Scale / Custom)"})},{label:"Rate limit",value:"5 / 30 / 30 / 30 session mints per minute (Free / Growth / Scale / Custom)"},{label:"Quota",value:"15 min / 10 h / 100 h / 100 h Live audio per 30 days (Free / Growth / Scale / Custom)"},{label:"Session TTL",value:"5 minutes to connect; 15 minutes max session length"}]}),e.jsx(h,{children:"Step 1 — Mint a session token"}),e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx(w,{method:"POST"}
71),e.jsx("span",{className:"font-mono text-sm text-foreground/90",children:"/v1/live/sessions"})]}),e.jsx(n,{children:"Request body"}),e.jsx(d,{headers:["Field","Type","Required","Description"],rows:[[e.jsx(s,{children:"voice"}),"string","Yes",e.jsxs(e.Fragment,{children:["An id from the ",e.jsx("a",{href:"#voice-catalog",className:"text-primary hover:underline",children:"voice catalog"}),"."]})],[e.jsx(s,{children:"system_prompt"}),"string","No","Application instructions for the agent (persona, rules, topics). ≤ 4,000 characters. Wrapped with the AnveVoice identity directive before reaching the model."]]}),e.jsx(n,{children:"Example"}),e.jsx(i,{language:"bash",code:`curl -X POST https://api.anvevoice.app/functions/v1/voice-api-live-session \\
72  -H "Authorization: Bearer anvapi_your_key_here" \\
73  -H "Content-Type: application/json" \\
74  -d '{
75    "voice": "voice_calm_female_01",
76    "system_prompt": "You are a concise help-desk agent. Answer in under 2 sentences."
77  }'`}),e.jsx(n,{children:"Response"}),e.jsx(i,{language:"json",code:`{
78  "session_token": "anvsess_...",
79  "expires_at":    "2026-04-22T12:34:56.789Z",
80  "ws_url":        "wss://api.anvevoice.app/functions/v1/voice-api-live-ws?session_token=anvsess_..."
81}`}),e.jsxs(v,{variant:"warning",children:["Session tokens are ",e.jsx("strong",{children:"single use"}),". Mint a new one per connection. The raw token is shown exactly once; server-side we store only an HMAC of it, so it cannot be recovered."]}),e.jsx(h,{children:"Step 2 — Open the WebSocket"}),e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx(w,{method:"WSS"}),e.jsx("span",{className:"font-mono text-sm text-foreground/90",children:"/v1/live/ws?session_token=..."})]}),e.jsx(n,{children:"Client → server (JSON frames only, no binary)"}),e.jsx(d,{headers:["Frame","Description"],rows:[[e.jsx(s,{children:'{type:"anve.audio", data, sample_rate_hz?}'}),e.jsxs(e.Fragment,{children:["Base64-encoded PCM 16-bit mono audio chunk. ",e.jsx(s,{children:"sample_rate_hz"})," defaults to 16 000 if omitted."]})],[e.jsx(s,{children:'{type:"anve.text", text}'}),"Optional typed-text input as an alternative to speaking."],[e.jsx(s,{children:'{type:"anve.end"}'}),"Gracefully end the session. Server closes the socket after flushing."]]}),e.jsx(n,{children:"Server → client"}),e.jsx(d,{headers:["Frame","When"],rows:[[e.jsx(s,{children:'{type:"anve.ready"}'}),"Upstream setup succeeded. Start streaming mic audio."],[e.jsx(s,{children:'{type:"anve.audio", data}'}),"Model audio chunk. Base64-encoded PCM 16-bit, 24 kHz mono."],[e.jsx(s,{children:'{type:"anve.text", text}'}),"Model text output (uncommon — only if the agent emits text parts)."],[e.jsx(s,{children:'{type:"anve.turn_complete"}'}),'The agent finished one turn. Use this to drive UI cues like "your turn to speak".'],[e.jsx(s,{children:'{type:"anve.error", code, message, request_id}'}),"Any error. Socket closes next."],[e.jsx(s,{children:'{type:"anve.session_end", reason}'}),"Terminal frame. reason ∈ client_end, client_close, upstream_close, session_timeout, etc."]]}),e.jsx(n,{children:"Example (Node)"}),e.jsx(i,{language:"javascript",code:`import WebSocket from "ws";
82import fs from "node:fs";
83
84const ws = new WebSocket("<ws_url from /v1/live/sessions>");
85const audio = [];
86
87ws.on("message", (buf) => {
88  const m = JSON.parse(buf.toString());
89  if (m.type === "anve.ready") {
90    ws.send(JSON.stringify({ type: "anve.text", text: "Introduce yourself in one sentence." }));
91  } else if (m.type === "anve.audio") {
92    audio.push(Buffer.from(m.data, "base64"));
93  } else if (m.type === "anve.turn_complete") {
94    fs.writeFileSync("reply.pcm", Buffer.concat(audio));
95    ws.send(JSON.stringify({ type: "anve.end" }));
96  }
97});`}),e.jsxs(v,{variant:"tip",children:["The ",e.jsx(s,{children:"system_prompt"}),' you pass at mint time is wrapped with an AnveVoice identity directive before reaching the model — the agent introduces itself as AnveVoice, never mentions the underlying provider, and speaks the brand name as one word ("AHN-vay voys").']})]})}function ae(){const t=[{id:"voice_calm_female_01",name:"Aria",lang:"en-US",gender:"female",tags:"calm, professional"},{id:"voice_calm_male_01",name:"Atlas",lang:"en-US",gender:"male",tags:"calm, professional"},{id:"voice_warm_female_01",name:"Sienna",lang:"en-US",gender:"female",tags:"warm, friendly"},{id:"voice_warm_male_01",name:"Nolan",lang:"en-US",gender:"male",tags:"warm, friendly"},{id:"voice_calm_female_es",name:"Valeria",lang:"es-ES",gender:"female",tags:"calm, professional"},{id:"voice_warm_male_es",name:"Mateo",lang:"es-ES",gender:"male",tags:"warm, friendly"},{id:"voice_calm_female_fr",name:"Camille",lang:"fr-FR",gender:"female",tags:"calm, professional"},{id:"voice_warm_male_fr",name:"Louis",lang:"fr-FR",gender:"male",tags:"warm, friendly"},{id:"voice_calm_female_de",name:"Lena",lang:"de-DE",gender:"female",tags:"calm, professional"},{id:"voice_warm_male_de",name:"Felix",lang:"de-DE",gender:"male",tags:"warm, friendly"},{id:"voice_calm_female_hi",name:"Aanya",lang:"hi-IN",gender:"female",tags:"calm, professional"},{id:"voice_warm_male_hi",name:"Vihaan",lang:"hi-IN",gender:"male",tags:"warm, friendly"}];return e.jsxs("div",{children:[e.jsx(u,{id:"voice-catalog",children:"Voice catalog"}),e.jsxs(a,{children:["Twelve curated voices across five languages. The ",e.jsx(s,{children:"id"})," column is what you pass in the"," ",e.jsx(s,{children:"voice"})," field of TTS and Live requests. For programmatic access (including any new voices we add), hit ",e.jsx("a",{href:"#endpoint-voices",className:"text-primary hover:underline",children:"GET /v1/voices"}),"."]}),e.jsx(d,{headers:["ID","Name","Language","Gender","Tags"],rows:t.map(r=>[e.jsx(s,{children:r.id}),r.name,r.lang,r.gender,r.tags])})]})}function ie(){return e.jsxs("div",{children:[e.jsx(u,{id:"changelog",children:"Changelog"}),e.jsx("ul",{className:"space-y-5 text-[15px]",children:[{date:"May 2026",title:"Free tier opened",desc:"Every plan can now call the API. Free gets a sampler quota (5K TTS chars / 30 min STT / 15 min Live per 30 days) with stricter per-minute rate caps; Growth, Scale and Custom keep their existing larger quotas. The plan_required error is gone for non-paying accounts."},{date:"April 2026",title:"Public API v1 launch",desc:"TTS, STT (batch + streaming), and Live c
97onversational endpoints go live on api.anvevoice.app. Plan-gated to Growth and Scale at launch. Dashboard key management and usage ledger shipped."},{date:"April 2026",title:"Live WebSocket endpoint",desc:"Real-time bidirectional voice via session-token handshake. Full white-label enforcement: wrapped system prompt, scrubbed text frames, branded error envelopes."},{date:"April 2026",title:"STT model tiers",desc:"Added the optional model parameter: 'lite' for fast / high-volume, 'pro' for best accuracy on proper nouns and accented speech."}].map((t,r)=>e.jsxs("li",{className:"flex items-start gap-4",children:[e.jsx("div",{className:"flex-shrink-0 w-24 text-xs uppercase tracking-wider text-muted-foreground/80 pt-1",children:t.date}),e.jsxs("div",{children:[e.jsx("div",{className:"font-semibold text-foreground",children:t.title}),e.jsx("div",{className:"text-muted-foreground leading-relaxed",children:t.desc})]})]},r))})]})}function _e(){const[t,r]=y.useState("overview"),[o,c]=y.useState(!1),g=y.useRef(null),f=I();y.useEffect(()=>{const l=new IntersectionObserver(p=>{for(const m of p)m.isIntersecting&&r(m.target.id)},{rootMargin:"-20% 0px -60% 0px"});return _.forEach(p=>{const m=document.getElementById(p.id);m&&l.observe(m)}),()=>l.disconnect()},[]);const P=l=>{const p=document.getElementById(l);p&&(p.scrollIntoView({behavior:"smooth"}),r(l),c(!1))};return e.jsxs(e.Fragment,{children:[e.jsxs(R,{children:[e.jsx("title",{children:"AnveVoice Public API Reference"}),e.jsx("meta",{name:"description",content:"Reference documentation for the AnveVoice public API: text-to-speech, speech-to-text (batch and streaming), and real-time conversational Live endpoints."})]}),e.jsxs("div",{className:"min-h-screen bg-background",children:[e.jsxs(S,{to:"/developer",className:"fixed top-4 left-4 z-50 inline-flex items-center gap-2 bg-background/80 backdrop-blur-sm border border-border rounded-full px-3 py-2 text-sm font-medium text-muted-foreground hover:text-primary shadow-sm transition-colors group",children:[e.jsx(E,{className:"h-4 w-4 group-hover:-translate-x-0.5 transition-transform"}),"Developer dashboard"]}),e.jsxs("div",{className:"relative overflow-hidden border-b border-border/40",children:[e.jsx("div",{className:"absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-secondary/5"}),e.jsx("div",{className:"absolute top-0 left-1/2 -translate-x-1/2 w-[600px] h-[300px] bg-primary/8 rounded-full blur-[100px]"}),e.jsxs("div",{className:"container mx-auto px-4 sm:px-6 py-10 md:py-14 relative",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4",children:[e.jsx("div",{className:"p-2.5 rounded-xl bg-primary/10 border border-primary/20",children:e.jsx(T,{className:"h-6 w-6 text-primary"})}),e.jsx(N,{className:"bg-primary/10 text-primary border-primary/20 text-xs font-medium",children:"API Reference"})]}),e.jsx("h1",{className:"text-3xl md:text-5xl font-bold text-foreground mb-3 tracking-tight",children:"AnveVoice Public API"}),e.jsxs("p",{className:"text-muted-foreground text-lg md:text-xl max-w-2xl leading-relaxed",children:["Text-to-Speech, Speech-to-Text, and real-time conversational voice — all behind one HTTPS base URL, authenticated with a single ",e.jsx(s,{children:"anvapi_"})," key."]})]})]}),e.jsx("div",{className:"container mx-auto px-4 sm:px-6 py-8",children:e.jsxs("div",{className:"flex gap-10 relative",children:[f&&e.jsxs(F,{variant:"default",size:"sm",className:"fixed bottom-6 right-6 z-50 shadow-xl rounded-full h-12 px-5 gap-2",onClick:()=>c(!o),children:[o?e.jsx(C,{className:"h-4 w-4"}):e.jsx(O,{className:"h-4 w-4"}),e.jsx("span",{className:"text-sm font-medium",children:"Sections"})]}),e.jsx("aside",{className:x("w-64 shrink-0",f?x("fixed inset-0 z-40 bg-background/95 backdrop-blur-xl p-6 pt-16 overflow-y-auto transition-transform duration-300 ease-out",o?"translate-x-0":"-translate-x-full"):"sticky top-20 self-start max-h-[calc(100vh-6rem)] overflow-y-auto"),children:e.jsx("nav",{className:"space-y-0.5",children:_.map(l=>{const p=l.icon,m=t===l.id;return e.jsxs("button",{onClick:()=>P(l.id),className:x("w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm transition-all duration-200 text-left group",m?"bg-primary/10 text-primary font-semibold shadow-sm border border-primary/15":"text-muted-foreground hover:text-foreground hover:bg-muted/40"),children:[e.jsx(p,{className:x("h-4 w-4 shrink-0 transition-colors",m?"text-primary":"text-muted-foreground
97/60 group-hover:text-foreground/60")}),e.jsx("span",{className:"truncate",children:l.label}),m&&e.jsx(A,{className:"h-3 w-3 ml-auto text-primary/60"})]},l.id)})})}),e.jsxs("div",{ref:g,className:"flex-1 min-w-0 max-w-3xl",children:[e.jsx(X,{}),e.jsx(Y,{}),e.jsx(Q,{}),e.jsx(Z,{}),e.jsx($,{}),e.jsx(ee,{}),e.jsx(se,{}),e.jsx(te,{}),e.jsx(re,{}),e.jsx(ne,{}),e.jsx(ae,{}),e.jsx(ie,{})]})]})})]})]})}export{_e as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.