API'et arbejder med de samme agenter, opkald og kreditter som webdashboardet. Alt, hvad du bygger i dashboardet, kan styres fra dine egne systemer, og omvendt.
| Hvad | Endpoint |
|---|---|
| Vis agenter | GET /api/v1/voice/agents |
| Opret en agent | POST /api/v1/voice/agents |
| Hent / opdater en agent | GET · PATCH /api/v1/voice/agents/{id} |
| Foretag et udgående opkald | POST /api/v1/voice/calls |
| Vis opkald | GET /api/v1/voice/calls |
| Hent et opkald (udskrift) | GET /api/v1/voice/calls/{id} |
| Slet et opkald | DELETE /api/v1/voice/calls/{id} |
| Slet en opkalders opkald | POST /api/v1/voice/calls/delete-by-caller |
| Kampagner | GET · POST /api/v1/voice/campaigns |
| Hent en kampagne | GET /api/v1/voice/campaigns/{id} |
| Start / pause / annuller | POST /api/v1/voice/campaigns/{id}/{action} |
| Klonede stemmer | GET · POST /api/v1/voice/voices |
| Slet en klonet stemme | DELETE /api/v1/voice/voices/{id} |
| Spærreliste | GET · POST /api/v1/voice/do-not-call |
| Fjern fra listen | DELETE /api/v1/voice/do-not-call/{phone} |
| Sprog, stemmer, skabeloner | GET /api/v1/voice/catalog |
| En agents tests | GET · POST /api/v1/voice/agents/{id}/tests |
| Kør tests / læs en kørsel | POST /api/v1/voice/agents/{id}/test-runs · GET /api/v1/voice/test-runs/{id} |
| Tildel et nummer til en agent | PATCH /api/v1/voice/phone-numbers/{id} |
| Ordlister | GET · POST /api/v1/voice/vocabularies |
Opret en nøgle under Integrationer → API-nøgler i dashboardet (eller med et enkelt klik på oversigten), og send den som et Bearer-token:
Authorization: Bearer sk-your-key
En nøgle virker i det arbejdsområde, hvor dens ejer arbejder, med den persons rolle: en skrivebeskyttet medlems nøgle kan læse, men ikke ændre noget.
Opret en agent ud fra en skabelon, og angiv eventuelt dens felter i samme anmodning. Uden template starter den tom; GET /api/v1/voice/catalog viser skabelonerne samt de sprog og stemmer, en agent kan få. Skabelonerne er skrevet på engelsk og kinesisk, så til et andet sprog sender du system_prompt og first_message på det sprog. Enten gemmes hele anmodningen, eller også oprettes ingen agent, så en afvist anmodning kan sendes igen, når den er rettet. dashboard_url i svaret er agentens side i dashboardet, hvor du kan tale med kladden i browseren. Hver agent kører på EvaSay ASR, EvaSay LLM og EvaSay TTS, som EvaSay vælger for hvert opkald efter sprog og belastning, og som er inkluderet i opkaldsprisen; der er ingen konti hos andre udbydere at indstille.
curl https://evasay.com/api/v1/voice/agents \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Front desk",
"language": "en",
"first_message": "Hi, thanks for calling Sunrise Salon. How can I help?",
"system_prompt": "You are the front desk of Sunrise Salon..."
}'
Opdater et vilkårligt af disse felter med PATCH /api/v1/voice/agents/{id}:
| Felt | Bemærkninger |
|---|---|
name, first_message, system_prompt | Tekst |
status | published udgiver kladden som en ny version; draft holder op med at tage imod opkald |
language | Et af 27 sprog, f.eks. en, zh, es, de, eller multi for at følge den, der ringer |
temperature | 0-100 |
max_duration_sec, silence_timeout_sec | Opkaldsgrænser |
interruptible, end_call_enabled | Booleske værdier |
confirm_details | Boolesk; læser tal og navne op igen og får dem bekræftet |
ai_disclosure | Boolesk, standard true; før sin første besked siger agenten på opkaldets sprog, at den, der ringer, taler med en AI (udelades, når den første besked allerede siger det) |
voicemail_detection | Boolesk; udgående opkald lytter først og slutter ved en telefonsvarer |
voicemail_message | Efterlades på en telefonsvarer, kan bruge {{variables}}; ingen for at lægge på |
transfer_number | Nummer at stille om til, i internationalt format |
transfer_destinations | Op til 9 numre mere, [{name, number, when}]; agenten vælger et ud fra when |
transfer_briefing | Boolesk; den, der svarer først, hører agentens resumé af opkaldet |
pronunciations | Op til 100 [{word, say, case_sensitive}]; stemmen siger say for word |
idle_messages | Op til 3 påmindelser, der siges efter tur til en tavs opringer, før opkaldet slutter |
noise_reduction | Boolesk; opringerens baggrundsstøj filtreres, før den høres |
recording_enabled | Boolesk; opkald optages i to kanaler (opringeren til venstre, agenten til højre) |
recording_consent | announce, ask (gemmes kun, hvis opringeren siger ja) eller none |
recording_notice | Meddelelsen eller spørgsmålet, der siges først; tomt for den indbyggede tekst på opkaldets sprog |
handoffs | Op til 5 [{agent_id, when}]: andre agenter, som denne må overdrage et opkald til |
knowledge_base_id | En af dine vidensbaser |
vocabulary_id | Et af dine ordforråd; termer i det genkendes mere pålideligt, når opringeren siger dem |
voice_id | Et id for en indbygget EvaSay-stemme eller en af dine klonede stemmer (clone:…) |
Indbyggede stemmer afhænger af sproget: kinesisk har ming-designed-female-clear og ming-designed-female-warm (kvindelige), ming-designed-male-clear og ming-designed-male-friendly (mandlige), de andre sprog har F1–F5 (kvindelige) og M1–M5 (mandlige). En indbygget stemme, der ikke taler agentens sprog, erstattes af stemmen af samme køn, der gør. Det ældre feltnavn tts_voice_id accepteres stadig. Enhver anden værdi for voice_id, eller en klonet stemme der ikke er klar endnu, afvises.
analysis_config bestemmer, hvad der udledes af hvert opkald, når det slutter: summary (standard true), summaryLanguage, successCriteria (hvad et vellykket opkald opnår), fields (op til 20 {name, type, description} at udtrække, hvor type er string, number eller boolean) og scorecard (op til 10 {name, description, weight}, vægt 1–5). Resultaterne findes i opkaldets analysis og i webhooken call.analyzed.
Når du ændrer en agents felter, ændrer du dens kladde. Opkald bliver ved med at bruge den udgivne version, indtil du udgiver kladden med POST /api/v1/voice/agents/{id}/publish (eventuelt med en note) eller med status: "published" i samme PATCH. Hver udgivelse gemmer en nummereret version; published_version i agenten fortæller, hvilken opkaldene bruger. Et opkald bliver på den version, der var aktiv, da det begyndte, så udgivelse under et opkald ændrer det ikke. Testopkald fra dashboardet bruger kladden.
GET /agents/{id}/versions viser versionerne, og POST /agents/{id}/versions/{version}/restore ruller tilbage: nye opkald bruger den version, og kladden bliver den. Agentens navn, udrulning, widgetens udseende og notifikationer har ikke versioner og ændres med det samme, ligesom dokumenterne i dens vidensbase.
En test spiller ét opkald i tekst: en simuleret opkalder spiller scenario, agenten svarer ud fra sin kladde (instruktioner, første besked og viden), og en bedømmer vurderer samtalen ud fra success_criteria. Skriv tests til de opkald, der betyder noget, kør dem efter hver ændring, og udgiv, når de består.
curl https://evasay.com/api/v1/voice/agents/AGENT_ID/tests \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Move a booking",
"scenario": "A regular customer wants to move Friday 3 pm to Saturday morning.",
"success_criteria": "Offers Saturday times and confirms the new time and the customer'"'"'s name.",
"max_turns": 8
}'
POST /agents/{id}/test-runs kører alle agentens tests, eller dem i test_ids, og svarer med én kørsel pr. test (status: "running"). Spørg GET /test-runs/{id}, indtil status er passed, failed eller error; så har kørslen transcript og bedømmerens reason (på engelsk, eller på kinesisk med reason_language: "zh"). Hver kørsel koster Credits, som vises ved testene i dashboardet; kørslerne stopper ved den første, saldoen ikke kan betale, og not_started viser resten. En kørsel, der ikke kan gennemføres, refunderes. Tests tjekker, hvad agenten siger, ikke dens stemme eller timing, og kalder ikke dens funktioner: forhåndsvis dem med POST /tools/{id}/test. En agent har op til 30 tests; PATCH og DELETE /agents/{id}/tests/{test_id} ændrer eller fjerner en.
Ud over hele opkald (type: "simulation", standard) kan en test tjekke et enkelt svar. type: "next_reply" tager chat_history, samtalen før, der slutter med opkalderen ([{role, text}], hvor role er caller eller agent), og success_criteria for agentens næste svar. type: "tool_call" tager chat_history og expected_tool {name, arguments, match}: agenten skal kalde name (en af sine funktioner eller end_call, transfer_call, handoff_to_agent) med arguments, sammenlignet præcist (tekst trimmet, store og små bogstaver ignoreret) eller med match: "judge" efter betydning; andre argumenter ignoreres. En kørsels transcript viser de kaldte funktioner i tool_calls.
POST /agents/{id}/tests/generate foreslår tests ud fra agentens kladde: instruktioner, viden og funktioner. Det tager count (1–10, standard 5), types, focus (hvad der skal dækkes) og language (en eller zh, til navne og kriterier), koster Credits som én kørsel og svarer med kladder, du gennemgår og sender til POST /agents/{id}/tests; med save: true gemmes de.
hooks gør noget på et tidspunkt i opkaldet, op til 10 regler: on: "silence" (opringeren har ikke sagt noget i seconds, 3–600, siden agenten blev færdig; én gang, indtil de taler igen), on: "time_elapsed" (seconds inde i opkaldet, 10–3600) eller on: "call_ending". Hver regel gør (do) op til 3 af {type: "say", text}, {type: "transfer", destination?}, {type: "end_call", text?} og {type: "tool", name, args?}; en regel for opkaldets afslutning kører kun funktioner. Et opkald, som en regel afslutter, har ended_reason rule_ended.
Ved telefonopkald når de taster, en opringer trykker på, agenten som svar: en indtastning slutter med # eller en pause på to sekunder. Ved udgående opkald kan agenten også trykke på taster for at komme igennem en virksomheds telefonmenu.
transfer_number er agentens hovednummer til at give en opringer videre til et menneske og det nummer, der ringes til, når arbejdsområdet er løbet tør for kreditter. transfer_destinations tilføjer navngivne numre, hvert med en note om, hvornår det skal bruges („Fakturering: spørgsmål om fakturaer og refusioner”), og agenten vælger. Med transfer_briefing slået til skriver agenten et kort resumé, mens den stiller om; den, der tager telefonen, hører det med en EvaSay-stemme og på agentens resuméesprog, før opringeren stilles igennem. Opkaldets ended_reason er så transferred.
Med handoffs kan en agent overdrage et opkald til en anden udgivet agent i dit arbejdsområde, f.eks. en reception, der giver en booking videre til en bookingagent. Agenten vælger ud fra when. Den anden agent overtager samme opkald med alt, hvad der er sagt indtil videre, og taler med sine egne instruktioner, stemme, viden, værktøjer og overdragelser. Opkaldet forbliver opført, analyseret og faktureret under den første agent; dets udskrift noterer hver overdragelse.
Numre forbindes i dashboardet med din egen operatørkonto. GET /api/v1/voice/phone-numbers viser dem, og PATCH /api/v1/voice/phone-numbers/{id} med { "agent_id": "AGENT_ID" } sender nummerets opkald til en agent (dens udgivne version), eller med "agent_id": null til ingen; label omdøber det.
En ordliste rummer navne og udtryk, som opkaldere siger, og som en talegenkendelse ellers ville høre forkert, fx produkt-, medicin- eller gadenavne. POST /api/v1/voice/vocabularies med { "name": "Products", "terms": ["Lumora", "Vantix Pro"] } (op til 1.000 udtryk på 50 tegn, eller "preset": "medical" eller "legal" som udgangspunkt), og sæt derefter agentens vocabulary_id. GET, PATCH (name, terms) og DELETE /vocabularies/{id}; en liste, som en agent bruger, kan ikke slettes.
Hvert nummer har opkaldsregler på siden Telefonnumre, som anvendes, før agenten svarer: blokerede numre eller nummerbegyndelser (+1555) og opringere, der skjuler deres nummer, afvises uden at blive besvaret og koster ingenting; opringere på en liste kan stilles direkte videre til et andet nummer; og når agenten ikke kan svare (ikke udgivet, ingen worker, løbet tør for kreditter uden viderestillingsnummer), kan opkaldet ringe til et nummer eller afspille din egen besked. Et startopslag (run_at_start) kan også afvise en opringer ved at svare {"reject": true, "message": "..."}: agenten siger beskeden, hvis der er en, og lægger på, med ended_reason rejected.
Foretag ét opkald fra et af dit arbejdsområdes telefonnumre. Hver anmodning kræver en unik Idempotency-Key; sendes den samme nøgle igen, får du det samme opkald tilbage i stedet for at ringe to gange.
curl https://evasay.com/api/v1/voice/calls \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "AGENT_ID",
"to": "+14155550100",
"variables": { "customer_name": "Alex", "order_id": "1234" }
}'
from er påkrævet, når arbejdsområdet har mere end ét telefonnummer. variables udfylder pladsholdere som {{customer_name}} i agentens første besked og prompt.
GET /api/v1/voice/calls/{id} returnerer opkaldets status, varighed, afregnede kreditter, resumé, analyse og udskrift. Vis opkald med GET /api/v1/voice/calls?agent_id=&status=&channel=&user_id=&page= (user_id: dit eget id for personen, fra et webopkalds-token). Dets turns er opkaldets fejlsøgningslog, tur for tur: hvor tiden gik fra opringeren blev færdig med at tale til de hørte svaret, i millisekunder — waitMs (talens slutning), sttMs (genkendelse), llmMs (modellens første ord, ét ekstra for hver runde funktioner), ttsMs (stemmens første lyd), firstAudioMs (svaret blev hørt) — med de funktioner, der blev kaldt, afbrydelser og fejl. Opkaldssiden viser den også.
Med recording_enabled optages hvert opkald som en WAV med to kanaler: opringeren til venstre, agenten til højre, med opkaldets samplingfrekvens. Med recording_consent: "announce" siger agenten først, at opkaldet optages; med "ask" spørger den, og optagelsen gemmes kun, hvis opringeren siger ja (intet svar tæller som nej); med "none" siges der ikke noget. Tjek, hvad loven kræver, der hvor du og dine opringere befinder jer.
Optagelser gemmes i EvaSays lager eller i din egen S3-kompatible bucket (AWS S3, Cloudflare R2, Google Cloud Storage, Supabase, MinIO), som du indstiller under Integrationer → Webhooks og notifikationer → Lagring af optagelser. Den worker, der kører opkaldet, uploader filen direkte til bucketen. GET /api/v1/voice/calls/{id} returnerer en recordingUrl, der er gyldig i en time, når optagelsen er gemt, og recording.status (recording, stored, declined eller failed).
DELETE /api/v1/voice/calls/{id} sletter et afsluttet opkald med transskription, optagelse (i EvaSays lager eller din egen bucket), analyse og webhook-leveringer. De brugte Credits bliver i kredithistorikken. Et opkald, der ikke kan slettes endnu, svarer 409 med code call_not_deletable_yet: det er i gang eller lige afsluttet, bliver stadig afregnet, optagelsen bliver måske stadig uploadet, eller det skylder Credits, som saldoen ikke dækkede (køb Credits først).
Når en person beder dig slette sine data, sletter POST /api/v1/voice/calls/delete-by-caller med { "phone_number": "+14155550123" } alle opkald med det nummer (opkalderens nummer ved indgående opkald, det kaldte nummer ved udgående), eller med { "user_id": "..." } alle webopkald med det user_id i deres token. Svaret er { "deleted": 12, "kept_back": { "settling": 1 }, "more": false }: højst 200 opkald pr. anmodning, så spørg igen, så længe more er true, og senere igen for opkaldene i kept_back. Står nummeret på din spærreliste, bliver det der. I dashboardet gøres det samme under Opkald → Slet en opkalders data.
Send POST /api/v1/voice/calls/{id}/control, mens et opkald er i gang. Den worker, der kører opkaldet, opfanger kommandoen inden for omkring 2 sekunder; API'et svarer 202. Kan den worker, der kører opkaldet, ikke nås, svarer API'et 503 (code call_unreachable), og kommandoen udføres ikke.
type | Hvad der sker |
|---|---|
say | Agenten siger text efter sin igangværende sætning, eller med det samme med "interrupt": true |
note | Agenten får at vide text (siges ikke) og tager højde for det fra sit næste svar; udskriften noterer det |
end | Agenten siger text, hvis den er angivet, og lægger så på; et telefonopkald uden text lægges på med det samme |
Opkaldets ended_reason er så api_ended. Opkaldssiden i dashboardet har de samme kontroller.
POST /api/v1/voice/calls/{id}/listen (eventuelt { "channels": 2 }) returnerer en listen_url, som du kan åbne inden for to minutter. Det er en WebSocket: først en JSON-besked {"type":"start","sampleRate":8000,"channels":1,"encoding":"pcm_s16le"}, så binære rammer med 16-bit little-endian PCM med det, opringeren hører (begge stemmer blandet; med channels: 2 opringeren til venstre og agenten til højre). Den lukker, når opkaldet slutter. Lyden kommer direkte fra den worker, der kører opkaldet, ikke gennem EvaSays kontrolplan; knappen Lyt med på dashboardets opkaldsside bruger den samme adresse.
Send og modtag et opkalds lyd fra dit eget program, f.eks. dit eget telefonsystem eller din app. Start opkaldet:
curl https://evasay.com/api/v1/voice/calls/websocket \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{ "agent_id": "AGENT_ID", "encoding": "pcm_s16le", "sample_rate": 16000 }'
websocket_url i svaret indeholder et engangstoken og kan åbnes inden for 15 minutter. encoding er pcm_s16le (16-bit little-endian PCM med en sample_rate på 8000, 16000 eller 24000) eller mulaw (8 kHz μ-law). Lyden går begge veje som binære rammer i det format, helst på 20 ms hver. Tekstrammer er JSON:
| Retning | Beskeder |
|---|---|
| Dig → EvaSay | {"type":"dtmf","digits":"12#"} tastetryk; {"type":"end"} lægger på; {"type":"text","text":"…"} ord, opringeren skrev ("input":"button" for et tappet svar); {"type":"context","text":"…","key":"cart"} hvad din app melder (agenten svarer ikke på det); {"type":"tool_result","id":"…","result":{…}} (eller "error") svaret fra en sidefunktion |
| EvaSay → dig | start (med callId); clear (opringeren afbrød: smid agentens endnu ikke afspillede lyd væk); transcript (role, text, final og input for skrevne ord); user_started_speaking, user_stopped_speaking, agent_started_speaking, agent_stopped_speaking; cards (cards, quick_replies); tool (id, name, arguments: kør en af dine sidefunktioner); notice (code: too_fast eller limit for skrevne ord); ended (med reason, derefter lukker socket'en) |
Agenten hilser, så snart du forbinder. user_id og page_tools (de sidefunktioner, din app svarer på, se nedenfor) kan føjes til anmodningen. Opkald afregnes pr. minut som alle andre, med de samme opkaldsposter, den samme analyse og de samme webhooks.
Ved et webopkald (widgetten, den hostede side, din app) ser opringeren en chat ved siden af stemmen, så agenten kan mere end at tale. Opringere i telefonen får intet af dette.
Slå Agent → Værktøjer → Send til opkalderen til (send_to_caller i agent-API'et), så kan agenten lægge op til fem kort ad gangen på opringerens skærm: en titel, en linje under, en beskrivelse, et billede, et link og op til to svarknapper hver; den kan også tilbyde op til tre hurtige svar under et spørgsmål. Links læses aldrig højt.
Agenten må kun sende links og billeder, den har fået i det opkald: dens instruktioner og hilsen, vidensbasen (et dokument læst fra en webside bærer dens adresse), svarene fra dine funktioner og de færdige kort. Et link skal desuden være på en af allowed_hosts (et færdigt korts eget websted er det altid). Links, agenten finder på, eller som opringeren læser højt, sendes ikke. Links til de websteder i agentens ord kan klikkes på i chatten.
"send_to_caller": {
"enabled": true,
"allowed_hosts": ["shop.example.com", "*.cdn.example.com"],
"presets": [
{ "name": "hours", "when": "asked when we open", "title": "Opening hours",
"description": "Mon–Sat 9:00–18:00", "url": "https://shop.example.com/stores", "image_url": "" }
]
}
Hver afsendelse sendes til dig som webhooken call.message_sent (channel, items med title og url, quickReplies, blocked). Et opkald sender højst 10 gange.
Under opkaldet kan opringeren også skrive (en e-mailadresse, et ordrenummer) eller trykke på en svarknap; agenten svarer på det som på tale og stopper først, hvis den talte. Op til 500 tegn pr. besked, én i sekundet, 100 pr. opkald. I opkaldsposten er disse ture markeret som skrevne eller tappede.
Widgetten giver din side et evasay-objekt. Alt er valgfrit, og opkaldsrammen lytter kun til din side, hvis den er et af widgettens tilladte websteder (Agent → Udrul):
<script src="https://evasay.com/voice-widget.js" data-agent="AGENT_SLUG" async></script>
<script>
window.evasay = window.evasay || [];
evasay.push(function (agent) {
agent.setVariables({ plan: 'pro', page: location.pathname }); // for the next call
agent.update('Cart: 2 items, $120', { key: 'cart' }); // during it
agent.registerTool('add_to_cart', async function (args) {
// your code, in the visitor's browser
return { ok: true, checkout: 'https://shop.example.com/checkout' };
});
agent.on('cards', function (cards) {}); // also 'live', 'ended'
});
</script>
setVariables udfylder {{name}} i instruktionerne og hilsenen. De kommer fra den besøgendes browser, så agenten får at vide, at de ikke er verificerede, og de når aldrig dine funktioner eller startopslaget.update fortæller agenten, hvad der sker på siden, uden at få den til at svare; en nyere opdatering med samme key erstatter den ældre."kind": "page", ingen url) til agenten, og registrer en funktion med samme navn på din side. Agenten må kun kalde den ved opkald fra en side, der har registreret den; den venter op til timeout_sec (1–10, standard 5) på svaret, medmindre wait_for_result er false. Den kører logget ind som den besøgende, som et klik fra dem: bed om bekræftelse på din egen side før alt, hvad der koster penge eller ikke kan fortrydes. Links i dens svar kan sendes som kort.Sæt Hvem der kan starte et opkald til Kun med et token, og lad din server hente et engangstoken til den loggede bruger:
curl https://evasay.com/api/v1/voice/web-calls \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{ "agent_id": "AGENT_ID", "user_id": "u_42", "variables": { "name": "Ann" }, "expires_in": 600 }'
Svaret indeholder token (ét opkald, inden for expires_in sekunder, 30–3600, standard 600), agent (sluggen) og web_call_url. Giv tokenet til siden med data-token-url="/your/endpoint" på widgettens script (den POST'er dertil med den besøgendes cookies og læser { "token": "…" }) eller med agent.setToken(async () => token). Tokenets variables er verificerede: instruktionerne, startopslaget og dine funktioners skabeloner må bruge dem, ligesom user_id, som opkaldet beholder (userId i opkaldet, user_id til at filtrere opkald). Behold din API-nøgle på din server.
I din egen app POST'er du { "token": "…", "pageTools": ["add_to_cart"] } til https://evasay.com + web_call_url. Svaret er opkaldets forbindelse (en WebRTC-tilbudsadresse eller en WebSocket-adresse med sit opkaldstoken) til en RTVI-klient som Pipecats klient-SDK'er til web, iOS, Android og React Native. Kort, sidefunktioner og meddelelser kommer som RTVI server-message (evasay.cards, evasay.tool, evasay.notice); send skrevne ord med send-text og sidens meldinger og svar som client-message evasay.context og evasay.tool_result. Eller før lyden selv med Lyd over en WebSocket, med user_id og page_tools.
Under Telefonnumre → SIP kan din egen omstilling, dine SIP-telefoner eller din SIP-trunk ringe direkte til dine agenter; din SIP-udbyder afregner opkaldene:
sip:ev…@<EvaSay's SIP domain>, kun indgående opkald, til omstillinger (3CX, FreePBX, Asterisk…) og SIP-telefoner.from); viderestillinger til en person afleveres til trunken med REFER. Når trunken beder om legitimationsoplysninger, svarer EvaSay med trunkens brugernavn og adgangskode, som du har angivet.Indgående opkald logger ind med digest med det brugernavn og den adgangskode, EvaSay giver dig (realm er SIP-domænet); du kan også begrænse kilde-IP'erne eller kun acceptere på IP, når din udbyder ikke kan logge ind (IP'erne er så påkrævede). Hver SIP-adresse eller trunk har en grænse for samtidige opkald; derover får opkald 486. Adgangskoder vises én gang, når de oprettes eller nulstilles. Kun UDP og G.711 (PCMU, PCMA); tastetryk via RFC 4733 eller SIP INFO; slå registrering (REGISTER) fra på din omstillings trunk.
En kampagne ringer til en liste af kontakter med én agent, inden for ringetider og en samtidighedsgrænse (max_concurrency, op til 100 opkald ad gangen og aldrig flere end dit arbejdsområdes grænse for samtidige opkald), og forsøger igen med personer, den ikke fik fat i.
curl https://evasay.com/api/v1/voice/campaigns \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Appointment reminders",
"agent_id": "AGENT_ID",
"phone_number_id": "PHONE_NUMBER_ID",
"timezone": "America/New_York",
"window_start": "09:00",
"window_end": "18:00",
"max_concurrency": 2,
"max_attempts": 2,
"retry_delay_min": 60,
"consent_confirmed": true,
"contacts": [
{ "phone": "+14155550100", "name": "Alex", "appointment": "Tuesday 3 pm" }
]
}'
Kontakter kan også være CSV-tekst med telefonnummeret i første kolonne. consent_confirmed: true er påkrævet: med det bekræfter du, at alle på listen har accepteret at blive ringet op, også af en AI-stemme, og EvaSay gemmer den bekræftelse sammen med kampagnen (consent_confirmed_at). Kampagnen oprettes som en kladde; start den med POST /api/v1/voice/campaigns/{id}/start, og brug pause eller cancel på samme måde. Agenten skal være udgivet, før en kampagne starter.
Med voicemail_detection slået til (standard) lytter et udgående opkald efter, at den anden side taler, før agenten hilser; forbliver de tavse, hilser agenten efter to eller tre sekunder. Når agenten hører en telefonsvarer eller en teleoperatørs optagelse, venter den, til hilsenen og bippet er slut, efterlader voicemail_message eller lægger på, når der ikke er nogen. Sådanne opkald slutter med ended_reason voicemail, afregnes for den tid, de varede, og analyseres eller notificeres ikke.
I en kampagne ringes der igen til et nummer, der nåede en telefonsvarer, som til et, der ikke svarede, og beskeden efterlades kun ved sidste forsøg, så ingen får den samme besked to gange.
Hvert udgående opkald, fra en kampagne eller fra POST /api/v1/voice/calls, tjekker først arbejdsområdets spærreliste. Et nummer på listen ringes aldrig op: API'et svarer 409 med code do_not_call, og en kampagne markerer kontakten som canceled med outcome do_not_call og går videre til den næste.
Når personen i et opkald, agenten foretog, beder om ikke at blive ringet op igen, sætter agenten selv nummeret på listen, siger det til dem, og webhooken call.do_not_call sendes. Numre kan også tilføjes og fjernes under Kampagner → Spærreliste eller med API'et:
curl https://evasay.com/api/v1/voice/do-not-call \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{ "phones": ["+14155550100"], "note": "Asked by email" }'
Numre angives i internationalt format; op til 1.000 ad gangen. GET /api/v1/voice/do-not-call viser dem, nyeste først (search, limit, page), hver med sin source (call, dashboard eller api). DELETE /api/v1/voice/do-not-call/%2B14155550100 tager ét af listen igen; gør det kun, når personen har accepteret at blive ringet op.
POST /api/v1/voice/voices opretter en stemme ud fra en WAV-optagelse af én taler (multipart audio, name, language, consent=true). Det svarer 202 med status running; forespørg GET /api/v1/voice/voices, indtil den er ready, og sæt så en agents voice_id til stemmens voice_id. language er det sprog, der tales i optagelsen, et vilkårligt af agentsprogene ovenfor; stemmen taler dem alle undtagen kinesisk, hvor en indbygget stemme af samme køn svarer, og den ligner mest taleren på optagelsens sprog. Hver klonet stemme koster kreditter, som dashboardet viser, før du opretter en.
Tilføj en https-adresse under Integrationer → Webhooks og notifikationer for at modtage opkaldshændelser:
| Hændelse | Hvornår |
|---|---|
call.started | Agenten tog telefonen |
call.ended | Opkaldet sluttede, med varighed og kreditter |
call.analyzed | Resumé, resultat, udtrukne felter og udskrift er klar |
call.transcript | Under opkaldet, de nye linjer i udskriften hvert par sekunder |
call.tool_called | Agenten kaldte en af dine funktioner: name, arguments, status, durationMs |
call.handed_off | Opkaldet blev overdraget til en anden agent: fromAgentId, toAgentId |
call.transferred | Opkaldet blev stillet om til en person: destination |
call.voicemail | Et udgående opkald nåede en telefonsvarer |
call.do_not_call | Personen i et udgående opkald bad om ikke at blive ringet op igen: phone |
call.recording_ready | Optagelsen med to kanaler er gemt: recordingUrl (gyldig i 24 timer), durationMs |
call.message_sent | Agenten viste kort på en web- eller appopringers skærm: items, quickReplies |
alert.triggered | En af dine alarmer (Webhooks og notifikationer → Alarmer) overskred sin tærskel |
alert.resolved | Den alarm er tilbage til normal |
Hændelser, der sendes under et opkald, bærer data.call (id, agentId, channel, direction, numre). Hver anmodning er signeret:
EvaSay-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
EvaSay-Delivery: <delivery id>
Verificer signaturen med den webhook-hemmelighed, der blev vist, da du oprettede webhooken, og svar med en 2xx-status. Mislykkede leverancer forsøges igen efter 1 minut, 5 minutter, 30 minutter, 2 timer og 12 timer med samme indhold og samme EvaSay-Delivery-id, så du kan ignorere gentagelser. En webhooks seneste leverancer, med det præcist sendte indhold og den status, dit endpoint svarede, vises af GET /webhooks/{id}/deliveries og i dashboardet; POST /webhooks/{id}/deliveries/{delivery_id} sender én igen.
Ud over e-mail og webhooks alert.triggered / alert.resolved kan alarmer gå til en Slack-kanal (incoming webhook), en WeCom-grupperobot eller Telegram under Webhooks og notifikationer → Alarmer → Send også til.
Fejl har én form:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_agent_field",
"message": "status must be draft or published",
"param": "status"
}
}
| Status | Betydning |
|---|---|
| 400 | Ugyldigt input (code og param siger hvilket) |
| 401 | Manglende eller ugyldig API-nøgle |
| 402 | Ikke nok kreditter til at starte opkaldet |
| 403 | Nøglen er skrivebeskyttet, eller agenten er utilgængelig |
| 404 | Ingen sådan agent, noget sådant opkald eller sådan kampagne i dette arbejdsområde |
| 409 | Forkert tilstand (f.eks. start af en kampagne, der kører), en udbyderkonto er ikke forbundet, eller nummeret står på spærrelisten (do_not_call) |
| 429 | For mange anmodninger; sæt farten ned, og prøv igen |
Arbejdsområdets Voice API-anmodninger de seneste 30 dage (tid, endpoint, status, varighed, nøgle og fejlkode; ingen indhold) vises under API-nøgler → Log over API-anmodninger.
Læsninger er begrænset til 120 anmodninger i minuttet pr. nøgle, skrivninger og opkald til 30.
Opkald afregnes pr. minut fra arbejdsområdets kreditter, den samme saldo som dashboardet bruger. De aktuelle priser står på prissiden.
Brug OpenAPI-kontrakten til at generere en integrationsklient. Det offentlige API, dashboardet og MCP-administrationsendpointet arbejder på de samme arbejdsområderessourcer og tilladelser.
| Funktion | Endpoint |
|---|---|
| Genbrugelige værktøjer | GET / POST /api/v1/voice/tools |
| Læs / opdater / slet et værktøj | GET / PATCH / DELETE /api/v1/voice/tools/{id} |
| Forhåndsvis eller test et værktøj | POST /api/v1/voice/tools/{id}/test |
| Bind værktøjer til en agent | PUT /api/v1/voice/agents/{id}/tools |
| Vidensbaser | GET / POST /api/v1/voice/knowledge-bases |
| Læs / opdater / slet en vidensbase | GET / PATCH / DELETE /api/v1/voice/knowledge-bases/{id} |
| Tilføj / vis dokumenter | POST / GET /api/v1/voice/knowledge-bases/{id}/documents |
| Læs / slet et dokument | GET / DELETE /api/v1/voice/knowledge-bases/{id}/documents/{doc_id} |
| Abonnementer på opkaldshændelser | GET / POST /api/v1/voice/webhooks |
| Læs / opdater / slet et abonnement | GET / PATCH / DELETE /api/v1/voice/webhooks/{id} |
| Send en signeret testhændelse | POST /api/v1/voice/webhooks/{id}/test |
| Find eksterne MCP-værktøjer | POST /api/v1/voice/mcp/discover |
| MCP-administrationsendpoint | /api/v1/voice/mcp |
Registrer et HTTP-værktøj, der forespørger din CRM-adapter:
{
"name": "lookup_customer",
"description": "Find a customer after confirming their customer ID.",
"kind": "http",
"url": "https://crm.example.com/customers/{{customer_id}}",
"method": "GET",
"read_only": true,
"credential_ref": "crm",
"input_schema": {
"type": "object",
"properties": { "customer_id": { "type": "string" } },
"required": ["customer_id"],
"additionalProperties": false
},
"response_path": "data"
}
POST /tools returnerer { "data": { "id": "TOOL_ID", ... } }. Bind dets definition til en agent med PUT /agents/AGENT_ID/tools og { "tool_ids": ["TOOL_ID"] }. Det erstatter hele værktøjslisten med øjebliksbilleder; bind igen, når et biblioteksværktøj ændres. Sletning af en definition i biblioteket beholder eksisterende øjebliksbilleder. Du kan også læse og erstatte indlejrede definitioner med agent-API'ets felt tools. Brug analysis_config og widget_config til at konfigurere analysen og widgetten via agent-API'et.
Et værktøj kan bruge GET, POST, PUT, PATCH eller DELETE. query og request_body accepterer indlejrede JSON-skabeloner som { "customer": { "id": "{{customer_id}}" } }. En hel pladsholder bevarer den oprindelige JSON-type. Pladsholdere i URL'en kodes og må kun stå efter en fast, offentlig HTTPS-vært. Uden request_body modtager værktøjer, der ikke er GET, { "arguments": {...}, "call": { "callId": "...", "agentId": "...", "toolCallId": "...", "idempotencyKey": "..." } }. response_path vælger et felt med punktnotation. Simple parameters accepteres stadig; input_schema understøtter desuden indlejrede objekter, arrays, opregninger og numeriske grænser. Eksterne skemareferencer og regulære udtryk accepteres ikke.
static_args: værdier, der sendes med hvert kald, uanset hvad modellen skriver, som et butiks-id; de udfylder også {{name}} i adressen og kroppen.extract: [{name, path}] beholder felter fra en funktions svar (data.id) til senere funktioners {{name}}, så et opslags customer_id kan gå ind i den ordre, der følger, uden at modellen gentager det. Felter fra et startopslag beholdes på samme måde.reject_when: op til 5 regler {on: caller|agent, pattern, negate}; så længe alle gælder for de seneste ord, køres funktionen ikke, og agenten får reject_message.model_says: ved hvert kald skriver modellen én sætning, der siges, mens funktionen kører, i stedet for det faste speak_before.Forbind en app under Integrationer → Webhooks og notifikationer → Forbundne apps, og brug derefter „Tilføj en færdig funktion” på agentens fane Viden og værktøjer; du behøver ikke noget eget endpoint:
check_availability (ledige tider på en dato) og book_appointment (booker den tid, opringeren valgte). Tider i Google Calendar følger den tidszone, de åbne dage, de timer og den aftalelængde, du angiver; Cal.com bruger begivenhedstypens egen tilgængelighed og en reserve-e-mailadresse, du angiver til, når opringeren ikke opgiver nogen.save_to_sheet, som tilføjer en række med de kolonner, du angiver, plus opkaldets ID og tid.notify_team, som sender en besked, agenten skriver, til en Slack-kanal (incoming webhook).EvaSays kontrolplan kører disse funktioner med den konto, du har forbundet; hverken workeren eller agentdefinitionen opbevarer appens legitimationsoplysninger. Når en agent læses via API'et, vises de som kind: "app" (med app, action, connection_id, app_config); send dem tilbage uændret, når du erstatter tools, for at beholde dem. Apps forbindes kun i dashboardet.
Sæt run_at_start: true på et af en agents værktøjer, så kaldes det, når hvert opkald begynder, før agenten hilser eller svarer. Parametre med navnene caller_number, called_number, direction, channel eller call_id udfyldes for det. De felter, det returnerer, udfylder {{variables}} i first_message, system_prompt og idle_messages (felter et niveau nede som {{customer.name}}), og hele svaret gives til agenten som baggrund. En hilsen med variabler venter op til 3 sekunder på svaret; alt, hvad der ikke findes, efterlades tomt. Ét værktøj pr. agent kan køre ved start.
Legitimationsoplysninger konfigureres i servermiljøet for dit arbejdsområde og din destination; bed support@evasay.com om at oprette en credential_ref. Læg ikke API-nøgler i agentdefinitioner, headers, prompter eller værktøjsparametre. Din adapter kan opbevare CRM-legitimationsoplysninger i sit eget miljø.
Forhåndsvis et værktøj, før du sender anmodninger til forretningssystemet:
{
"arguments": { "customer_id": "customer-123" },
"dry_run": true,
"mock_result": { "name": "Alex", "order_status": "shipped" }
}
En forhåndsvisning validerer parametrene og viser den afbildede anmodning; den kører ingen samtale og kontakter ikke forretningssystemet. Sæt dry_run=false for en reel kørsel. En reel skrivetest kræver også confirmed=true og idempotency_key (8–128 bogstaver, tal, punktummer, understregninger, kolon eller bindestreger). Testsvar indeholder ok, status, duration_ms og et afgrænset resultat. De returnerer ikke legitimationsoplysninger. Læse- og skrivetest kræver skrivetilladelse i arbejdsområdet.
Under et opkald bærer forretningsanmodninger en stabil Idempotency-Key. Dit forretningsendpoint skal respektere den. Identiske skrivninger inden for et opkald afdubleres, også operationer med ukendt udfald efter en timeout. En anden tilsigtet operation har brug for et selvstændigt forretningsargument, som operation_id. EvaSay genafspiller ikke skrivninger automatisk. Hændelser for værktøjskørsel indeholder status og varighed; samtaletestfunktionen er stadig en tekstsimulering, ikke en test af værktøjskørsel.
Konfigurer en Streamable HTTP-MCP-forbindelse med:
URL: https://evasay.com/api/v1/voice/mcp
Authorization: Bearer <your EvaSay API key>
I Claude Code for eksempel:
claude mcp add --transport http evasay https://evasay.com/api/v1/voice/mcp --header "Authorization: Bearer $EVASAY_API_KEY"
Forbindelsen fortæller værktøjet, hvordan det bygger en agent: læs kataloget, opret en kladde, tilføj viden, funktioner og ordlister, skriv tests og kør dem, ret kladden, til de består, giv dig agentens dashboard_url til at prøve den, og udgiv og tildel et nummer først, når du godkender. Værktøjer, der læser dokumentation, kan starte fra https://evasay.com/llms.txt, som linker til denne side, OpenAPI-kontrakten og MCP-adressen.
Brug klientens sikre indstilling for token eller miljøvariabel. Endpointet bruger API-nøglegodkendelse, ikke et OAuth-loginflow. Det udstiller oprettelse og konfiguration af agenter, biblioteksværktøjer, viden, webhooks og opkaldsposter. At udgive og foretage rigtige opkald er skrivehandlinger; udgående opkald bruger kreditter og operatørgebyrer. Hvert værktøjskald genkontrollerer arbejdsområdets tilladelser. Slå din klients bekræftelseskontroller til for skrivehandlinger. Endpointet bruger tilstandsløse JSON-svar; det tilbyder ikke en notifikationsstrøm i baggrunden.
Et eksempel på en instruktion til kodningsværktøjet er: „Opret en kladde af en EvaSay-agent, registrer mit CRM-opslagsendpoint, forhåndsvis det med testargumenter, bind det til agenten, og konfigurer en call.analyzed-webhook.” Gennemgå og godkend udtrykkeligt udgivelse og rigtige opkald.
POST /mcp/discover accepterer { "url": "https://crm.example.com/mcp", "credential_ref": "crm" } og returnerer serverens værktøjer og skemaer. Registrer kun det valgte værktøj:
{
"name": "lookup_customer",
"description": "Find a CRM customer by confirmed ID.",
"kind": "mcp",
"url": "https://crm.example.com/mcp",
"mcp_tool": "get_customer",
"credential_ref": "crm",
"read_only": true,
"input_schema": {
"type": "object",
"properties": { "customer_id": { "type": "string" } },
"required": ["customer_id"]
}
}
Kun registrerede værktøjer bliver tilgængelige for agenten. Fjernforbindelser understøtter Streamable HTTP med JSON- eller SSE-svar på anmodninger, offentlige HTTPS-destinationer og forudkonfigurerede legitimationsoplysninger. Ældre SSE-endpoints, OAuth-forhandling, serverinitieret sampling/elicitation og binære vedhæftninger understøttes ikke. Opdagelse giver ikke automatisk adgang til alle serverens værktøjer. Fjernværktøjets skema skal være indlejret og bruge den understøttede delmængde af JSON Schema.
Opret en webhook via POST /webhooks med { "url": "https://crm.example.com/evasay-events", "events": ["call.analyzed"] }. Svaret indeholder abonnementet og en genereret signeringshemmelighed, der kun returneres ved oprettelsen. Verificer EvaSay-Signature, afdubler EvaSay-Delivery, og opdater dit CRM. Hændelseswebhooks er asynkrone notifikationer; værktøjer under opkald returnerer resultater direkte til agenten.