API-et arbeider med de samme agentene, samtalene og kredittene som nettpanelet. Alt du bygger i panelet, kan styres fra dine egne systemer, og omvendt.
| Hva | Endpoint |
|---|---|
| List agenter | GET /api/v1/voice/agents |
| Opprett en agent | POST /api/v1/voice/agents |
| Hent / oppdater en agent | GET · PATCH /api/v1/voice/agents/{id} |
| Ring et utgående samtale | POST /api/v1/voice/calls |
| List samtaler | GET /api/v1/voice/calls |
| Hent en samtale (utskrift) | GET /api/v1/voice/calls/{id} |
| Slett en samtale | DELETE /api/v1/voice/calls/{id} |
| Slett samtalene til en innringer | POST /api/v1/voice/calls/delete-by-caller |
| Kampanjer | GET · POST /api/v1/voice/campaigns |
| Hent en kampanje | GET /api/v1/voice/campaigns/{id} |
| Start / pause / avbryt | POST /api/v1/voice/campaigns/{id}/{action} |
| Klonede stemmer | GET · POST /api/v1/voice/voices |
| Slett en klonet stemme | DELETE /api/v1/voice/voices/{id} |
| Reservasjonsliste | GET · POST /api/v1/voice/do-not-call |
| Fjern fra listen | DELETE /api/v1/voice/do-not-call/{phone} |
| Språk, stemmer, maler | GET /api/v1/voice/catalog |
| En agents tester | GET · POST /api/v1/voice/agents/{id}/tests |
| Kjør tester / les en kjøring | 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 |
Opprett en nøkkel under Integrasjoner → API-nøkler i panelet (eller med ett klikk på oversikten), og send den som et Bearer-token:
Authorization: Bearer sk-your-key
En nøkkel virker i arbeidsområdet der eieren arbeider, med den personens rolle: nøkkelen til et skrivebeskyttet medlem kan lese, men ikke endre noe.
Opprett en agent fra en mal, og angi eventuelt feltene i samme forespørsel. Uten template starter den tom; GET /api/v1/voice/catalog viser malene og språkene og stemmene en agent kan få. Malene er skrevet på engelsk og kinesisk, så for et annet språk sender du system_prompt og first_message på det språket. Enten lagres hele forespørselen, eller så opprettes ingen agent, så en avvist forespørsel kan sendes på nytt når den er rettet. dashboard_url i svaret er agentens side i dashbordet, der du kan snakke med utkastet i nettleseren. Hver agent kjører på EvaSay ASR, EvaSay LLM og EvaSay TTS, som EvaSay velger for hvert anrop etter språk og belastning, og som er inkludert i samtaleprisen; det finnes ingen kontoer hos andre leverandører å stille inn.
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..."
}'
Oppdater et hvilket som helst av disse feltene med PATCH /api/v1/voice/agents/{id}:
| Felt | Merknader |
|---|---|
name, first_message, system_prompt | Tekst |
status | published publiserer utkastet som en ny versjon; draft slutter å ta imot samtaler |
language | Ett av 27 språk, f.eks. en, zh, es, de, eller multi for å følge den som ringer |
temperature | 0-100 |
max_duration_sec, silence_timeout_sec | Samtalegrenser |
interruptible, end_call_enabled | Boolske verdier |
confirm_details | Boolsk; leser opp tall og navn igjen og får dem bekreftet |
ai_disclosure | Boolsk, standard true; før den første meldingen sier agenten på samtalens språk at den som ringer, snakker med en AI (utelates når den første meldingen allerede sier det) |
voicemail_detection | Boolsk; utgående samtaler lytter først og avsluttes ved en telefonsvarer |
voicemail_message | Legges igjen på en telefonsvarer, kan bruke {{variables}}; ingen for å legge på |
transfer_number | Nummer å stille om til, i internasjonalt format |
transfer_destinations | Opptil 9 numre til, [{name, number, when}]; agenten velger ett ut fra when |
transfer_briefing | Boolsk; den som svarer først, hører agentens sammendrag av samtalen |
pronunciations | Opptil 100 [{word, say, case_sensitive}]; stemmen sier say for word |
idle_messages | Opptil 3 påminnelser som sies etter tur til en taus innringer før samtalen avsluttes |
noise_reduction | Boolsk; innringerens bakgrunnsstøy filtreres før den høres |
recording_enabled | Boolsk; samtaler tas opp i to kanaler (innringeren til venstre, agenten til høyre) |
recording_consent | announce, ask (lagres bare hvis innringeren sier ja) eller none |
recording_notice | Meldingen eller spørsmålet som sies først; tomt for den innebygde teksten på samtalens språk |
handoffs | Opptil 5 [{agent_id, when}]: andre agenter som denne kan overlate en samtale til |
knowledge_base_id | En av kunnskapsbasene dine |
vocabulary_id | Et av ordforrådene dine; termene i det gjenkjennes sikrere når innringeren sier dem |
voice_id | En id for en innebygd EvaSay-stemme, eller en av de klonede stemmene dine (clone:…) |
Innebygde stemmer avhenger av språket: kinesisk har ming-designed-female-clear og ming-designed-female-warm (kvinnelige), ming-designed-male-clear og ming-designed-male-friendly (mannlige), de andre språkene har F1–F5 (kvinnelige) og M1–M5 (mannlige). En innebygd stemme som ikke snakker agentens språk, byttes ut med stemmen av samme kjønn som gjør det. Det eldre feltnavnet tts_voice_id godtas fortsatt. Enhver annen verdi for voice_id, eller en klonet stemme som ikke er klar ennå, avvises.
analysis_config bestemmer hva som utledes av hver samtale når den er slutt: summary (standard true), summaryLanguage, successCriteria (hva en vellykket samtale oppnår), fields (opptil 20 {name, type, description} å hente ut, der type er string, number eller boolean) og scorecard (opptil 10 {name, description, weight}, vekt 1–5). Resultatene ligger i samtalens analysis og i webhooken call.analyzed.
Når du endrer en agents felt, endrer du utkastet. Samtaler fortsetter å bruke den publiserte versjonen til du publiserer utkastet med POST /api/v1/voice/agents/{id}/publish (eventuelt med en note), eller med status: "published" i samme PATCH. Hver publisering lagrer en nummerert versjon; published_version i agenten forteller hvilken samtalene bruker. En samtale blir på versjonen som var aktiv da den startet, så publisering midt i en samtale endrer den ikke. Testsamtaler fra panelet bruker utkastet.
GET /agents/{id}/versions lister versjonene, og POST /agents/{id}/versions/{version}/restore ruller tilbake: nye samtaler bruker den versjonen, og utkastet blir den. Agentens navn, utrulling, widgetens utseende og varsler har ikke versjoner og endres umiddelbart, det samme gjør dokumentene i kunnskapsbasen.
En test spiller én samtale i tekst: en simulert innringer spiller scenario, agenten svarer fra utkastet sitt (instruksjoner, første melding og kunnskap), og en dommer vurderer samtalen mot success_criteria. Skriv tester for samtalene som betyr noe, kjør dem etter hver endring, og publiser 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 kjører alle agentens tester, eller dem i test_ids, og svarer med én kjøring per test (status: "running"). Spør GET /test-runs/{id} til status er passed, failed eller error; da har kjøringen transcript og dommerens reason (på engelsk, eller på kinesisk med reason_language: "zh"). Hver kjøring koster Credits, som vises ved testene i dashbordet; kjøringene stopper ved den første saldoen ikke kan betale for, og not_started viser resten. En kjøring som ikke kan fullføres, refunderes. Tester sjekker hva agenten sier, ikke stemmen eller timingen, og kaller ikke funksjonene: forhåndsvis dem med POST /tools/{id}/test. En agent har opptil 30 tester; PATCH og DELETE /agents/{id}/tests/{test_id} endrer eller fjerner en.
I tillegg til hele samtaler (type: "simulation", standard) kan en test sjekke ett enkelt svar. type: "next_reply" tar chat_history, samtalen før som slutter med innringeren ([{role, text}], der role er caller eller agent), og success_criteria for agentens neste svar. type: "tool_call" tar chat_history og expected_tool {name, arguments, match}: agenten skal kalle name (en av funksjonene sine, eller end_call, transfer_call, handoff_to_agent) med arguments, sammenlignet nøyaktig (tekst trimmet, store og små bokstaver ignorert) eller med match: "judge" etter betydning; andre argumenter ignoreres. En kjørings transcript viser de kalte funksjonene i tool_calls.
POST /agents/{id}/tests/generate foreslår tester ut fra agentens utkast: instruksjoner, kunnskap og funksjoner. Det tar count (1–10, standard 5), types, focus (hva som skal dekkes) og language (en eller zh, for navn og kriterier), koster Credits som én kjøring og svarer med utkast du ser over og sender til POST /agents/{id}/tests; med save: true lagres de.
hooks gjør noe på et bestemt tidspunkt i samtalen, opptil 10 regler: on: "silence" (innringeren har ikke sagt noe på seconds, 3–600, siden agenten ble ferdig; én gang til de snakker igjen), on: "time_elapsed" (seconds ut i samtalen, 10–3600) eller on: "call_ending". Hver regel gjør (do) opptil 3 av {type: "say", text}, {type: "transfer", destination?}, {type: "end_call", text?} og {type: "tool", name, args?}; en regel for samtalens slutt kjører bare funksjoner. En samtale som en regel avslutter, har ended_reason rule_ended.
I telefonsamtaler når tastene innringeren trykker på, agenten som svar: en inntasting avsluttes med # eller en pause på to sekunder. I utgående samtaler kan agenten også trykke på taster for å komme gjennom et selskaps telefonmeny.
transfer_number er agentens hovednummer for å gi en innringer videre til et menneske, og nummeret det ringes til når arbeidsområdet har gått tom for kreditter. transfer_destinations legger til navngitte numre, hvert med et notat om når det skal brukes («Fakturering: spørsmål om fakturaer og refusjoner»), og agenten velger. Med transfer_briefing på skriver agenten et kort sammendrag mens den kobler videre; personen som tar telefonen, hører det, med en EvaSay-stemme og på agentens sammendragsspråk, før innringeren settes gjennom. Samtalens ended_reason er da transferred.
Med handoffs kan en agent overlate en samtale til en annen publisert agent i arbeidsområdet ditt, for eksempel en resepsjon som gir en bestilling videre til en bestillingsagent. Agenten velger ut fra when. Den andre agenten overtar den samme samtalen med alt som er sagt så langt, og snakker med sine egne instruksjoner, stemme, kunnskap, verktøy og overleveringer. Samtalen forblir oppført, analysert og fakturert under den første agenten; utskriften noterer hver overlevering.
Numre kobles til i dashbordet 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 samtaler til en agent (den publiserte versjonen), eller med "agent_id": null til ingen; label gir det nytt navn.
En ordliste inneholder navn og uttrykk som innringere sier og som talegjenkjenning ellers ville hørt feil, for eksempel produkt-, medisin- eller gatenavn. POST /api/v1/voice/vocabularies med { "name": "Products", "terms": ["Lumora", "Vantix Pro"] } (opptil 1 000 uttrykk på 50 tegn, eller "preset": "medical" eller "legal" som utgangspunkt), og sett deretter agentens vocabulary_id. GET, PATCH (name, terms) og DELETE /vocabularies/{id}; en liste som en agent bruker, kan ikke slettes.
Hvert nummer har samtaleregler på siden Telefonnumre, som brukes før agenten svarer: blokkerte numre eller nummerbegynnelser (+1555) og innringere som skjuler nummeret sitt, avvises uten å bli besvart og koster ingenting; innringere på en liste kan settes rett gjennom til et annet nummer; og når agenten ikke kan svare (ikke publisert, ingen worker, tom for kreditter uten viderekoblingsnummer), kan samtalen ringe til et nummer eller spille av din egen melding. Et startoppslag (run_at_start) kan også avvise en innringer ved å svare {"reject": true, "message": "..."}: agenten sier meldingen, hvis det finnes en, og legger på, med ended_reason rejected.
Ring én samtale fra et av arbeidsområdets telefonnumre. Hver forespørsel trenger en unik Idempotency-Key; sendes samme nøkkel på nytt, får du samme samtale tilbake i stedet for at det ringes to ganger.
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åkrevd når arbeidsområdet har mer enn ett telefonnummer. variables fyller plassholdere som {{customer_name}} i agentens første melding og prompt.
GET /api/v1/voice/calls/{id} returnerer samtalens status, varighet, belastede kreditter, sammendrag, analyse og utskrift. List samtaler med GET /api/v1/voice/calls?agent_id=&status=&channel=&user_id=&page= (user_id: din egen id for personen, fra et nettsamtale-token). Dens turns er samtalens feilsøkingslogg, tur for tur: hvor tiden gikk fra innringeren ble ferdig med å snakke til de hørte svaret, i millisekunder — waitMs (slutten av talen), sttMs (gjenkjenning), llmMs (modellens første ord, ett ekstra for hver runde med funksjoner), ttsMs (stemmens første lyd), firstAudioMs (svaret ble hørt) — med funksjonene som ble kalt, avbrudd og feil. Samtalesiden viser den også.
Med recording_enabled tas hver samtale opp som en WAV med to kanaler: innringeren til venstre, agenten til høyre, med samtalens samplingfrekvens. Med recording_consent: "announce" sier agenten først at samtalen tas opp; med "ask" spør den, og opptaket lagres bare hvis innringeren sier ja (intet svar regnes som nei); med "none" sies ingenting. Sjekk hva loven krever der du og innringerne dine befinner dere.
Opptak lagres i EvaSays lagring eller i din egen S3-kompatible bucket (AWS S3, Cloudflare R2, Google Cloud Storage, Supabase, MinIO) som du stiller inn under Integrasjoner → Webhooks og varsler → Lagring av opptak. Workeren som kjører samtalen, laster filen opp rett til bucketen. GET /api/v1/voice/calls/{id} returnerer en recordingUrl som er gyldig i en time etter at opptaket er lagret, og recording.status (recording, stored, declined eller failed).
DELETE /api/v1/voice/calls/{id} sletter en avsluttet samtale med transkripsjon, opptak (i EvaSays lagring eller din egen bucket), analyse og webhook-leveranser. Brukte Credits blir stående i kreditthistorikken. En samtale som ikke kan slettes ennå, svarer 409 med code call_not_deletable_yet: den pågår eller ble nettopp avsluttet, avregnes fortsatt, opptaket lastes kanskje fortsatt opp, eller den skylder Credits som saldoen ikke dekket (kjøp Credits først).
Når noen ber deg slette dataene sine, sletter POST /api/v1/voice/calls/delete-by-caller med { "phone_number": "+14155550123" } alle samtaler med det nummeret (innringerens nummer ved innkommende samtaler, nummeret som ble ringt ved utgående), eller med { "user_id": "..." } alle nettsamtaler med den user_id i tokenet. Svaret er { "deleted": 12, "kept_back": { "settling": 1 }, "more": false }: høyst 200 samtaler per forespørsel, så spør igjen så lenge more er true, og senere igjen for samtalene i kept_back. Står nummeret på reservasjonslisten din, blir det stående der. I dashbordet gjøres det samme under Samtaler → Slett data om en innringer.
Send POST /api/v1/voice/calls/{id}/control mens en samtale pågår. Workeren som kjører samtalen, plukker opp kommandoen innen omtrent 2 sekunder; API-et svarer 202. Kan ikke workeren som kjører samtalen nås, svarer API-et 503 (code call_unreachable), og kommandoen utføres ikke.
type | Hva som skjer |
|---|---|
say | Agenten sier text etter den pågående setningen, eller med en gang med "interrupt": true |
note | Agenten får vite text (sies ikke) og tar hensyn til det fra neste svar; utskriften noterer det |
end | Agenten sier text hvis den er oppgitt, og legger deretter på; en telefonsamtale uten text legges på med en gang |
Samtalens ended_reason er da api_ended. Samtalesiden i panelet har de samme kontrollene.
POST /api/v1/voice/calls/{id}/listen (eventuelt { "channels": 2 }) returnerer en listen_url du kan åpne innen to minutter. Det er en WebSocket: først en JSON-melding {"type":"start","sampleRate":8000,"channels":1,"encoding":"pcm_s16le"}, deretter binære rammer med 16-biters little-endian PCM med det innringeren hører (begge stemmene blandet; med channels: 2 innringeren til venstre og agenten til høyre). Den lukkes når samtalen avsluttes. Lyden kommer rett fra workeren som kjører samtalen, ikke gjennom EvaSays kontrollplan; Lytt-knappen på panelets samtaleside bruker den samme adressen.
Send og motta lyden fra en samtale fra ditt eget program, for eksempel ditt eget telefonsystem eller din app. Start samtalen:
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 har et engangstoken og kan åpnes innen 15 minutter. encoding er pcm_s16le (16-biters little-endian PCM med en sample_rate på 8000, 16000 eller 24000) eller mulaw (8 kHz μ-law). Lyden går begge veier som binære rammer i det formatet, helst på 20 ms hver. Tekstrammer er JSON:
| Retning | Meldinger |
|---|---|
| Du → EvaSay | {"type":"dtmf","digits":"12#"} tastetrykk; {"type":"end"} legger på; {"type":"text","text":"…"} ord innringeren skrev ("input":"button" for et tappet svar); {"type":"context","text":"…","key":"cart"} det appen din melder (agenten svarer ikke på det); {"type":"tool_result","id":"…","result":{…}} (eller "error") svaret fra en sidefunksjon |
| EvaSay → deg | start (med callId); clear (innringeren avbrøt: kast agentens lyd som ikke er spilt av ennå); 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: kjør en av sidefunksjonene dine); notice (code: too_fast eller limit for skrevne ord); ended (med reason, deretter lukkes socketen) |
Agenten hilser så snart du kobler til. user_id og page_tools (sidefunksjonene appen din svarer på, se nedenfor) kan legges til i forespørselen. Samtaler faktureres per minutt som alle andre, med de samme samtalepostene, den samme analysen og de samme webhookene.
I en nettsamtale (widgeten, den vertsbaserte siden, appen din) ser innringeren en chat ved siden av stemmen, slik at agenten kan gjøre mer enn å snakke. Innringere på telefon får ikke noe av dette.
Slå på Agent → Verktøy → Send til innringeren (send_to_caller i agent-API-et), så kan agenten legge opptil fem kort om gangen på innringerens skjerm: en tittel, en linje under, en beskrivelse, et bilde, en lenke og opptil to svarknapper hver; den kan også tilby opptil tre hurtigsvar under et spørsmål. Lenker leses aldri opp.
Agenten kan bare sende lenker og bilder den har fått i den samtalen: instruksjonene og hilsenen, kunnskapsbasen (et dokument lest fra en nettside bærer adressen til siden), svarene fra funksjonene dine og de ferdige kortene. En lenke må i tillegg være på en av allowed_hosts (et ferdig korts eget nettsted er alltid det). Lenker agenten finner på, eller som innringeren leser opp, sendes ikke. Lenker til de nettstedene i agentens ord kan klikkes 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 sending sendes til deg som webhooken call.message_sent (channel, items med title og url, quickReplies, blocked). En samtale sender høyst 10 ganger.
Under samtalen kan innringeren også skrive (en e-postadresse, et ordrenummer) eller trykke på en svarknapp; agenten svarer på det som på tale og stopper først hvis den snakket. Opptil 500 tegn per melding, én i sekundet, 100 per samtale. I samtaleposten er disse turene merket som skrevne eller tappede.
Widgeten gir siden din et evasay-objekt. Alt er valgfritt, og samtalerammen lytter bare til siden din hvis den er et av widgetens tillatte nettsteder (Agent → Rull ut):
<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 instruksjonene og hilsenen. De kommer fra den besøkendes nettleser, så agenten får beskjed om at de ikke er verifisert, og de når aldri funksjonene dine eller startoppslaget.update forteller agenten hva som skjer på siden uten å få den til å svare; en nyere oppdatering med samme key erstatter den eldre."kind": "page", ingen url) på agenten, og registrer en funksjon med samme navn på siden din. Agenten kan bare kalle den i samtaler fra en side som har registrert den; den venter opptil timeout_sec (1–10, standard 5) på svaret med mindre wait_for_result er false. Den kjører innlogget som den besøkende, som et klikk fra dem: be om bekreftelse på din egen side før alt som koster penger eller ikke kan angres. Lenker i svaret kan sendes som kort.Sett Hvem som kan starte en samtale til Bare med et token, og la serveren din hente et engangstoken for den innloggede brukeren:
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 har token (én samtale, innen expires_in sekunder, 30–3600, standard 600), agent (sluggen) og web_call_url. Gi tokenet til siden med data-token-url="/your/endpoint" på widgetens skript (den POST-er dit med den besøkendes informasjonskapsler og leser { "token": "…" }) eller med agent.setToken(async () => token). Tokenets variables er verifisert: instruksjonene, startoppslaget og malene til funksjonene dine kan bruke dem, det samme kan user_id, som samtalen beholder (userId i samtalen, user_id for å filtrere samtaler). Behold API-nøkkelen din på serveren din.
I din egen app POST-er du { "token": "…", "pageTools": ["add_to_cart"] } til https://evasay.com + web_call_url. Svaret er samtalens tilkobling (en WebRTC-tilbudsadresse eller en WebSocket-adresse med samtaletoken) for en RTVI-klient som Pipecats klient-SDK-er for web, iOS, Android og React Native. Kort, sidefunksjoner og varsler 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 sentralbord, SIP-telefonene dine eller SIP-trunken din ringe agentene dine direkte; SIP-leverandøren din fakturerer samtalene:
sip:ev…@<EvaSay's SIP domain>, bare innkommende samtaler, for sentralbord (3CX, FreePBX, Asterisk…) og SIP-telefoner.from); viderekoblinger til en person leveres til trunken med REFER. Når trunken ber om legitimasjon, svarer EvaSay med trunkens brukernavn og passord som du har oppgitt.Innkommende samtaler logger inn med digest med brukernavnet og passordet EvaSay gir deg (realm er SIP-domenet); du kan også begrense kilde-IP-ene, eller bare godta på IP når leverandøren din ikke kan logge inn (IP-ene er da påkrevd). Hver SIP-adresse eller trunk har en grense for samtidige samtaler; over den får samtaler 486. Passord vises én gang, når de opprettes eller tilbakestilles. Bare UDP og G.711 (PCMU, PCMA); tastetrykk via RFC 4733 eller SIP INFO; slå av registrering (REGISTER) på sentralbordets trunk.
En kampanje ringer en liste med kontakter med én agent, innenfor ringetider og en samtidighetsgrense (max_concurrency, opptil 100 samtaler om gangen og aldri flere enn arbeidsområdets grense for samtidige samtaler), og prøver på nytt med personer den ikke fikk tak 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åkrevd: med det bekrefter du at alle på listen har samtykket i å bli oppringt, også av en AI-stemme, og EvaSay lagrer den bekreftelsen sammen med kampanjen (consent_confirmed_at). Kampanjen opprettes som et utkast; start den med POST /api/v1/voice/campaigns/{id}/start, og bruk pause eller cancel på samme måte. Agenten må være publisert før en kampanje starter.
Med voicemail_detection på (standard) lytter en utgående samtale etter at den andre siden snakker før agenten hilser; hvis de forblir tause, hilser agenten etter to eller tre sekunder. Når agenten hører en telefonsvarer eller et opptak fra en teleoperatør, venter den til hilsenen og pipet er over, legger igjen voicemail_message, eller legger på når det ikke finnes noen. Slike samtaler avsluttes med ended_reason voicemail, belastes for tiden de varte, og analyseres eller varsles ikke.
I en kampanje ringes et nummer som nådde en telefonsvarer, opp igjen som ett som ikke svarte, og meldingen legges bare igjen ved siste forsøk, slik at ingen får samme melding to ganger.
Hver utgående samtale, fra en kampanje eller fra POST /api/v1/voice/calls, sjekker først arbeidsområdets reservasjonsliste. Et nummer på listen ringes aldri: API-et svarer 409 med code do_not_call, og en kampanje markerer kontakten som canceled med outcome do_not_call og går videre til neste.
Når personen i en samtale agenten ringte, ber om ikke å bli oppringt igjen, setter agenten selv nummeret på listen, sier fra til dem, og webhooken call.do_not_call sendes. Numre kan også legges til og fjernes under Kampanjer → Reservasjonsliste 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 oppgis i internasjonalt format; opptil 1 000 om gangen. GET /api/v1/voice/do-not-call lister dem, nyeste først (search, limit, page), hvert med sin source (call, dashboard eller api). DELETE /api/v1/voice/do-not-call/%2B14155550100 tar ett av listen igjen; gjør det bare når personen har samtykket i å bli oppringt.
POST /api/v1/voice/voices oppretter en stemme fra et WAV-opptak av én taler (multipart audio, name, language, consent=true). Det svarer 202 med status running; spør GET /api/v1/voice/voices til den er ready, og sett deretter en agents voice_id til stemmens voice_id. language er språket som snakkes i opptaket, hvilket som helst av agentspråkene ovenfor; stemmen snakker dem alle unntatt kinesisk, der en innebygd stemme av samme kjønn svarer, og den ligner mest på taleren i opptaket på opptakets språk. Hver klonede stemme koster kreditter, som panelet viser før du oppretter en.
Legg til en https-adresse under Integrasjoner → Webhooks og varsler for å motta samtalehendelser:
| Hendelse | Når |
|---|---|
call.started | Agenten tok telefonen |
call.ended | Samtalen ble avsluttet, med varighet og kreditter |
call.analyzed | Sammendrag, utfall, uttrukne felt og utskrift er klare |
call.transcript | Under samtalen, de nye linjene i utskriften hvert par sekunder |
call.tool_called | Agenten kalte en av funksjonene dine: name, arguments, status, durationMs |
call.handed_off | Samtalen ble overlatt til en annen agent: fromAgentId, toAgentId |
call.transferred | Samtalen ble koblet videre til en person: destination |
call.voicemail | En utgående samtale nådde en telefonsvarer |
call.do_not_call | Personen i en utgående samtale ba om ikke å bli oppringt igjen: phone |
call.recording_ready | Opptaket med to kanaler er lagret: recordingUrl (gyldig i 24 timer), durationMs |
call.message_sent | Agenten viste kort på skjermen til en nett- eller appinnringer: items, quickReplies |
alert.triggered | En av alarmene dine (Webhooks og varsler → Alarmer) passerte terskelen |
alert.resolved | Den alarmen er tilbake til normalt |
Hendelser som sendes under en samtale, bærer data.call (id, agentId, channel, direction, numre). Hver forespørsel er signert:
EvaSay-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
EvaSay-Delivery: <delivery id>
Verifiser signaturen med webhook-hemmeligheten som ble vist da du opprettet webhooken, og svar med en 2xx-status. Mislykkede leveringer prøves på nytt etter 1 minutt, 5 minutter, 30 minutter, 2 timer og 12 timer med samme innhold og samme EvaSay-Delivery-id, så du kan ignorere gjentakelser. En webhooks siste leveringer, med det nøyaktige innholdet som ble sendt og statusen endpointet ditt svarte med, listes av GET /webhooks/{id}/deliveries og i panelet; POST /webhooks/{id}/deliveries/{delivery_id} sender én på nytt.
I tillegg til e-post og webhookene alert.triggered / alert.resolved kan alarmer gå til en Slack-kanal (incoming webhook), en WeCom-gruppebot eller Telegram under Webhooks og varsler → Alarmer → Send også til.
Feil har én form:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_agent_field",
"message": "status must be draft or published",
"param": "status"
}
}
| Status | Betydning |
|---|---|
| 400 | Ugyldig inndata (code og param sier hvilken) |
| 401 | Manglende eller ugyldig API-nøkkel |
| 402 | Ikke nok kreditter til å starte samtalen |
| 403 | Nøkkelen er skrivebeskyttet, eller agenten er utilgjengelig |
| 404 | Ingen slik agent, samtale eller kampanje i dette arbeidsområdet |
| 409 | Feil tilstand (f.eks. å starte en kampanje som kjører), en leverandørkonto er ikke koblet til, eller nummeret står på reservasjonslisten (do_not_call) |
| 429 | For mange forespørsler; senk tempoet og prøv igjen |
Arbeidsområdets Voice API-forespørsler de siste 30 dagene (tid, endpoint, status, varighet, nøkkel og feilkode; ikke innhold) listes under API-nøkler → Logg over API-forespørsler.
Lesing er begrenset til 120 forespørsler i minuttet per nøkkel, skriving og samtaler til 30.
Samtaler faktureres per minutt fra arbeidsområdets kreditter, den samme saldoen panelet bruker. Gjeldende priser står på prissiden.
Bruk OpenAPI-kontrakten til å generere en integrasjonsklient. Det offentlige API-et, panelet og MCP-administrasjonsendpointet arbeider på de samme arbeidsområderessursene og tillatelsene.
| Funksjon | Endpoint |
|---|---|
| Gjenbrukbare verktøy | GET / POST /api/v1/voice/tools |
| Les / oppdater / slett et verktøy | GET / PATCH / DELETE /api/v1/voice/tools/{id} |
| Forhåndsvis eller test et verktøy | POST /api/v1/voice/tools/{id}/test |
| Bind verktøy til en agent | PUT /api/v1/voice/agents/{id}/tools |
| Kunnskapsbaser | GET / POST /api/v1/voice/knowledge-bases |
| Les / oppdater / slett en kunnskapsbase | GET / PATCH / DELETE /api/v1/voice/knowledge-bases/{id} |
| Legg til / list dokumenter | POST / GET /api/v1/voice/knowledge-bases/{id}/documents |
| Les / slett et dokument | GET / DELETE /api/v1/voice/knowledge-bases/{id}/documents/{doc_id} |
| Abonnementer på samtalehendelser | GET / POST /api/v1/voice/webhooks |
| Les / oppdater / slett et abonnement | GET / PATCH / DELETE /api/v1/voice/webhooks/{id} |
| Send en signert testhendelse | POST /api/v1/voice/webhooks/{id}/test |
| Finn eksterne MCP-verktøy | POST /api/v1/voice/mcp/discover |
| MCP-administrasjonsendpoint | /api/v1/voice/mcp |
Registrer et HTTP-verktøy som spør CRM-adapteren din:
{
"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 definisjonen til en agent med PUT /agents/AGENT_ID/tools og { "tool_ids": ["TOOL_ID"] }. Dette erstatter hele verktøylisten med øyeblikksbilder; bind på nytt når et bibliotekverktøy endres. Å slette en definisjon i biblioteket beholder eksisterende øyeblikksbilder. Du kan også lese og erstatte innebygde definisjoner med agent-API-ets felt tools. Bruk analysis_config og widget_config for å konfigurere analysen og widgeten via agent-API-et.
Et verktøy kan bruke GET, POST, PUT, PATCH eller DELETE. query og request_body godtar nestede JSON-maler som { "customer": { "id": "{{customer_id}}" } }. En hel plassholder beholder den opprinnelige JSON-typen. Plassholdere i URL-en kodes og kan bare stå etter en fast, offentlig HTTPS-vert. Uten request_body får verktøy som ikke er GET, { "arguments": {...}, "call": { "callId": "...", "agentId": "...", "toolCallId": "...", "idempotencyKey": "..." } }. response_path velger et felt med punktnotasjon. Enkle parameters godtas fortsatt; input_schema støtter i tillegg nestede objekter, matriser, opplistinger og numeriske grenser. Eksterne skjemareferanser og regulære uttrykk godtas ikke.
static_args: verdier som sendes med hvert kall uansett hva modellen skriver, som en butikk-id; de fyller også {{name}} i adressen og kroppen.extract: [{name, path}] beholder felt fra en funksjons svar (data.id) til senere funksjoners {{name}}, slik at et oppslags customer_id kan gå inn i bestillingen som følger uten at modellen gjentar det. Felt fra et startoppslag beholdes på samme måte.reject_when: opptil 5 regler {on: caller|agent, pattern, negate}; så lenge alle gjelder for de siste ordene, kjøres ikke funksjonen, og agenten får reject_message.model_says: ved hvert kall skriver modellen én setning som sies mens funksjonen kjører, i stedet for det faste speak_before.Koble til en app under Integrasjoner → Webhooks og varsler → Tilkoblede apper, og bruk deretter «Legg til en ferdig funksjon» på agentens fane Kunnskap og verktøy; du trenger ikke noe eget endpoint:
check_availability (ledige tider på en dato) og book_appointment (bestiller tiden innringeren valgte). Tider i Google Calendar følger tidssonen, åpne dager, timer og avtalelengde du angir; Cal.com bruker hendelsestypens egen tilgjengelighet og en reserve-e-postadresse du angir for når innringeren ikke oppgir noen.save_to_sheet, som legger til en rad med kolonnene du lister, pluss samtalens ID og tid.notify_team, som poster en melding agenten skriver, i en Slack-kanal (incoming webhook).EvaSays kontrollplan kjører disse funksjonene med kontoen du koblet til; verken workeren eller agentdefinisjonen har appens legitimasjon. Når en agent leses via API-et, vises de som kind: "app" (med app, action, connection_id, app_config); send dem tilbake uendret når du erstatter tools, for å beholde dem. Apper kobles bare til i panelet.
Sett run_at_start: true på et av en agents verktøy, så kalles det når hver samtale begynner, før agenten hilser eller svarer. Parametere med navnene caller_number, called_number, direction, channel eller call_id fylles ut for det. Feltene det returnerer, fyller {{variables}} i first_message, system_prompt og idle_messages (felt ett nivå ned som {{customer.name}}), og hele svaret gis til agenten som bakgrunn. En hilsen med variabler venter opptil 3 sekunder på svaret; alt som ikke finnes, blir stående tomt. Ett verktøy per agent kan kjøre ved start.
Legitimasjon konfigureres i servermiljøet for arbeidsområdet og målet ditt; be support@evasay.com opprette en credential_ref. Ikke legg API-nøkler i agentdefinisjoner, headere, prompter eller verktøyparametere. Adapteren din kan ha CRM-legitimasjonen i sitt eget miljø.
Forhåndsvis et verktøy før du sender forespørsler til forretningssystemet:
{
"arguments": { "customer_id": "customer-123" },
"dry_run": true,
"mock_result": { "name": "Alex", "order_status": "shipped" }
}
En forhåndsvisning validerer parameterne og viser den avbildede forespørselen; den kjører ingen samtale og kontakter ikke forretningssystemet. Sett dry_run=false for en reell kjøring. En reell skrivetest krever også confirmed=true og idempotency_key (8–128 bokstaver, tall, punktum, understreker, kolon eller bindestreker). Testsvar inneholder ok, status, duration_ms og et avgrenset resultat. De returnerer ikke legitimasjon. Lese- og skrivetester krever skrivetillatelse i arbeidsområdet.
Under en samtale bærer forretningsforespørsler en stabil Idempotency-Key. Forretningsendpointet ditt må respektere den. Identiske skrivinger innenfor en samtale avdupliseres, også operasjoner med ukjent utfall etter en tidsavbrytelse. En annen tilsiktet operasjon trenger et eget forretningsargument, som operation_id. EvaSay spiller ikke av skrivinger automatisk på nytt. Hendelser for verktøykjøring inneholder status og varighet; samtaletestfunksjonen er fortsatt en tekstsimulering, ikke en test av verktøykjøring.
Konfigurer en Streamable HTTP-MCP-tilkobling 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"
Tilkoblingen forteller verktøyet hvordan det bygger en agent: les katalogen, lag et utkast, legg til kunnskap, funksjoner og ordlister, skriv tester og kjør dem, rett utkastet til de består, gi deg agentens dashboard_url for å prøve den, og publiser og tildel et nummer først når du godkjenner. Verktøy som leser dokumentasjon kan starte fra https://evasay.com/llms.txt, som lenker til denne siden, OpenAPI-kontrakten og MCP-adressen.
Bruk klientens sikre innstilling for token eller miljøvariabel. Endpointet bruker API-nøkkelautentisering, ikke et OAuth-innloggingsflyt. Det eksponerer opprettelse og konfigurasjon av agenter, bibliotekverktøy, kunnskap, webhooks og samtaleposter. Å publisere og ringe ekte samtaler er skrivehandlinger; utgående samtaler bruker kreditter og operatøravgifter. Hvert verktøykall sjekker arbeidsområdets tillatelser på nytt. Slå på klientens bekreftelseskontroller for skrivehandlinger. Endpointet bruker tilstandsløse JSON-svar; det tilbyr ikke en varselstrøm i bakgrunnen.
Et eksempel på en instruksjon til kodeverktøyet er: «Opprett en EvaSay-agent som utkast, registrer CRM-oppslagsendpointet mitt, forhåndsvis det med testargumenter, bind det til agenten, og konfigurer en call.analyzed-webhook.» Gjennomgå og godkjenn uttrykkelig publisering og ekte samtaler.
POST /mcp/discover godtar { "url": "https://crm.example.com/mcp", "credential_ref": "crm" } og returnerer serverens verktøy og skjemaer. Registrer bare det valgte verktøyet:
{
"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"]
}
}
Bare registrerte verktøy blir tilgjengelige for agenten. Eksterne tilkoblinger støtter Streamable HTTP med JSON- eller SSE-svar på forespørsler, offentlige HTTPS-mål og forhåndskonfigurert legitimasjon. Eldre SSE-endpoints, OAuth-forhandling, serverinitiert sampling/elicitation og binære vedlegg støttes ikke. Oppdaging gir ikke automatisk tilgang til alle serverens verktøy. Det eksterne verktøyets skjema må være innebygd og bruke den støttede delmengden av JSON Schema.
Opprett en webhook via POST /webhooks med { "url": "https://crm.example.com/evasay-events", "events": ["call.analyzed"] }. Svaret inneholder abonnementet og en generert signeringshemmelighet, som bare returneres ved opprettelsen. Verifiser EvaSay-Signature, avduplisér EvaSay-Delivery, og oppdater CRM-et ditt. Hendelseswebhooks er asynkrone varsler; verktøy under samtaler returnerer resultater direkte til agenten.