API:et arbetar med samma agenter, samtal och krediter som webbpanelen. Allt du bygger i panelen kan styras från dina egna system, och tvärtom.
| Vad | Endpoint |
|---|---|
| Lista agenter | GET /api/v1/voice/agents |
| Skapa en agent | POST /api/v1/voice/agents |
| Hämta / uppdatera en agent | GET · PATCH /api/v1/voice/agents/{id} |
| Ringa ett utgående samtal | POST /api/v1/voice/calls |
| Lista samtal | GET /api/v1/voice/calls |
| Hämta ett samtal (utskrift) | GET /api/v1/voice/calls/{id} |
| Radera ett samtal | DELETE /api/v1/voice/calls/{id} |
| Radera en uppringares samtal | POST /api/v1/voice/calls/delete-by-caller |
| Kampanjer | GET · POST /api/v1/voice/campaigns |
| Hämta en kampanj | GET /api/v1/voice/campaigns/{id} |
| Starta / pausa / avbryta | POST /api/v1/voice/campaigns/{id}/{action} |
| Klonade röster | GET · POST /api/v1/voice/voices |
| Ta bort en klonad röst | DELETE /api/v1/voice/voices/{id} |
| Spärrlista | GET · POST /api/v1/voice/do-not-call |
| Ta bort från listan | DELETE /api/v1/voice/do-not-call/{phone} |
| Språk, röster, mallar | GET /api/v1/voice/catalog |
| En agents tester | GET · POST /api/v1/voice/agents/{id}/tests |
| Kör tester / läs en körning | POST /api/v1/voice/agents/{id}/test-runs · GET /api/v1/voice/test-runs/{id} |
| Koppla ett nummer till en agent | PATCH /api/v1/voice/phone-numbers/{id} |
| Ordlistor | GET · POST /api/v1/voice/vocabularies |
Skapa en nyckel under Integrationer → API-nycklar i panelen (eller med ett klick på översikten) och skicka den som Bearer-token:
Authorization: Bearer sk-your-key
En nyckel verkar i den arbetsyta där dess ägare arbetar, med den personens roll: en skrivskyddad medlems nyckel kan läsa men inte ändra något.
Skapa en agent från en mall och ange vid behov dess fält i samma anrop. Utan template börjar den tom; GET /api/v1/voice/catalog listar mallarna och de språk och röster en agent kan ha. Mallarna är skrivna på engelska och kinesiska, så för ett annat språk skickar du system_prompt och first_message på det språket. Antingen sparas hela begäran eller så skapas ingen agent, så en avvisad begäran kan skickas igen när den är rättad. dashboard_url i svaret är agentens sida i instrumentpanelen, där du kan prata med utkastet i webbläsaren. Varje agent körs på EvaSay ASR, EvaSay LLM och EvaSay TTS, som EvaSay väljer för varje samtal efter språk och belastning och som ingår i samtalspriset; det finns inga konton hos andra leverantörer att ställa in.
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..."
}'
Uppdatera vilket som helst av dessa fält med PATCH /api/v1/voice/agents/{id}:
| Fält | Anmärkningar |
|---|---|
name, first_message, system_prompt | Text |
status | published publicerar utkastet som en ny version; draft slutar ta emot samtal |
language | Ett av 27 språk, t.ex. en, zh, es, de, eller multi för att följa den som ringer |
temperature | 0-100 |
max_duration_sec, silence_timeout_sec | Samtalsgränser |
interruptible, end_call_enabled | Booleska värden |
confirm_details | Booleskt; läser upp siffror och namn igen och ber om bekräftelse |
ai_disclosure | Booleskt, standard true; före sitt första meddelande säger agenten på samtalets språk att den som ringer talar med en AI (utelämnas när det första meddelandet redan säger det) |
voicemail_detection | Booleskt; utgående samtal lyssnar först och avslutas vid en röstbrevlåda |
voicemail_message | Lämnas på en röstbrevlåda, kan använda {{variables}}; inget för att lägga på |
transfer_number | Nummer att koppla vidare till, i internationellt format |
transfer_destinations | Upp till 9 nummer till, [{name, number, when}]; agenten väljer ett utifrån when |
transfer_briefing | Booleskt; den som svarar först hör agentens sammanfattning av samtalet |
pronunciations | Upp till 100 [{word, say, case_sensitive}]; rösten säger say för word |
idle_messages | Upp till 3 påminnelser som sägs i tur och ordning till en tyst uppringare innan samtalet avslutas |
noise_reduction | Booleskt; uppringarens bakgrundsbrus filtreras innan det hörs |
recording_enabled | Booleskt; samtal spelas in i två kanaler (uppringaren till vänster, agenten till höger) |
recording_consent | announce, ask (sparas bara om uppringaren går med på det) eller none |
recording_notice | Meddelandet eller frågan som sägs först; tomt för det inbyggda på samtalets språk |
handoffs | Upp till 5 [{agent_id, when}]: andra agenter som den här får lämna över ett samtal till |
knowledge_base_id | En av dina kunskapsbaser |
vocabulary_id | Ett av dina ordförråd; termer i det känns igen säkrare när uppringaren säger dem |
voice_id | Ett id för en inbyggd EvaSay-röst, eller en av dina klonade röster (clone:…) |
Inbyggda röster beror på språket: kinesiska har ming-designed-female-clear och ming-designed-female-warm (kvinnliga), ming-designed-male-clear och ming-designed-male-friendly (manliga), de övriga språken har F1–F5 (kvinnliga) och M1–M5 (manliga). En inbyggd röst som inte talar agentens språk byts mot rösten av samma kön som gör det. Det äldre fältnamnet tts_voice_id accepteras fortfarande. Alla andra värden för voice_id, och klonade röster som inte är klara än, avvisas.
analysis_config anger vad som tas fram ur varje samtal när det är slut: summary (standard true), summaryLanguage, successCriteria (vad ett lyckat samtal uppnår), fields (upp till 20 {name, type, description} att extrahera, där type är string, number eller boolean) och scorecard (upp till 10 {name, description, weight}, vikt 1–5). Resultaten finns i samtalets analysis och i webhooken call.analyzed.
Att ändra en agents fält ändrar dess utkast. Samtalen fortsätter använda den publicerade versionen tills du publicerar utkastet med POST /api/v1/voice/agents/{id}/publish (gärna med en note), eller med status: "published" i samma PATCH. Varje publicering sparar en numrerad version; published_version i agenten visar vilken samtalen använder. Ett samtal stannar på den version som var aktiv när det började, så att publicera under ett samtal ändrar det inte. Testsamtal från panelen använder utkastet.
GET /agents/{id}/versions listar versionerna, och POST /agents/{id}/versions/{version}/restore rullar tillbaka: nya samtal använder den versionen och utkastet blir den. Agentens namn, driftsättning, widgetens utseende och aviseringar har inga versioner och ändras direkt, liksom dokumenten i dess kunskapsbas.
Ett test spelar upp ett samtal i text: en simulerad uppringare spelar scenario, agenten svarar utifrån sitt utkast (instruktioner, första meddelande och kunskap), och en bedömare prövar samtalet mot success_criteria. Skriv tester för de samtal som är viktiga, kör dem efter varje ändring och publicera när de går igenom.
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ör alla agentens tester, eller de i test_ids, och svarar med en körning per test (status: "running"). Fråga GET /test-runs/{id} tills status är passed, failed eller error; då innehåller körningen transcript och bedömarens reason (på engelska, eller på kinesiska med reason_language: "zh"). Varje körning kostar Credits, som visas vid testerna i instrumentpanelen; körningarna stannar vid den första som saldot inte räcker till, och not_started listar resten. En körning som inte kan genomföras återbetalas. Tester kontrollerar vad agenten säger, inte rösten eller tajmingen, och anropar inte dess funktioner: förhandsgranska dem med POST /tools/{id}/test. En agent har upp till 30 tester; PATCH och DELETE /agents/{id}/tests/{test_id} ändrar eller tar bort ett.
Förutom hela samtal (type: "simulation", standard) kan ett test kontrollera ett enda svar. type: "next_reply" tar chat_history, samtalet före som slutar med uppringaren ([{role, text}], där role är caller eller agent), och success_criteria för agentens nästa svar. type: "tool_call" tar chat_history och expected_tool {name, arguments, match}: agenten ska anropa name (en av sina funktioner, eller end_call, transfer_call, handoff_to_agent) med arguments, jämförda exakt (text trimmad, skiftläge ignorerat) eller med match: "judge" efter betydelse; andra argument ignoreras. En körnings transcript visar de anropade funktionerna i tool_calls.
POST /agents/{id}/tests/generate föreslår tester utifrån agentens utkast: instruktioner, kunskap och funktioner. Den tar count (1–10, standard 5), types, focus (vad som ska täckas) och language (en eller zh, för namn och kriterier), kostar Credits som en körning och svarar med utkast att granska och skicka till POST /agents/{id}/tests; med save: true sparas de.
hooks gör något vid ett visst ögonblick i samtalet, upp till 10 regler: on: "silence" (uppringaren har inte sagt något på seconds, 3–600, sedan agenten blev klar; en gång tills de talar igen), on: "time_elapsed" (seconds in i samtalet, 10–3600) eller on: "call_ending". Varje regel gör (do) upp till 3 av {type: "say", text}, {type: "transfer", destination?}, {type: "end_call", text?} och {type: "tool", name, args?}; en regel för samtalets slut kör bara funktioner. Ett samtal som en regel avslutar har ended_reason rule_ended.
I telefonsamtal når de knappar uppringaren trycker på agenten som svar: en inmatning slutar med # eller en paus på två sekunder. I utgående samtal kan agenten också trycka på knappar för att ta sig igenom ett företags telefonmeny.
transfer_number är agentens huvudnummer för att lämna över en uppringare till en människa, och numret som rings när arbetsytan har slut på krediter. transfer_destinations lägger till namngivna nummer, vart och ett med en anteckning om när det ska användas („Fakturering: frågor om fakturor och återbetalningar”), och agenten väljer. Med transfer_briefing på skriver agenten en kort sammanfattning när den kopplar vidare; den som svarar hör den, med en EvaSay-röst och på agentens sammanfattningsspråk, innan uppringaren kopplas fram. Samtalets ended_reason är då transferred.
Med handoffs kan en agent lämna över ett samtal till en annan publicerad agent i din arbetsyta, till exempel en reception som lämnar en bokning till en bokningsagent. Agenten väljer utifrån when. Den andra agenten tar över samma samtal med allt som sagts hittills och talar med sina egna instruktioner, röst, kunskap, verktyg och överlämnanden. Samtalet förblir listat, analyserat och debiterat under den första agenten; dess utskrift noterar varje överlämnande.
Nummer kopplas in i instrumentpanelen med ditt eget operatörskonto. GET /api/v1/voice/phone-numbers listar dem, och PATCH /api/v1/voice/phone-numbers/{id} med { "agent_id": "AGENT_ID" } skickar numrets samtal till en agent (dess publicerade version), eller med "agent_id": null till ingen; label byter namn på det.
En ordlista innehåller namn och termer som uppringare säger och som en taligenkänning annars skulle höra fel, till exempel produkt-, läkemedels- eller gatunamn. POST /api/v1/voice/vocabularies med { "name": "Products", "terms": ["Lumora", "Vantix Pro"] } (upp till 1 000 termer på 50 tecken, eller "preset": "medical" eller "legal" att utgå från), och ange sedan agentens vocabulary_id. GET, PATCH (name, terms) och DELETE /vocabularies/{id}; en lista som en agent använder kan inte tas bort.
Varje nummer har samtalsregler på sidan Telefonnummer, som tillämpas innan agenten svarar: blockerade nummer eller nummerbörjan (+1555) och uppringare som döljer sitt nummer nekas utan att besvaras och kostar ingenting; uppringare på en lista kan kopplas direkt till ett annat nummer; och när agenten inte kan svara (inte publicerad, ingen worker, slut på krediter utan vidarekopplingsnummer) kan samtalet ringa ett nummer eller spela upp ditt eget meddelande. Ett startuppslag (run_at_start) kan också avvisa en uppringare genom att svara {"reject": true, "message": "..."}: agenten säger meddelandet, om det finns, och lägger på, med ended_reason rejected.
Ring ett samtal från ett av din arbetsytas telefonnummer. Varje anrop kräver en unik Idempotency-Key; att skicka samma nyckel igen ger tillbaka samma samtal i stället för att ringa två gånger.
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 krävs när arbetsytan har fler än ett telefonnummer. variables fyller platshållare som {{customer_name}} i agentens första meddelande och prompt.
GET /api/v1/voice/calls/{id} returnerar samtalets status, längd, debiterade krediter, sammanfattning, analys och utskrift. Lista samtal med GET /api/v1/voice/calls?agent_id=&status=&channel=&user_id=&page= (user_id: ditt eget id för personen, från en webbsamtals-token). Dess turns är samtalets felsökningslogg, tur för tur: vart tiden tog vägen från att uppringaren slutade tala till att de hörde svaret, i millisekunder — waitMs (slut på tal), sttMs (igenkänning), llmMs (modellens första ord, ett till per omgång funktioner), ttsMs (rösten första ljud), firstAudioMs (svaret hördes) — med de funktioner som anropats, avbrott och fel. Samtalssidan visar den också.
Med recording_enabled spelas varje samtal in som en WAV med två kanaler: uppringaren till vänster, agenten till höger, med samtalets samplingsfrekvens. Med recording_consent: "announce" säger agenten först att samtalet spelas in; med "ask" frågar den, och inspelningen sparas bara om uppringaren går med på det (inget svar räknas som nej); med "none" sägs ingenting. Kontrollera vad lagen kräver där du och dina uppringare befinner er.
Inspelningar sparas i EvaSays lagring, eller i din egen S3-kompatibla bucket (AWS S3, Cloudflare R2, Google Cloud Storage, Supabase, MinIO) som du ställer in under Integrationer → Webhooks och aviseringar → Lagring av inspelningar. Den worker som kör samtalet laddar upp filen direkt till bucketen. GET /api/v1/voice/calls/{id} returnerar en recordingUrl som gäller i en timme när inspelningen har sparats, och recording.status (recording, stored, declined eller failed).
DELETE /api/v1/voice/calls/{id} raderar ett avslutat samtal med transkription, inspelning (i EvaSays lagring eller din egen bucket), analys och webhook-leveranser. Använda Credits finns kvar i kredithistoriken. Ett samtal som inte kan raderas än svarar 409 med code call_not_deletable_yet: det pågår eller avslutades nyss, debiteras fortfarande, inspelningen kanske fortfarande laddas upp, eller det har Credits som saldot inte räckte till (fyll på Credits först).
När någon ber dig radera sina uppgifter raderar POST /api/v1/voice/calls/delete-by-caller med { "phone_number": "+14155550123" } alla samtal med det numret (uppringarens nummer för inkommande samtal, det uppringda numret för utgående), eller med { "user_id": "..." } alla webbsamtal med det user_id i sin token. Svaret är { "deleted": 12, "kept_back": { "settling": 1 }, "more": false }: högst 200 samtal per begäran, så fråga igen så länge more är true, och senare igen för samtalen i kept_back. Om numret finns på din spärrlista ligger det kvar där. I instrumentpanelen görs detsamma under Samtal → Radera en uppringares data.
Skicka POST /api/v1/voice/calls/{id}/control medan ett samtal pågår. Den worker som kör samtalet plockar upp kommandot inom ungefär 2 sekunder; API:et svarar 202. Går det inte att nå den worker som kör samtalet svarar API:et 503 (code call_unreachable), och kommandot utförs inte.
type | Vad som händer |
|---|---|
say | Agenten säger text efter sin pågående mening, eller direkt med "interrupt": true |
note | Agenten får veta text (sägs inte) och tar hänsyn till det från sitt nästa svar; utskriften noterar det |
end | Agenten säger text om den anges och lägger sedan på; ett telefonsamtal utan text läggs på direkt |
Samtalets ended_reason är då api_ended. Samtalssidan i panelen har samma kontroller.
POST /api/v1/voice/calls/{id}/listen (valfritt { "channels": 2 }) returnerar en listen_url som du kan öppna inom två minuter. Det är en WebSocket: först ett JSON-meddelande {"type":"start","sampleRate":8000,"channels":1,"encoding":"pcm_s16le"}, sedan binära ramar med 16-bitars little-endian PCM med det uppringaren hör (båda rösterna blandade; med channels: 2 uppringaren till vänster och agenten till höger). Den stängs när samtalet slutar. Ljudet kommer direkt från den worker som kör samtalet, inte via EvaSays kontrollplan; knappen Lyssna på panelens samtalssida använder samma adress.
Skicka och ta emot ett samtals ljud från ditt eget program, till exempel ditt eget telefonsystem eller din app. Starta samtalet:
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 innehåller en engångstoken och kan öppnas inom 15 minuter. encoding är pcm_s16le (16-bitars little-endian PCM med en sample_rate på 8000, 16000 eller 24000) eller mulaw (8 kHz μ-law). Ljudet går åt båda håll som binära ramar i det formatet, helst på 20 ms vardera. Textramar är JSON:
| Riktning | Meddelanden |
|---|---|
| Du → EvaSay | {"type":"dtmf","digits":"12#"} knapptryckningar; {"type":"end"} lägger på; {"type":"text","text":"…"} ord som uppringaren skrivit ("input":"button" för ett knackat svar); {"type":"context","text":"…","key":"cart"} vad din app rapporterar (agenten svarar inte på det); {"type":"tool_result","id":"…","result":{…}} (eller "error") svaret från en sidfunktion |
| EvaSay → du | start (med callId); clear (uppringaren avbröt: släng agentens ännu ej spelade ljud); transcript (role, text, final och input för skrivna ord); user_started_speaking, user_stopped_speaking, agent_started_speaking, agent_stopped_speaking; cards (cards, quick_replies); tool (id, name, arguments: kör en av dina sidfunktioner); notice (code: too_fast eller limit för skrivna ord); ended (med reason, därefter stängs socketen) |
Agenten hälsar så fort du ansluter. user_id och page_tools (de sidfunktioner din app svarar på, se nedan) kan läggas till i anropet. Samtal debiteras per minut som alla andra, med samma samtalsposter, analys och webhooks.
I ett webbsamtal (widgeten, den värdade sidan, din app) ser uppringaren en chatt bredvid rösten, så att agenten kan göra mer än att tala. Den som ringer via telefon får inget av detta.
Slå på Agent → Verktyg → Skicka till uppringaren (send_to_caller i agent-API:et) så kan agenten visa upp till fem kort åt gången på uppringarens skärm: en rubrik, en rad under, en beskrivning, en bild, en länk och upp till två svarsknappar var; den kan också erbjuda upp till tre snabbsvar under en fråga. Länkar läses aldrig upp.
Agenten får bara skicka länkar och bilder som den fått i just det samtalet: dess instruktioner och hälsning, kunskapsbasen (ett dokument som lästs från en webbsida bär dess adress), svaren från dina funktioner och de färdiga korten. En länk måste dessutom finnas bland allowed_hosts (ett färdigt korts egen webbplats gör det alltid). Länkar som agenten hittar på, eller som uppringaren läser upp, skickas inte. Länkar till de webbplatserna i agentens ord går att klicka 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": "" }
]
}
Varje utskick skickas till dig som webhooken call.message_sent (channel, items med title och url, quickReplies, blocked). Ett samtal skickar högst 10 gånger.
Under samtalet kan uppringaren också skriva (en e-postadress, ett ordernummer) eller knacka på en svarsknapp; agenten svarar på det som på tal och slutar först tala om den pratade. Upp till 500 tecken per meddelande, ett per sekund, 100 per samtal. I samtalsposten är dessa turer markerade som skrivna eller knackade.
Widgeten ger din sida ett evasay-objekt. Allt är valfritt, och samtalsramen lyssnar bara på din sida om den är en av widgetens tillåtna webbplatser (Agent → Driftsätt):
<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 fyller {{name}} i instruktionerna och hälsningen. De kommer från besökarens webbläsare, så agenten får veta att de inte är verifierade, och de når aldrig dina funktioner eller startuppslaget.update berättar för agenten vad som händer på sidan utan att få den att svara; en nyare uppdatering med samma key ersätter den äldre."kind": "page", ingen url) på agenten och registrera en funktion med samma namn på din sida. Agenten får bara anropa den i samtal från en sida som registrerat den; den väntar upp till timeout_sec (1–10, standard 5) på svaret om inte wait_for_result är false. Den körs inloggad som besökaren, som ett klick av dem: be om bekräftelse på din egen sida före allt som kostar pengar eller inte går att ångra. Länkar i dess svar kan skickas som kort.Sätt Vem som kan starta ett samtal till Bara med en token, och låt din server hämta en engångstoken för den inloggade användaren:
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 innehåller token (ett samtal, inom expires_in sekunder, 30–3600, standard 600), agent (sluggen) och web_call_url. Ge token till sidan med data-token-url="/your/endpoint" på widgetens skript (den POST:ar dit med besökarens cookies och läser { "token": "…" }) eller med agent.setToken(async () => token). Tokenens variables är verifierade: instruktionerna, startuppslaget och dina funktioners mallar får använda dem, liksom user_id, som samtalet behåller (userId i samtalet, user_id för att filtrera samtal). Behåll din API-nyckel på din server.
I din egen app, POST:a { "token": "…", "pageTools": ["add_to_cart"] } till https://evasay.com + web_call_url. Svaret är samtalets anslutning (en WebRTC-offeradress, eller en WebSocket-adress, med sin samtalstoken), för en RTVI-klient som Pipecats klient-SDK:er för webb, iOS, Android och React Native. Kort, sidfunktioner och meddelanden kommer som RTVI server-message (evasay.cards, evasay.tool, evasay.notice); skicka skrivna ord med send-text och sidans rapporter och svar som client-message evasay.context och evasay.tool_result. Eller för över ljudet själv med Ljud över en WebSocket, med user_id och page_tools.
Under Telefonnummer → SIP kan din egen telefonväxel, dina SIP-telefoner eller din SIP-trunk ringa dina agenter direkt; din SIP-leverantör debiterar samtalen:
sip:ev…@<EvaSay's SIP domain>, bara inkommande samtal, för växlar (3CX, FreePBX, Asterisk…) och SIP-telefoner.from); vidarekopplingar till en person lämnas till trunken med REFER. När trunken ber om inloggningsuppgifter svarar EvaSay med trunkens användarnamn och lösenord som du angav.Inkommande samtal loggar in med digest med det användarnamn och lösenord EvaSay ger dig (realm är SIP-domänen); du kan också begränsa käll-IP-adresserna, eller bara acceptera på IP när din leverantör inte kan logga in (IP-adresserna krävs då). Varje SIP-adress eller trunk har en gräns för samtidiga samtal; över den får samtal 486. Lösenord visas en gång, när de skapas eller återställs. Bara UDP och G.711 (PCMU, PCMA); knapptryckningar via RFC 4733 eller SIP INFO; stäng av registrering (REGISTER) på din växels trunk.
En kampanj ringer en lista med kontakter med en agent, inom ringtider och en samtidighetsgräns (max_concurrency, upp till 100 samtal samtidigt, och aldrig fler än din arbetsytas gräns för samtidiga samtal), och försöker igen med personer den inte nådde.
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 också vara CSV-text med telefonnumret i första kolumnen. consent_confirmed: true krävs: med det bekräftar du att alla på listan har samtyckt till att bli uppringda, även av en AI-röst, och EvaSay sparar den bekräftelsen med kampanjen (consent_confirmed_at). Kampanjen skapas som ett utkast; starta den med POST /api/v1/voice/campaigns/{id}/start, och använd pause eller cancel på samma sätt. Agenten måste vara publicerad innan en kampanj startar.
Med voicemail_detection på (standard) lyssnar ett utgående samtal först efter att andra sidan talar innan agenten hälsar; om de förblir tysta hälsar agenten efter två eller tre sekunder. När agenten hör en röstbrevlåda eller en teleoperatörs inspelning väntar den tills hälsningen och pipet är över, lämnar voicemail_message, eller lägger på när det inte finns något. Sådana samtal slutar med ended_reason voicemail, debiteras för den tid de varade och analyseras eller aviseras inte.
I en kampanj ringer man upp ett nummer som nådde en röstbrevlåda igen som ett som inte svarade, och meddelandet lämnas bara vid sista försöket, så att ingen får samma meddelande två gånger.
Varje utgående samtal, från en kampanj eller från POST /api/v1/voice/calls, kontrollerar först arbetsytans spärrlista. Ett nummer på listan rings aldrig: API:et svarar 409 med code do_not_call, och en kampanj markerar kontakten som canceled med outcome do_not_call och går vidare till nästa.
När personen i ett samtal som agenten ringde ber att inte bli uppringd igen lägger agenten själv in numret på listan, säger det till dem, och webhooken call.do_not_call skickas. Nummer kan också läggas till och tas bort under Kampanjer → Spärrlista 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" }'
Nummer anges i internationellt format; upp till 1 000 åt gången. GET /api/v1/voice/do-not-call listar dem, nyaste först (search, limit, page), var och en med sin source (call, dashboard eller api). DELETE /api/v1/voice/do-not-call/%2B14155550100 tar bort ett igen; gör det bara när personen har samtyckt till att bli uppringd.
POST /api/v1/voice/voices skapar en röst från en WAV-inspelning av en talare (multipart audio, name, language, consent=true). Det svarar 202 med status running; fråga GET /api/v1/voice/voices tills den är ready, och sätt sedan en agents voice_id till rösten voice_id. language är det språk som talas i inspelningen, vilket som helst av agentspråken ovan; rösten talar alla utom kinesiska, där en inbyggd röst av samma kön svarar, och låter mest som talaren på inspelningens språk. Varje klonad röst kostar krediter, som panelen visar innan du skapar en.
Lägg till en https-adress under Integrationer → Webhooks och aviseringar för att ta emot samtalshändelser:
| Händelse | När |
|---|---|
call.started | Agenten svarade |
call.ended | Samtalet slutade, med längd och krediter |
call.analyzed | Sammanfattning, utfall, extraherade fält och utskrift är klara |
call.transcript | Under samtalet, de nya raderna i utskriften var några sekunder |
call.tool_called | Agenten anropade en av dina funktioner: name, arguments, status, durationMs |
call.handed_off | Samtalet lämnades över till en annan agent: fromAgentId, toAgentId |
call.transferred | Samtalet kopplades vidare till en person: destination |
call.voicemail | Ett utgående samtal nådde en röstbrevlåda |
call.do_not_call | Personen i ett utgående samtal bad att inte bli uppringd igen: phone |
call.recording_ready | Tvåkanalsinspelningen är sparad: recordingUrl (giltig i 24 timmar), durationMs |
call.message_sent | Agenten visade kort på en webb- eller appuppringares skärm: items, quickReplies |
alert.triggered | Ett av dina larm (Webhooks och aviseringar → Larm) passerade sitt tröskelvärde |
alert.resolved | Det larmet är tillbaka till normalt |
Händelser som skickas under ett samtal bär data.call (id, agentId, channel, direction, nummer). Varje anrop är signerat:
EvaSay-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
EvaSay-Delivery: <delivery id>
Verifiera signaturen med den webhook-hemlighet som visades när du skapade webhooken, och svara med en 2xx-status. Misslyckade leveranser försöks igen efter 1 minut, 5 minuter, 30 minuter, 2 timmar och 12 timmar med samma innehåll och samma EvaSay-Delivery-id, så du kan ignorera upprepningar. En webhooks senaste leveranser, med exakt skickat innehåll och den status din endpoint svarade, listas av GET /webhooks/{id}/deliveries och i panelen; POST /webhooks/{id}/deliveries/{delivery_id} skickar en igen.
Förutom e-post och webhooks alert.triggered / alert.resolved kan larm gå till en Slack-kanal (incoming webhook), en WeCom-grupprobot eller Telegram under Webhooks och aviseringar → Larm → Skicka även till.
Fel har en enda form:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_agent_field",
"message": "status must be draft or published",
"param": "status"
}
}
| Status | Betydelse |
|---|---|
| 400 | Ogiltig inmatning (code och param anger vilken) |
| 401 | API-nyckel saknas eller är ogiltig |
| 402 | Inte tillräckligt med krediter för att starta samtalet |
| 403 | Nyckeln är skrivskyddad, eller agenten är inte tillgänglig |
| 404 | Ingen sådan agent, ingen sådant samtal eller kampanj i den här arbetsytan |
| 409 | Fel tillstånd (t.ex. att starta en pågående kampanj), ett leverantörskonto är inte anslutet, eller numret står på spärrlistan (do_not_call) |
| 429 | För många anrop; sakta ner och försök igen |
Arbetsytans röst-API-anrop de senaste 30 dagarna (tid, endpoint, status, längd, nyckel och felkod; inget innehåll) listas under API-nycklar → API-förfrågningslogg.
Läsningar är begränsade till 120 anrop per minut och nyckel, skrivningar och samtal till 30.
Samtal debiteras per minut från arbetsytans krediter, samma saldo som panelen använder. Aktuella priser finns på prissidan.
Använd OpenAPI-kontraktet för att generera en integrationsklient. Det publika API:et, panelen och MCP-hanteringsendpointen arbetar på samma arbetsyteresurser och behörigheter.
| Förmåga | Endpoint |
|---|---|
| Återanvändbara verktyg | GET / POST /api/v1/voice/tools |
| Läsa / uppdatera / ta bort ett verktyg | GET / PATCH / DELETE /api/v1/voice/tools/{id} |
| Förhandsgranska eller testa ett verktyg | POST /api/v1/voice/tools/{id}/test |
| Koppla verktyg till en agent | PUT /api/v1/voice/agents/{id}/tools |
| Kunskapsbaser | GET / POST /api/v1/voice/knowledge-bases |
| Läsa / uppdatera / ta bort en kunskapsbas | GET / PATCH / DELETE /api/v1/voice/knowledge-bases/{id} |
| Lägga till / lista dokument | POST / GET /api/v1/voice/knowledge-bases/{id}/documents |
| Läsa / ta bort ett dokument | GET / DELETE /api/v1/voice/knowledge-bases/{id}/documents/{doc_id} |
| Prenumerationer på samtalshändelser | GET / POST /api/v1/voice/webhooks |
| Läsa / uppdatera / ta bort en prenumeration | GET / PATCH / DELETE /api/v1/voice/webhooks/{id} |
| Skicka en signerad testhändelse | POST /api/v1/voice/webhooks/{id}/test |
| Upptäcka fjärr-MCP-verktyg | POST /api/v1/voice/mcp/discover |
| MCP-hanteringsendpoint | /api/v1/voice/mcp |
Registrera ett HTTP-verktyg som frågar 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 returnerar { "data": { "id": "TOOL_ID", ... } }. Koppla dess definition till en agent med PUT /agents/AGENT_ID/tools och { "tool_ids": ["TOOL_ID"] }. Det ersätter hela verktygslistan med ögonblicksbilder; koppla om när ett bibliotekverktyg ändras. Att ta bort en definition i biblioteket behåller befintliga ögonblicksbilder. Du kan också läsa och ersätta inbäddade definitioner med agent-API:ets fält tools. Använd analysis_config och widget_config för att konfigurera analys och widget via agent-API:et.
Ett verktyg kan använda GET, POST, PUT, PATCH eller DELETE. query och request_body accepterar nästlade JSON-mallar som { "customer": { "id": "{{customer_id}}" } }. En hel platshållare behåller den ursprungliga JSON-typen. Platshållare i URL:en kodas och får bara stå efter en fast, publik HTTPS-värd. Utan request_body får verktyg som inte är GET { "arguments": {...}, "call": { "callId": "...", "agentId": "...", "toolCallId": "...", "idempotencyKey": "..." } }. response_path väljer ett fält med punktnotation. Enkla parameters accepteras fortfarande; input_schema stöder dessutom nästlade objekt, matriser, uppräkningar och numeriska gränser. Externa schemareferenser och reguljära uttryck accepteras inte.
static_args: värden som skickas med varje anrop oavsett vad modellen skriver, som ett butiks-id; de fyller också {{name}} i adressen och kroppen.extract: [{name, path}] behåller fält ur en funktions svar (data.id) till senare funktioners {{name}}, så att ett uppslags customer_id kan gå in i den beställning som följer utan att modellen upprepar det. Fält från ett startuppslag behålls på samma sätt.reject_when: upp till 5 regler {on: caller|agent, pattern, negate}; så länge alla gäller för de senaste orden körs inte funktionen och agenten får reject_message.model_says: vid varje anrop skriver modellen en mening som sägs medan funktionen körs, i stället för det fasta speak_before.Anslut en app under Integrationer → Webhooks och aviseringar → Anslutna appar och använd sedan „Lägg till en färdig funktion” på agentens flik Kunskap och verktyg; du behöver ingen egen endpoint:
check_availability (lediga tider ett visst datum) och book_appointment (bokar den tid uppringaren valde). Tider i Google Calendar följer den tidszon, de öppna dagar, de timmar och den mötestid du anger; Cal.com använder händelsetypens egen tillgänglighet och en reservadress för e-post som du anger för när uppringaren inte uppger någon.save_to_sheet, som lägger till en rad med de kolumner du listar, plus samtalets ID och tid.notify_team, som postar ett meddelande som agenten skriver i en Slack-kanal (incoming webhook).EvaSays kontrollplan kör dessa funktioner med det konto du anslöt; varken workern eller agentdefinitionen håller appens inloggningsuppgifter. När en agent läses via API:et visas de som kind: "app" (med app, action, connection_id, app_config); skicka tillbaka dem oförändrade när du ersätter tools för att behålla dem. Appar ansluts bara i panelen.
Sätt run_at_start: true på ett av en agents verktyg så anropas det när varje samtal börjar, innan agenten hälsar eller svarar. Parametrar som heter caller_number, called_number, direction, channel eller call_id fylls i åt det. De fält det returnerar fyller {{variables}} i first_message, system_prompt och idle_messages (fält en nivå ner som {{customer.name}}), och hela svaret ges till agenten som bakgrund. En hälsning med variabler väntar upp till 3 sekunder på svaret; allt som inte hittas lämnas tomt. Ett verktyg per agent kan köras vid start.
Inloggningsuppgifter konfigureras i servermiljön för din arbetsyta och ditt mål; be support@evasay.com att tillhandahålla en credential_ref. Lägg inte API-nycklar i agentdefinitioner, headers, prompter eller verktygsparametrar. Din adapter kan hålla CRM-inloggningsuppgifter i sin egen miljö.
Förhandsgranska ett verktyg innan du gör anrop till affärssystemet:
{
"arguments": { "customer_id": "customer-123" },
"dry_run": true,
"mock_result": { "name": "Alex", "order_status": "shipped" }
}
En förhandsgranskning validerar parametrarna och visar det mappade anropet; den kör inget samtal och kontaktar inte affärssystemet. Sätt dry_run=false för en verklig körning. Ett verkligt skrivtest kräver också confirmed=true och idempotency_key (8–128 bokstäver, siffror, punkter, understreck, kolon eller bindestreck). Testsvar innehåller ok, status, duration_ms och ett begränsat resultat. De returnerar inga inloggningsuppgifter. Läs- och skrivtest kräver skrivbehörighet i arbetsytan.
Under ett samtal bär affärsanrop en stabil Idempotency-Key. Din affärsendpoint måste respektera den. Identiska skrivningar inom ett samtal avdupliceras, även operationer med okänt utfall efter en timeout. En annan avsiktlig operation behöver ett eget affärsargument, som operation_id. EvaSay spelar inte upp skrivningar automatiskt igen. Händelser för verktygskörning innehåller status och längd; samtalstestfunktionen förblir en textsimulering, inte ett test av verktygskörning.
Konfigurera en Streamable HTTP-MCP-anslutning med:
URL: https://evasay.com/api/v1/voice/mcp
Authorization: Bearer <your EvaSay API key>
I Claude Code till exempel:
claude mcp add --transport http evasay https://evasay.com/api/v1/voice/mcp --header "Authorization: Bearer $EVASAY_API_KEY"
Anslutningen talar om för verktyget hur det bygger en agent: läs katalogen, skapa ett utkast, lägg till kunskap, funktioner och ordlistor, skriv tester och kör dem, rätta utkastet tills de går igenom, ge dig agentens dashboard_url att prova den med, och publicera och koppla ett nummer först när du godkänner. Verktyg som läser dokumentation kan börja från https://evasay.com/llms.txt, som länkar till den här sidan, OpenAPI-kontraktet och MCP-adressen.
Använd klientens säkra inställning för token eller miljövariabel. Endpointen använder API-nyckelautentisering, inte ett OAuth-inloggningsflöde. Den exponerar skapande och konfiguration av agenter, biblioteksverktyg, kunskap, webhooks och samtalsposter. Att publicera och ringa verkliga samtal är skrivåtgärder; utgående samtal förbrukar krediter och operatörsavgifter. Varje verktygsanrop kontrollerar arbetsytans behörigheter på nytt. Slå på din klients bekräftelsekontroller för skrivåtgärder. Endpointen använder tillståndslösa JSON-svar; den erbjuder ingen bakgrundsström med aviseringar.
Ett exempel på instruktion till kodningsverktyget är: „Skapa en EvaSay-agent som utkast, registrera min CRM-uppslagsendpoint, förhandsgranska den med testargument, koppla den till agenten och konfigurera en call.analyzed-webhook.” Granska och godkänn uttryckligen publicering och verkliga samtal.
POST /mcp/discover accepterar { "url": "https://crm.example.com/mcp", "credential_ref": "crm" } och returnerar serverns verktyg och scheman. Registrera bara det valda verktyget:
{
"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"]
}
}
Bara registrerade verktyg blir tillgängliga för agenten. Fjärranslutningar stöder Streamable HTTP med JSON- eller SSE-svar på anrop, publika HTTPS-mål och förkonfigurerade inloggningsuppgifter. Äldre SSE-endpoints, OAuth-förhandling, serverinitierad sampling/elicitation och binära bilagor stöds inte. Upptäckt ger inte automatiskt åtkomst till alla serverns verktyg. Fjärrverktygets schema måste vara inbäddat och använda den stödda delmängden av JSON Schema.
Skapa en webhook via POST /webhooks med { "url": "https://crm.example.com/evasay-events", "events": ["call.analyzed"] }. Svaret innehåller prenumerationen och en genererad signeringshemlighet, som bara returneras vid skapandet. Verifiera EvaSay-Signature, avduplicera EvaSay-Delivery och uppdatera ditt CRM. Händelsewebhooks är asynkrona aviseringar; verktyg under samtal returnerar resultat direkt till agenten.