Napojení
REST API
Kompletní reference API v1. Vše je JSON a chyby mají jednotný tvar. Ceny volai jsou celá čísla v haléřích (přípona Hal); připojené faktury používají nejmenší jednotky uvedené měny.
Autentizace
Každý požadavek nese API klíč v hlavičce Authorization: Bearer vk_... . Klíč získáš v portálu v sekci Přístupy a API (podrobněji v Quickstartu).
curl https://volai.cz/v1/balance \
-H "Authorization: Bearer vk_TVUJ_KLIC"Celé tohle API má i strojově čitelný popis na GET /openapi.json (OpenAPI 3.1, bez API klíče) - vygeneruj si z něj klienta, kolekci do Postmanu, nebo ho napoj rovnou do n8n.
Formát chyb
Neúspěch má vždy stejný tvar, ať selže cokoli:
{
"error": {
"code": "insufficient_credit",
"cause": "account",
"message": "Insufficient credit. Account balance is 3.00 CZK. Top up at volai.cz/en/credit and try again.",
"action": "Top up the credit at https://volai.cz/en/credit (or ask the account owner to), then send the request again. Nothing was charged and volai itself is up.",
"requestId": "req_9f2b7a1c4e6d8f0a",
"docsUrl": "https://volai.cz/en/docs/api#errors"
}
}Těchhle pět kódů se může objevit prakticky kdekoli - u jednotlivých endpointů níž jsou dopsané jen situační kódy navíc:
| HTTP | Kód | Příčina | Význam |
|---|---|---|---|
| 401 | unauthorized | request | Chybí nebo je neplatná hlavička Authorization. |
| 402 | insufficient_credit | account | Na akci nezbývá dost kreditu. |
| 403 | account_suspended | account | Provozovatel volai účet ručně pozastavil - napiš na podpora@volai.cz. Daňové doklady (GET /v1/billing/documents, /{id} a /{id}/pdf, v MCP list_billing_documents a get_billing_document) zůstávají dostupné i během pozastavení. |
| 429 | rate_limited | busy | Překročený rate limit - u endpointu s API klíčem počkej podle hlavičky Retry-After; veřejný GET /v1/changelog tuhle hlavičku neposílá. |
| 500 | internal_error | service | Chyba na naší straně - zkus to prosím znovu. |
400 (neplatný vstup) a 404 (záznam neexistuje) taky můžou přijít prakticky kdekoli, ale jejich code je specifický pro dané pole nebo endpoint - přesný výčet je vždy u konkrétního volání níž. Pár akcí navíc může vrátit 502 (chyba u externího poskytovatele - telefonní síť, ElevenLabs) nebo 503 (dočasně nedostupné, zkus to za chvíli).
Kdo za chybu může: cause a action
Každá chyba nese navíc cause (čtyři hodnoty) a action (jedna anglická věta, co udělat, kterou můžeš uživateli přečíst doslova). cause je strojově čitelná odpověď na otázku, jestli má chybu opravit tvůj kód, tvůj účet, čas, nebo my:
| Příčina | Kdo to opraví |
|---|---|
request | Tělo, URL, hlavičky požadavku nebo argumenty nástroje - včetně chybějícího nebo neplatného API klíče. Oprav vstup a pošli znovu; volai běží. |
account | Stav tvého účtu: kredit, limity, vlastnictví čísla nebo agenta, ověření e-mailu, konfigurace, nebo záznam, který na účtu neexistuje. Tělo je v pořádku; změň stav účtu (v portálu nebo jiným voláním), případně vezmi správné id z výpisu, a zkus to znovu. |
busy | Dočasný zámek nebo limit okamžiku (jiná operace nad tím samým záznamem ještě běží, rate limit). Počkej pár sekund a pošli TOTÉŽ znovu, nic neměň. |
service | My nebo náš dodavatel (operátor, hlasová platforma). Na tvé straně není co opravit; zkus to za chvíli, a když to trvá, napiš na podpora@volai.cz s requestId. |
Pro AI agenty (Claude Code, Cursor, vlastní skripty): podle cause řekni uživateli, kdo chybu opraví. U request vyjmenuj pole z message, u account řekni, co v účtu změnit nebo které id zkontrolovat, u busy počkej a zopakuj, a jen u service mluv o problému na straně volai. Nikdy nehlas request, account ani busy jako výpadek volai.
Příčina je určená kódem, ne HTTP statusem: kvóty účtu (agent_limit, tool_limit, api_key_limit, relay_lease_limit) vrací 400, a přesto jsou account; not_found u záznamu je account (z odpovědi nejde poznat, jestli cizí id existuje), u neznámé cesty pod /v1 je request. Úplné přiřazení kódů k příčinám je u každé operace v GET /openapi.json (popis chybových odpovědí).
Hláška u kódu validation říká pole (tečkovaná cesta v těle, například dataFields.0.type), skutečnou hodnotu a přijatý strop, například Field "knowledge" is 210000 characters long, the maximum accepted is 200000. nebo Field "systemPrompt" is required. Produktové limity (60 / 6000 / 300 / 20000 znaků u jména, instrukcí, cíle a podkladů agenta) hlásí vlastní kódy invalid_name, invalid_system_prompt, invalid_goal, invalid_knowledge s přesným číslem. Neznámé pole ve striktních tělech (koncept agenta) vrací Unknown field "revision". Remove it; the documentation lists the accepted fields.
requestId a docsUrl
Úplně každá odpověď v1 (úspěšná i chybová) nese v hlavičce X-Request-Id jedinečné ID požadavku (req_ + 16 hex znaků) - u chyby je stejná hodnota navíc přímo v těle jako requestId. Přehraná idempotentní odpověď (viz Idempotence níž) dostane VLASTNÍ aktuální requestId - hlavička a tělo se u ní nikdy neliší, i když zbytek odpovědi je doslova stejný jako napoprvé. Pošli tohle ID podpoře a najde přesně tenhle jeden požadavek v logu.
Chybové tělo nese navíc docsUrl - odkaz rovnou sem, na tuhle sekci.
U konceptu agenta (viz sekci Koncept agenta níž) chyba revision_conflict nese navíc currentRevision - aktuální revizi. Načti ji přes GET .../draft a porovnej rozdíl, než uložení zopakuješ - neposílej naslepo to samé tělo se stejnou expectedRevision.
{
"error": {
"code": "revision_conflict",
"cause": "request",
"message": "The draft has changed since you last read it. Fetch the latest revision and try again.",
"action": "Reload the record you are changing - GET /v1/agents/{id}/draft (or the get_agent_draft tool) for an agent draft, GET /v1/tasks/{id} (or the get_task tool) for a task - reapply your change on top of its current revision and send the request again with that value in expectedRevision (agent draft) or revision (task). This is not a volai outage.",
"currentRevision": 4,
"requestId": "req_9f2b7a1c4e6d8f0a",
"docsUrl": "https://volai.cz/en/docs/api#errors"
}
}Hlavičky
Po ověření klíče nese KAŽDÁ odpověď (úspěšná i chybová) hlavičky RateLimit-Limit, RateLimit-Remaining a RateLimit-Reset (vteřin do konce aktuálního okna) - u 429 z limitu API klíče navíc Retry-After se stejným počtem vteřin. 429 rate_limited z limitu odchozích hovorů (POST /v1/calls) nese v Retry-After vlastní čekání do uvolnění toho limitu, když je známé.
401 nese hlavičku WWW-Authenticate: Bearer realm="volai", error="invalid_token" (RFC 6750) - HTTP knihovna z ní pozná důvod selhání, aniž by musela parsovat tělo.
Neznámá cesta a špatná metoda
Neznámá cesta pod /v1 (i holé /v1) vrací JSON 404 se stejným tvarem chyby jako kdekoli jinde - {"error":{"code":"not_found", ...}} - pro všechny metody (GET, POST, PUT, PATCH, DELETE, OPTIONS i HEAD). Výjimka: špatná METODA na EXISTUJÍCÍ cestě (například DELETE /v1/balance) zůstává obyčejná Next.js 405 bez JSON těla - tohle je jediné místo v celém API v1, kde neúspěch nemá popsaný tvar chyby.
Idempotence
POST /v1/messages, POST /v1/calls, POST /v1/relay, POST /v1/numbers, POST /v1/numbers/orders, POST /v1/sms-numbers, POST /v1/agents, POST /v1/tools, POST /v1/agents/{id}/draft/publish, POST /v1/agents/{id}/test-call, POST /v1/integrations, POST /v1/tasks, POST /v1/tasks/{id}/start, POST /v1/tasks/{id}/process, POST /v1/credit/topup a POST /v1/credit/auto-topup/setup umí hlavičku Idempotency-Key. Rozsah klíče je globální pro daný API klíč, bez ohledu na HTTP metodu, cestu nebo tělo. Každá odlišná logická akce napříč všemi endpointy a těly proto potřebuje novou hodnotu; stejnou hodnotu použij jen při opakování přesně téhož logického požadavku, typicky po timeoutu, kdy nevíš, jestli první pokus prošel. Do 24 hodin pak dostaneš zpátky přesně tutéž odpověď jako napoprvé, včetně chybové, dopadl-li první pokus chybou, a nic se neodešle ani nezavolá podruhé. Klidně použij ID objednávky ze své appky doplněné o název konkrétní akce. Souběžný požadavek se stejným klíčem, který ještě běží (odpověď se teprve ukládá), vrátí 409 idempotency_in_progress - zkus to prosím za chvíli znovu.
U POST /v1/numbers/orders se klíč trvale spojí s objednávkou ještě před voláním operátora; stejný klíč s jinou adresou vrátí 409 idempotency_conflict. Pokud operátor po nákupu vrátí nejasnou odpověď, může být potřeba kontrola stavu objednávky.
curl -X POST https://volai.cz/v1/messages \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: objednavka-4471" \
-d '{"to": "+420777123456", "body": "Děkujeme za objednávku."}'Rate limity
60 požadavků za minutu na jeden API klíč (MCP sdílí stejný limit - používá tentýž klíč). Po překročení přijde 429 a hlavička Retry-After s počtem vteřin do dalšího pokusu.
POST /v1/messages má navíc vlastní strop: nejvýš jedna SMS za 2 vteřiny a 100 SMS denně na účet.
Odchozí hovory (POST /v1/calls, relay i zkušební hovor) mají dohromady vlastní strop: 10 hovorů za minutu a 1000 za den na účet, a souběžně můžou běžet nejvýš 2 hovory zabudovaného agenta.
Kolik ti z limitu 60/min zbývá, zjistíš bez čekání na 429 - v hlavičkách RateLimit-Limit, RateLimit-Remaining a RateLimit-Reset, které nese úplně každá odpověď (viz sekci Formát chyb > Hlavičky výš).
Stránkování
GET /v1/messages a GET /v1/calls berou limit (kolik záznamů max - výchozí 50, strop 200 i při vyšší zadané hodnotě) a before (ms timestamp - vrátí jen starší záznamy).
hasMore a nextBefore
Obě odpovědi nesou navíc hasMore (boolean - existuje starší stránka) a nextBefore (razítko posledního vráceného záznamu, nebo null, když hasMore je false). Pro další stránku pošli nextBefore z předchozí odpovědi jako nový before - žádné ruční počítání offsetu.
before je EXKLUZIVNÍ (vrátí jen záznamy starší, ne stejně staré) - poslední záznam předchozí stránky se v další stránce nikdy nezopakuje. Výjimečně mohou mít dva záznamy úplně stejné milisekundové razítko přesně na hranici stránky - v tom vzácném případě může druhý z nich vypadnout. Deduplikuj proto podle id, nespoléhej na to, že stránky nikdy nic nevynechají.
GET /v1/calls?direction=in nebo ?direction=out prohledává historii po dávkách s tvrdým stropem počtu dávek - hasMore: true proto může znamenat i jen to, že jsme prohledali dávky až do stropu a ještě jsme nenarazili na konec historie, ne jistotu další stránky. false naopak vždy znamená, že historie v daném směru doopravdy skončila.
Verzování
Aktuální verze veřejného rozhraní je 1.34.2 (GET /openapi.json v poli info.version - viz odstavec o strojově čitelném popisu API v úvodu stránky výš). Tři pravidla, podle kterých se verze mění:
- V rámci
v1přibývají jen NEPOVINNÁ pole a nové endpointy - stávající pole nikdy nezmizí, nezmění typ ani význam. Integrace, která čte jen pole, o kterých ví, nikdy nic nerozbije. Jedinou výjimkou byla verze 1.5.1, která u PŘÍCHOZÍCH hovorů přestala vracetansweredBy- pole u nich nikdy nemělo smysluplnou hodnotu (viz Historie změn níž). - Povinné pole nebo změna významu existujícího pole přijde vždy jako nová hlavní verze (
v2), nikdy jako tichá úpravav1. - U konceptu agenta (Koncept agenta výš) vždy posílej zpátky přesně ten objekt, který jsi přečetl z
GET .../draft- těloPUT/POSTje.strict(), takže neznámý klíč (třeba z novější verze, kterou tvá integrace ještě nezná) vrátí 400validationmísto tichého zahození.
Historie změn
- 9. 10. 2026 (1.34.2):
agentCallLimitsvlib/service/call-quotas.tsvrací pro rozsah kampaně{ concurrent: 8, daily: 6000, perMinute: 15 }; výchozí kvóta účtu (2, 1000, 10), podmínky zapnutí i společné čítače účtu se nemění. Chybová zprávarate_limitedu denního limitu uvádí 6000. - 9. 10. 2026 (1.34.1):
CAMPAIGN_QUOTA_EXPIRES_ATvlib/service/call-quotas.tsje2026-10-31T23:00:00Z; dál platí vypínačVOLAI_PETCENTER_CALL_QUOTA_ENABLED, přesná shoda účtu, agenta a interního kontextu odchozí úlohy a alespoň osm různých jmen vODORIK_RELAY_NAMES. Chování API pro ostatní účty se nemění. - 9. 10. 2026 (1.34.0): Nové endpointy
GET /v1/sms-numbers,POST /v1/sms-numbers(bez těla, podporujeIdempotency-Key, vrací 201) aDELETE /v1/sms-numbers/{e164}(nevratné, zaplacené období se nevrací) a MCP nástrojelist_sms_numbersabuy_sms_number(confirmedMonthlyFeeHalmusí odpovídat aktuálnímu poplatku v haléřích, jinak se nic nekoupí).GET /v1/messagesa MCPlist_messagesberoudirection(outve výchozím stavu,in,all) a vrací i zprávy přijaté na SMS čísle; zprávy nově nesoudirection,smsNumberadeliveryStatus(deliveredneboundelivered, jen u SMS odeslaných z čísla),statusmá novou hodnotureceivedafailReasonhodnotuopted_out.POST /v1/messagesa MCPsend_smsberoufromNumber(aktivní SMS číslo účtu, jen příjemci +420, 1,90 Kč za segment). Nová událost webhookumessage.receiveds daty{id, from, to, body, segments, receivedAt}(receivedAtje Unix ms); text přijaté SMS je cizí obsah a MCP u něj posílásecurityNotice. Přijaté SMS se uchovávají 90 dní. Nové chybové kódy:sms_numbers_unavailable,sms_number_limit,sms_number_out_of_stock,invalid_from_number,from_number_unsupported_destinationarecipient_opted_out; stávající kódyrecipient_rejected,sms_gateway_failed,recipient_is_virtual_number(SMS od sdíleného odesílatele na SMS číslo volai) arelease_failedplatí i pro SMS čísla. Polefromje u zprávy odeslané bezfromNumberdál interní štítekvolai, u zprávy odeslané ze SMS čísla samo číslo a u přijaté zprávy odesílatel. - 8. 10. 2026 (1.33.0): Politika
callback-routingmá volitelnémissedFirstMessage(do 500 znaků): použije se místofirstMessage, když předchozí ověřený odchozí hovor neměl rozhovor se zákazníkem (nezvednuto, záznamník, hlasové menu, nikdo nepromluvil, nebo hovor ještě neuzavřený). Initiation posílá motoruvolai_callback_kind(missed/contacted) vedlevolai_call_mode=campaign_callback. Post-call motoru umícaller_optout_requested(jen odchozí hovory): hovor pak neseoptOutRequested: trueve výpisu i detailu, číslo volaného se zapíše do seznamu nevolat účtu (GET /v1/dnc) a politikalorela_enterprisedalší pokus téže položky nenaplánuje. Hovor motoru sanswered_by: unknownzůstáváunknown- portál už místo něj nehádá záznamník z krátké odpovědi („Ano.“ po úvodu), takžehasConversationtakového hovoru odpovídá přepisu; schránka rozpoznaná motorem (voicemailReasonvyplněný) dostane v politicelorela_enterprisedalší pokus i přes hlášku operátora v přepisu. Nový důvodvoicemailReason: digits(hláška operátora čtoucí volané číslo po číslicích). Vše aditivní; stávající politiky, hovory a úlohy se nemění. - 8. 10. 2026 (1.32.1): Pole
fromu zprávy zůstává interní štítekvolaia OpenAPI ho nově popisuje; popis polesourceříká, že hodnotainboundu zpráv nevzniká. Instrukce MCP serveru, SKILL.md a llms soubory říkají totéž. Chování API se nemění. - 8. 10. 2026 (1.32.0): Uloží výslovný seznam vlastních aktivních agentů motoru pro zákazníky s jednoznačným skutečným odchozím hovorem z tohoto čísla během
lookbackSecs(60-604800 sekund). Neznámý, nejednoznačný nebo neověřený volající zůstane u výchozího agenta. PrázdnéagentIdspolitiku vypne. VolitelnáfirstMessageplatí jen pro ověřený callback.engineSyncRequired: trueznamená, že je nutné samostatně aktivovatwebhooks.inbound_route_urlv konfiguraci motoru výchozího agenta a ověřit ji čtením; tento požadavek živou konfiguraci motoru nepřepisuje. Detail ověřeného příchozího hovoru obsahujecallbackOf.callIda případně serverovétaskIdataskItemId. Nové REST GET/PUT/v1/numbers/{e164}/callback-routinga MCPget_callback_routing/set_callback_routing. Podepsaný kontext nástroje příchozího hovoru nese direction=in a prázdný dispatch/task/item. Serverovývolai_call_mode=campaign_callbackse nastaví jen při ověřené vazbě. Ověřený příchozí lidský kontakt ukončí další plánované pokusy stejné položky úlohy, bez přidání odchozího pokusu nebo ceny. Již běžící hovor a jeho účtování doběhnou. Serverová vazba dispatch/task/item se uchovává osm dní pro celé callback okno. - 8. 10. 2026 (1.31.0):
POST /v1/tasks,PATCH /v1/tasks/{id},create_taskaupdate_taskpřijímají nepovinnéretryPolicy: "lorela_enterprise"aexpiresAt(kladné bezpečné celé číslo, Unix ms); obě pole se vracejí ve veřejném úkolu. Bez politiky zůstávámaxAttempts1-3, při založení výchozí 1; s politikou 1-4, při založení výchozí 4. PATCH bez limitu jej nemění. Politiku lze zapnout jen před prvním pokusem o dispatch. Druhý pokus je nejdřív osm minut od začátku prvního skutečného pokusu, v 08:00-22:00 Europe/Prague; třetí v dalším jiném okně 08:00-09:00 nebo 17:00-19:00; čtvrtý v opačném okně následující kalendářní den. UžšícallingWindowvčetně dnů platí dál. Opakovat lze jenno_answer,missed,busynebo dokončenou hlasovou schránku bez kontaktu s člověkem; nejistý výsledek a chyba motoru vyžadují kontrolu. Politika nepovoluje ručníresolvesaction: "retry"a po pěti dnech od prvního skutečného pokusu už nevolá.expiresAtplatí i bez politiky a brání novému vytočení od termínu včetně prvního pokusu; probíhající hovor doběhne. DNC ani automatická blokace po třech neúspěších za 24 hodin se neobcházejí, takže čtvrtý pokus nemusí proběhnout. - 5. 10. 2026 (1.30.2): Hovor, u kterého motor
caller_loopdo post-callu nepošle (volající nejdřív mluvil s agentem a teprve potom na lince zůstala jen opakovaná hláška), máendReason: "completed"a běžnou cenu jako každý jiný dokončený hovor. Záložní synchronizace ztraceného post-callu (GET /v1/callsmotoru) nově čtemetrics.caller_loop_reported: hodnota1znamená, že motorcaller_loopdo post-callu poslal, acaller_loopse převezme jako dosud; hodnota0znamená běžný hovor, který se uzavře a naúčtuje sendReason: "completed"bez ohledu nametrics.caller_loop_released. U staršího motoru bez tohoto pole platí dosavadní pravidlo smetrics.caller_loop_released(kladná hodnota znamená běžný hovor). Tvary odpovědí REST a MCP, hodnotyendReasonani filtroutcomese nemění. - 4. 10. 2026 (1.30.1):
endReason: "caller_loop"apriceHal: 0se nově přidělují jen příchozímu hovoru s kladnýmdurationSecs; odchozí hovor nebo hovor s nulovou délkou, ke kterému motor pošletermination_reason: "caller_loop", jde běžnou cestou (endReason: "completed"a běžné účtování, hovor s nulovou délkou zůstává neuzavřený jako dosud). Záložní synchronizace ztraceného post-callu (GET /v1/callsmotoru) převezmecaller_loopjen tehdy, kdyžmetrics.caller_loop_releasedchybí nebo je0; při kladné hodnotě (během čekání se ozval člověk) se hovor uzavře a naúčtuje jako každý jiný dokončený hovor sendReason: "completed"acall.completednese cenu, stejně jako když post-call dorazí sám. Hovor sendReason: "caller_loop"se v portálu nikdy nezařadí mezi hovory k pozornosti (Přehled a filtr v Hovorech) a týdenní e-mailový souhrn ho nepočítá mezi vyřízené hovory ani volající a neuvádí ho mezi hovory, které potřebují reakci. Tvary odpovědí REST a MCP, hodnotyendReasona filtroutcomese nemění. - 4. 10. 2026 (1.30.0): Nová hodnota
endReason: "caller_loop"(RESTGET /v1/callsaGET /v1/calls/{id}, MCPlist_callsaget_call, webhookcall.completed): příchozí hovor, kde volající byl automat opakující pořád tutéž hlášku (fronta, vytáčecí systém) a který motor ukončil pojistkou. Zdrojem jemetadata.engine.termination_reason: "caller_loop"v post-callu motoru (u ztraceného post-callu totéž pole zGET /v1/callsmotoru). Hovor mástatus: "completed", kladnédurationSecsapriceHal: 0, z kreditu se nic nestrhne; cena 0 platí do pěti minut délky hovoru, delší hovor se účtuje podle běžného ceníku aendReasonzůstávácaller_loop. Webhookcall.completedneseendReason: "caller_loop". Hovor, ve kterém se během čekání ozval člověk a motor s ním pokračoval,caller_loopnedostane. Ve filtruoutcome(GET /v1/calls,list_calls) takový hovor patří doagent. - 4. 10. 2026 (1.29.6):
PATCH /v1/agents/{id},update_agenti publikace konceptu: změnalanguagez jazyka, ve kterém noví agenti vznikají na ElevenLabs (dnesen,de,pl), na jazyk, ve kterém vznikají na motoru (cs,sk), spustí u agenta sprovider: "elevenlabs"po uložení stejný pokus o převod na motor jako zapnutítransferTo. Při úspěchu má agentprovider: "engine"a výchozí hlas motoru pro nový jazyk (milena,katarina), při selhání zůstává na ElevenLabs. Změna mezicsasknic nepřesouvá.voicemail_requires_enginemá nové znění: při založení radíuseForOutboundTasks: true, u existujícího agenta podporu. - 4. 10. 2026 (1.29.5):
POST /v1/agentsacreate_agentvracejí vwarningsnový kódelevenlabs_by_explicit_choice({code, message: {cs, en}}), když požadavek poslaluseForOutboundTasks: false, výchozí nastavení nasazení by pro jazyk agenta zvolilo motor a agent na ElevenLabs opravdu zůstal (přepojenítransferToho mohlo na motor přepnout). Agent se založí jako dřív, kód nic neblokuje.PATCH /v1/agents/{id}, publikace ani rollback konceptu ho nevracejí. - 3. 10. 2026 (1.29.4): Jen dokumentace, chování API se nemění.
maxAttempts(1-3) je nejvyšší počet automatických vytočení jednoho kontaktu včetně prvního;1znamená bez opakování. Kontakt, kterému po vyčerpání pokusů dášresolvesaction: "retry", dostane ještě jedno vytočení navíc. Počítá se každý pokus, při kterém hovor mohl proběhnout (nezvednutý, odmítnutý volaným i s nejistým výsledkem). Nepočítá se pokus odmítnutý před vytočením, který máitems[].attempts[].countsAsAttempt: false. - 3. 10. 2026 (1.29.3): Pro pokusy zaznamenané od této verze je
items[].attempts[].countsAsAttemptrovnofalsepro všechny kódy, kdy hovor prokazatelně nevznikl, takže se nezapočítají domaxAttempts:agent_not_found,agent_no_number,insufficient_credit,invalid_number,unsupported_country,blocked_destination,on_dnc,destination_auto_blocked,cannot_call_own_number,cannot_call_volai_number,capacity_busy,call_rejected,validation,rate_limited,relay_lease_limit,invalid_workflow,engine_not_configuredadestination_busy. Dřív se trvalé překážky v čísle (invalid_number,unsupported_country,blocked_destination,on_dnc,destination_auto_blocked,cannot_call_own_number,cannot_call_volai_number) počítaly, takže po zrušení blokace a dalším odmítnutí ukazoval kontakt více pokusů, než kolik jich bylo povoleno, přestože se nevolalo. Pokusy zapsané před touto verzí se zpětně nepřepisují (výjimkou je pokus, jehož záměr vytočení uzavře oprava účtování). Nejisté chyby vytáčení (napříkladengine_unavailable) se počítají dál, protože hovor mohl vzniknout. Trvalá překážka dál posílá kontakt doreview(rozhoduješ ty), opravitelný kód (chybějící kredit, agent bez čísla a podobně) úkol pozastaví;rate_limitedarelay_lease_limitúkol nechají běžet a jen počkají. Nic se kvůli tomu nevytáčí dokola. Kontakt, který po vyčerpání pokusů vrátíš přesresolvesretry, nově po opravitelné chybě vytočení bez hovoru (napříkladinsufficient_credit) zůstanependinga po nápravě se znovu vytočí; dřív zůstalfaileda úkol nešel spustit (task_not_startable). - 3. 10. 2026 (1.29.2):
destination_busypři vytáčení z úkolu (hovor prokazatelně nevznikl): kontakt čeká dál (failed, když už měl započítaný pokus a má volný další, jinakpending) sitems[].lastError: "destination_busy"aitems[].nextAttemptAtpodle zbývající doby zámku čísla (nejméně 30 s, nejvýš 16 min, bez zámku 90 s), pokus mácountsAsAttempt: false, rezervace vreservedBudgetHalse uvolní a ostatní kontakty běží dál;lastErrorúkolu se nenastavuje, jen se smaže zastaralý čekacírate_limitedneborelay_lease_limit, protože obsazení dokazuje, že limit prošel. Po 6. obsazení za sebou (tedy po 5 čekáních) jde kontakt doreviewsreviewReason: "dial:destination_busy". Sedm trvalých kódů (on_dnc,destination_auto_blocked,cannot_call_own_number,cannot_call_volai_number,invalid_number,unsupported_country,blocked_destination) pošle kontakt doreviewsreviewReason: "dial:<kód>", ale úkol zůstávárunninga doneeds_attentionpřejde, až nezbude jiná práce (dřív hned). V API a MCP se blokace ruší dvěma voláními:POST /v1/dnc/{e164}/unblock(unblock_destination), pakresolvesaction: "retry"(resolve_task_item); u vlastního čísla, čísla jiného účtu volai, neplatného čísla, čísla mimo Česko a Slovensko a prémiové linky pomůže jenskip. Kontakt vreviewse může objevit i u běžícího úkolu;resolvepak vrací 409task_not_editable, takže počkej naneeds_attention, nebo úkol pozastav.POST /v1/callsse nemění. - 2. 10. 2026 (1.29.1):
items[].providerCallIdukazuje jen na hovor posledního pokusu: kontakt ve stavufailed, který čeká na další pokus, ho nenese; hovor každého pokusu zůstává vitems[].attempts[].providerCallId. Dřív na položce zůstal hovor prvního pokusu, další vytočený hovor se do úkolu nezapsal a kontakt se vytáčel znovu bez započtení pokusu a bez promítnutí ceny dospentHal. Chybyon_dnc,destination_auto_blocked,cannot_call_own_numberacannot_call_volai_numberpři vytáčení z úkolu jsou prokazatelně nevytočené: pokus máoutcome: "failed", rezervace vreservedBudgetHalse uvolní hned a kontakt jde doreviewsreviewReason: "dial:<kód>"(dřívoutcome: "unknown"a držená rezervace).POST /v1/tasks/{id}/startuž nevrací 409task_needs_attentionkvůli rezervaci, kterou nedrží žádný kontakt;POST /v1/tasks/{id}/reconciletakovou rezervaci srovná a uzavře i starší otevřený záměr po nevytočeném pokusu. - 2. 10. 2026 (1.29.0): Nový endpoint
POST /v1/numbers/orders/{id}/cancel(bez těla) a MCP nástrojcancel_number_order: objednávkapendingpřejde do nového stavucancelled(nová hodnotastatusobjednávky vGET /v1/numbers/ordersalist_number_orders);provisioningvrací 409in_progress,doneafailed409invalid_transition, cizí nebo neznámé id 404not_found; opakované zrušení vrací objednávku beze změny. Zrušená objednávka se nepočítá do brány prvního dobití (jedno číslo na účet bez dobití).callingWindow.endu úkolů je včetně celé minuty (current <= end): okno00:00-23:59pokrývá celý den awindow_closedv minutěenduž nepřijde. - 30. 9. 2026 (1.28.1):
PATCH /v1/numbers/{e164}(MCPset_number_routing) smode: "forward"vrací 402insufficient_credit, pokud účet ještě nikdy nedobil kredit a číslo zatím není přesměrované. Číslo, které už veforwardje, jde přesměrovat na jiný cíl i bez dobití.POST /v1/numbers(MCPbuy_number) aPOST /v1/numbers/orders(MCPorder_number_from_region) vrací 402insufficient_creditpři pokusu o další číslo, když účet bez dobití už drží aktivní číslo nebo má otevřenou objednávku (pending,provisioning). Stejný kód a příčina (account) jako u SMS, jiný text hlášky - říká, co udělat (první dobití kreditu); nic se neúčtuje. Po prvním dobití kreditu (karta, automatické dobití) omezení mizí. - 25. 9. 2026 (1.28.0): Nové pole
suspended: booleanu agenta (REST i MCP,GET/POST/PATCH /v1/agents). Nové chybové kódyagent_suspendedaaccount_suspended(403,cause: "account") -account_suspendedna každém REST volání s API klíčem a v každém MCP nástroji (po rate limitu) kromě čtení daňových dokladů (GET /v1/billing/documents,/{id}a/{id}/pdf, MCPlist_billing_documentsaget_billing_document), které zůstávají dostupné;agent_suspendednaPOST /v1/calls,POST /v1/agents/{id}/test-callaPOST /v1/tasks/{id}/start. Příchozí hovor zablokovaný pozastavením agenta nebo účtu neseendReason: "suspended"(nová hodnota vedlecredit_blocked, cena 0). Odpověďaccount_suspended/agent_suspendedse nikdy neukládá podIdempotency-Key, ať stejný klíč po obnovení projde. Klíče vlastních proměnných (variablesuPOST /v1/callsamake_call) nově nesmí začínat předponouvolai_- je vyhrazená pro proměnné, které doplňuje volai (napříkladvolai_block_reason), a takový požadavek vrátí 400validation; u úkolů se takový klíč odmítne až při vytáčení kontaktu. Pozastavení a obnovení dělá výhradně provozovatel v adminu - REST ani MCP pro to vlastní nástroj nemá. Věta, kterou volající slyší na zablokované lince (dluh i pozastavení), teď zní v jazyce agenta (cs, sk, en, de, pl). - 25. 9. 2026 (1.27.3): Beze změny rozhraní: stejný kód
warningsagent_misuse_suspectedve stejných odpovědích REST i MCP, jen širší rozpoznávání. - 24. 9. 2026 (1.27.2): Odchozí úkoly:
relay_lease_limitz vytáčení (kvóta 2 souběžných hovorů agenta na účet) se chová jakorate_limited- úkol zůstávárunning, nastavílastError: "relay_lease_limit", pokus se nezapočítá (countsAsAttempt: false) a čekající kontakty dostanouitems[].nextAttemptAtza minutu. Dřív šla položka doreviewsreviewReason: "dial:relay_lease_limit"a úkol doneeds_attention. Synchronizace s motorem (GET /v1/calls) čte nové poleattempt_idodchozího hovoru a páruje jím záznaminitiatedpo nejistém vytočení (bezcall_sid, i u agenta bez vlastního čísla); po spárování přijdecall.completeds cenou a uvolní se relay linka i kvóta. Vyžaduje motor sattempt_idve výpisu hovorů; starší výpis se chová jako dřív. - 24. 9. 2026 (1.27.1):
POST /v1/callssagentIdna agentovi vlastního motoru, zkušební hovor sesystemPrompt, MCPmake_calla odchozí úkoly: když vytočení u motoru skončí timeoutem, přerušeným spojením, odpovědí 500/504 nebo nečitelnou 2xx, vrací se dál502 engine_unavailable, ale hovor zůstáváinitiated(bezpriceHal), relay linka se neuvolní a stejnétoje 15 minut zamčené (destination_busy); kvóta souběžných hovorů se uvolní hned. Když hovor proběhl, výsledek a cenu doplní post-call nebo synchronizace s motorem (post-call ho nově najde i bezcall_sidpodle identifikátoru pokusu, i u agenta bez vlastního čísla) a přijdecall.completed; když ne, uzavře ho po 2 h watchdog jakofailedspriceHal: 0. Webhookcall.failedse u nejistého vytočení neposílá. Jisté selhání (spojení s motorem vůbec nevzniklo nebo vypršelo jeho navazování, 4xx, 502/503) se chová jako dřív:failed,priceHal: 0,call.failed. - 24. 9. 2026 (1.27.0): Nový kód
warningsagent_misuse_suspected({code, message: {cs, en}}). Objevuje se vPOST/PATCH /v1/agents,PUT /v1/agents/{id}/draft,POST /v1/agents/{id}/simulate,POST .../draft/publish,POST .../draft/rollback,POST /v1/calls(prompt zkušebního hovoru nebovariables),POST/PATCH /v1/tasks,POST/PATCH /v1/toolsa odpovídajících MCP nástrojích (create_agent,update_agent,save_agent_draft,simulate_agent_draft,publish_agent_draft,rollback_agent_draft,make_call,create_task,update_task,create_tool,update_tool). Polewarningsje nepovinné, chybí, když není co hlásit, a /openapi.json ho popisuje u všech těchto odpovědí. - 24. 9. 2026 (1.26.3):
POST /v1/callssfrom(bridge) a MCPmake_call: když objednávka spojení u telefonního operátora skončí síťovou chybou, timeoutem nebo odpovědí 429/5xx, vrací se úspěch sestatus: "initiated"místo502 callback_faileda hovor zůstáváinitiated, dokud ho cdr-sync nespáruje s CDR (a nezaúčtuje), nebo po 24 h uzavře watchdog jakofailedspriceHal: 0.callback_failedteď znamená jen prokazatelné odmítnutí operátorem (chybová odpověď nebo 4xx). Webhookcall.failedse u nejisté objednávky neposílá; stejné číslotozůstává asi 10 minut zamčené (destination_busy). - 24. 9. 2026 (1.26.2): Strop hovorů na účet za 24 hodin (sdílený
POST /v1/callss agentem i mostem, relay a zkušebními hovory, MCPmake_calli odchozími úkoly) je nově 1000 místo 200. Po jeho vyčerpání dál429 rate_limiteds hláškou o denním limitu;10/min, souběžnost a rozpočet motoru se nemění. - 24. 9. 2026 (1.26.1): Odchozí úkoly: záznam hovoru ve stavu
failedbezconversationIda bezpriceHal(vytočení motor odmítl nebo nepotvrdil) se vreconcileusadí na 0 - dřív položka zůstalareviewReason: "billing_unknown"a úkolneeds_attentionnavždy.resolveseskipu položkybilling_unknownpřepne úkol se zbývající prací dopaused(rezervace původního hovoru se dál počítá doreservedBudgetHalastartji toleruje);retrydál čeká na cenu. Rozhodnutí hned po chybě vytočení (reviewReason: "dial:...") už neztratí vazbu na hovor ani rezervaci.rate_limitedpři vytáčení (limit motoru, 10 hovorů za minutu, 200 za den) nechá úkolrunningslastError: "rate_limited"a čekajícím položkám nastavínextAttemptAtna konec limitu (podleRetry-After, jinak za 5 minut, nejvýš 24 hodin) místopaused; pokus se nezapočítá.invalid_workflowaengine_not_configuredpři vytáčení jsou prokazatelně bez hovoru (úkolpaused, pokus se nezapočítá). Každý hovor agenta na vlastním motoru, který motor nevytočil (odchozí úkoly iPOST /v1/calls, MCPmake_calla portál), má vGET /v1/callspriceHal: 0adurationSecs: 0místo chybějících hodnot; webhookcall.failedse nemění. - 24. 9. 2026 (1.26.0):
POST /v1/callssagentIdna agentovi vlastního motoru (a MCPmake_call): odmítnutí limitem odchozích minut motoru (hodinový a denní koš na účet) nebo plnou souběžností motoru je nově429 rate_limitedmísto502 engine_unavailable; u limitu minut s hlavičkouRetry-After(vteřiny do konce hodinového okna, u denního do půlnoci UTC). Nic se nevytočilo ani neúčtovalo; hovor v historii zůstává jakofaileda webhookcall.failednesereason: "rate_limited". Odchozí úkoly berourate_limited(i z limitu 10 hovorů za minutu a 200 za den) jako prokazatelně bez hovoru: položkafailedbez započtení pokusu, úkolpausedmístoneeds_attention. Chybová tabulkaPOST /v1/callsnově uvádí i502 engine_unavailable- u agenta na vlastním motoru znamená jen skutečný výpadek motoru, ne limit. - 23. 9. 2026 (1.25.0): Nové volitelné pole
event_idv obálce webhooku ({event, data, ts, event_id}) ucall.completed/call.failed/call.no_answer/call.missed-message.senta testovacíwebhook.testbeze změny. Neúspěšné doručení těchto čtyř událostí po 3 pokusech (3 s odstup) nekončí: zůstává ve frontě a doručí se v následujících minutách, nejvýš do 5 kol; opakované doručení nese bajtově stejné tělo.GET /v1/webhook/deliveries(i MCPlist_webhook_deliveries) teď ukazuje i mezistavy před posledním kolem,attemptsje součet pokusů napříč všemi koly, a nově nese volitelné poleeventId. - 23. 9. 2026 (1.24.1): Dva nové kódy
warnings:prompt_variables_unavailable_inbound(agent snumberE164, jehožsystemPrompt/firstMessageobsahuje{{promennou}}mimo sadu, kterou příchozí hovor doopravdy dodává) afirst_message_empty(firstMessage, ve které po odstranění všech{{...}}bloků nezůstane žádné písmeno ani číslice mimo proměnné). REST (POST/PATCH /v1/agents, publikace a návrat konceptu) i MCP (create_agent,update_agent,publish_agent_draft,rollback_agent_draft) čtou stejný zdroj jako editor agenta v portálu (agentWarnings). - 20. 9. 2026 (1.24.0): Nové nepovinné pole
busyCalendarIdsu agenta (POST/PATCH /v1/agents, MCPcreate_agent/update_agent, koncepty) i u hledání volna a zakládání události bez agenta (POST /v1/integrations/{id}/availability,POST /v1/integrations/{id}/events, MCPfind_free_slots,create_calendar_event). Kalendáře se čtou paralelně; selhání kteréhokoli z nich je chyba celého hledání, aby se nenabídl termín přes neviditelnou schůzku. Nejvýš čtyři, bez duplicit a bezcalendarId; jinak 400calendar_invalid_rules, neznámý kalendář 400calendar_invalid_calendar. - 20. 9. 2026 (1.23.4): Chybové tabulky
POST /v1/agents,PATCH /v1/agents/{id}a publikace i návratu konceptu doplňují šestici, kterou vracívalidateCalendar: 404calendar_integration_not_founda 400calendar_invalid_calendar,calendar_invalid_timezone,calendar_invalid_windows,calendar_no_windows,calendar_invalid_rules. Propisuje se doopenapi.json, reference /docs/api,SKILL.mdillms-full.txt. - 20. 9. 2026 (1.23.3):
maybeQueueMissedCallSmsspouští SMS i pro odchozí hovor sansweredBy: "voicemail"(dosud jenstatus: "no_answer"a příchozímissed). Hlasové menu (ivr) aniunknownSMS nespouští. Ostatní podmínky (jen CZ/SK číslo, DNC, blokace, jedna SMS na číslo za 24 h, noční klid, poslední pokus úkolu) platí beze změny;CallRecord.missedSmsse zapisuje stejně. - 19. 9. 2026 (1.23.2): Čas s milisekundami se formátoval s posunem zóny o minutu menším (
+01:59místo+02:00) - týkalo se to polenowv nástrojích agenta i začátku zakládané události, když klient poslalstartse zlomky sekund. Náhradní termíny u 409calendar_slot_taken(POST /v1/integrations/{id}/events, MCPcreate_calendar_event) se počítají od požadovaného termínu, stejně jakofind_free_slotsse zadaným časem. - 19. 9. 2026 (1.23.1): Pole
calendaru agenta (POST/PATCH /v1/agents, MCPcreate_agent/update_agenta koncepty) odmítne kalendář saccessRolereadernebofreeBusyReaderchybou 400calendar_invalid_calendar- agent do téhož kalendáře schůzky zapisuje. Roli vracílist_calendarsjakoaccessRole, pokud ji poskytovatel uvádí; kalendář bez uvedené role projde jako dřív. Ostatní chybové kódy se nemění. - 19. 9. 2026 (1.23.0): Nové pole
CallRecord.rating(value: "good" | "bad",reason?,note?,at,source: "portal" | "email" | "api" | "mcp") aCallRecord.missedSms;PATCH /v1/calls/{id}a MCPannotate_callpřijímajírating/ratingReason/ratingNote(patchCallAnnotationvolárateCallsesource: "api"/"mcp"). Nové poleAgentRecord.missedCallSms { enabled, text? }(proměnné{firma},{cislo},{agent}) vPOST/PATCH /v1/agents,GET /v1/agents/{id}a MCPcreate_agent/update_agent/get_agent/save_agent_draft.GET/PATCH /v1/accounta MCPget_account/update_accountmajícompanyName(max 80 znaků, prázdný řetězec maže) a GET nově vracínotifications.weeklySummary. Zkušební hovor v editoru agenta ukazuje výsledek podle cíle hovoru (call.evaluation.goal) a zapsaná data. - 18. 9. 2026 (1.22.0): Nové endpointy
POST /v1/integrations/{id}/availability(volné sloty bez uloženého agenta -windowschybí = 24 hodin každý den) aPOST /v1/integrations/{id}/events(založení schůzky, vyžadujeconfirm: true, nepovinnýidempotencyKeypro bezpečné opakování; 409calendar_slot_takenpři kolizi), MCP nástrojefind_free_slotsacreate_calendar_eventse stejným tvarem.DELETE /v1/integrations/{id}nově vracíaffectedAgents- agenty, kterým odpojení integrace vypnulo polecalendar. Nové polecalendaruPOST/PATCH /v1/agents,GET /v1/agents/{id}a MCPcreate_agent/update_agent/get_agent:integrationId,calendarId,timezone,slotMinutes,minNoticeMinutes,horizonDays,bufferMinutes,windows(pole oken{from,to}pro každý den v týdnu). Funguje jen na vlastním motoru volai (provider: "engine") - u agenta na ElevenLabs se pole uloží a čeká na varovánícalendar_pending_engine_switch, dokud agent nepřepne. Jedenáct nových chybových kódů scause/action:calendar_slot_taken,calendar_confirmation_required,calendar_invalid_range,calendar_integration_not_found,calendar_invalid_calendar,calendar_invalid_timezone,calendar_invalid_windows,calendar_no_windows,calendar_invalid_rules,calendar_too_many_events,calendar_unavailable. - 18. 9. 2026 (1.21.0): Nový typ pohybu ledgeru
setup_revision(GET /v1/credit/ledger, MCP) pro kolo úprav objednávky Na klíč nad rámec balíčku, částkaSETUP_EXTRA_REVISION_HAL(490 Kč bez DPH). Daňové doklady (GET /v1/billing/documents, .../{id}, list_billing_documents, get_billing_document) mají nově vždy vyplněné polekind("invoice" - výchozí, nebo "credit_note") a k němu volitelná polecorrectsNumberacorrectionReason; dobropis k vratce zřízení Na klíč se čísluje vlastní řadou OD a nese kladné částky (znaménko dává PDF).credit()(lib/service/balance.ts) dostal interní parametrnotifyTelegram- platba Na klíč posílá jen jednu Telegram hlášku ("Na klíč: zaplaceno"), ne dvě. Nová veřejná stránka /recepcni-na-klic (anglicky /en/receptionist-done-for-you). - 18. 9. 2026 (1.20.0): Nové pole
laughter(auto/on/off) vPOST/PATCH /v1/agentsa MCPcreate_agent/update_agent:autonechává rozhodnutí na detekci citlivého tématu motoru (dluhy, zdravotnictví, úřady, pohřebnictví),ontuhle detekci přebije,offho vždy potlačí; vynechaný klíč se uloží i vrací jakoauto, nikdy jako chybějící pole.GET /v1/agents/{id}a nový MCP nástrojget_agent(dřív chybějící parita pro detail jednoho agenta) přidávajílaughterEffective({active, reason, sensitiveCategory} | null) uvnitř vráceného objektu agenta, spočtené čerstvě pro publikovanou konfiguraci;nullznamená, že se to teď nestihlo zjistit (motor neodpověděl do 3 vteřin, výpadek, nebo tichá 404 u starší verze) - nikdy odhad. MCPupdate_agentvrací týž objekt jako pole vedleagent, protožePATCH /v1/agents/{id}ho nevrací vůbec. Pole se přijímá a ukládá i u agenta na ElevenLabs, ale bez slyšitelného efektu - přehraje ho jen český hlas Cartesia na vlastním motoru volai. - 18. 9. 2026 (1.19.0): Nová oblast REST API v1 a MCP - zdroj setup-orders, capability oblast setup (za credit). Sedm endpointů (POST /v1/setup-orders, GET /v1/setup-orders, GET/POST /v1/setup-orders/{id}, .../messages, .../checkout, .../launch, .../cancel) a sedm odpovídajících MCP nástrojů (create_setup_order, list_setup_orders, get_setup_order, message_setup_order, checkout_setup_order, launch_setup_order, cancel_setup_order) nad stejnou servisní vrstvou lib/service/setup-orders.ts. Nabídku počítá vždy katalog v kódu (lib/setup-catalog.ts), model z rozhovoru jen vybírá položky. Nové chybové kódy: setup_order_not_found, order_closed, invalid_transition, quote_pending_confirmation, checkout_open, turn_in_progress, advisor_no_quote, advisor_unavailable, setup_orders_disabled. Dokumentace na /docs/na-klic (anglicky /docs/done-for-you).
- 17. 9. 2026 (1.18.0): Koncept agenta (
PUT/GET /v1/agents/{id}/draft,POST /v1/agents/{id}/draft/publish) i MCPsave_agent_draftmají teď tříhodnotovénumberE164: chybějící klíč nechá číslo agenta beze změny,nullho odpojí, řetězec připojí uvedené číslo - dorovnání parity sPATCH /v1/agents/{id}, který tuhle sémantiku měl už dřív. Čtení konceptu navíc srovnávápublished.numberE164vždy se skutečným číslem živého agenta adraft.numberE164jen tehdy, když koncept o čísle nerozhoduje, takže kontrolní tabulka v editoru i odchozí úkoly vidí pravdivý stav i po připojení nebo přesunu čísla mimo editor; "nerozhoduje" platí i pro řetězec, který se shoduje se ŽIVÝM číslem agenta - taková hodnota se chová jako chybějící klíč, a to znovu při každém čtení konceptu proti tehdy aktuálně živému číslu; přesune-li se číslo později na jiného agenta mimo koncept, stejná uložená hodnota se stane výslovnou volbou a další publikace nebo rollback konceptu ho tomuhle agentovi vezme zpátky - ne potichu:warningsu publikace i rollbacku (REST i obou MCP nástrojů) v tom případě nese nový kódnumber_changed_by_publishsfrom/to(E.164, nebonullbez čísla), a ani ten operaci neblokuje. Pozor na zpětnou kompatibilitu čtení:draft.numberE164teď může v odpovědi přijít jakonull(výslovná volba "bez čísla"), kde dřív klíč jen chyběl - klient ho má číst stejně jako chybějící klíč, tedy "agent nemá číslo". Značka "otestováno" a otisk agenta připnutý běžícímu odchozímu úkolu se navíc počítají BEZ telefonního čísla (behaviorFingerprint, nedraftFingerprint), takže připojení ani přesun čísla mimo editor už nevyžaduje nový test a nezastaví běžící kampaň; koncepty s číslem uložené PŘED touhle změnou mají starou značku spočítanou ještě SE číslem, takže si o ni řeknou jednorázově znovu - jeden test nebo publikace po aktualizaci ji obnoví a dál platí nové pravidlo. - 15. 9. 2026 (1.17.0): Nový stav hodnocení cíle
GoalDisplayState(success/failure/unclear/no_conversation/not_evaluated) nahrazuje trojiciAgentGoalResultv zobrazení portálu, ve filtrech/hovorya v přehledu. REST a MCP dostalyansweredBy: "ivr",goal.reason("no_caller_speech"/"evaluation_error") ahasConversation(boolean | null). Parametrgoal(GET /v1/calls, MCPlist_calls) přijímá pět nových hodnot navíc ke stávajícíunknown, která zůstává zpětně kompatibilní - dál zahrnuje záznamy bez jasného výsledku (goal.resultchybí nebo jeunknown): vždyunclearanot_evaluated, uno_conversationjen když má taky výsledekunknown. - 13. 9. 2026 (1.16.0): Nová hodnota
endReason: "engine_error"(statusfailed) nastává, když motor pošlemetadata.engine.termination_reasons hodnotouengine_stallneboengine_erroru hovoru, který se obsluhoval - dřív se pole u takového hovoru zahazovalo.priceHalje0, jen když hovor ještě žádnou cenu nemá (jinak zůstává, ALERT log). Zákaznický webhookcall.faileddostal čtyři nová volitelná pole:durationSecs,priceHal,transcript,summary- vyplněná jen u téhle technické větve, jinde chybí jako dřív.GET /v1/calls/{id}a MCPget_callvrací stejnou hodnotuendReason. Odchozí úkoly (POST /v1/outbound-tasks, MCP) berouengine_errorjako opakovatelný pokus (stejná cesta jakono_answer), ne jako důvod k zastavení kampaně, a nezapisují ho do automatické 30denní blokace destinace. - 13. 9. 2026 (1.15.0):
POST/PATCH /v1/agentsa MCPcreate_agent/update_agent/save_agent_draftberou nové polesilencePromptSecs: number | null(celé číslo 3 až 25,nullvypíná), meze shodné s motorem (engine/types.py, U1). Chybějící pole přiPOST/create_agentuloží výchozích 10 - na rozdíl odvoicemailse pole přijímá a vrací u OBOU poskytovatelů (GET /v1/agentsvrací uloženou hodnotu i uprovider: "elevenlabs"). Hodnota mimo meze padá na obecnou validační chybu (validation, 400), žádný nový kód. Existující agenty na motoru dostanou výchozích 10 jednorázovým re-synchronizačním skriptem (scripts/resync-silence-prompt.mts), který mění výhradně tohle jedno pole. - 13. 9. 2026 (1.14.7): OpenAPI doplňuje popisy všech operací a polí požadavků včetně vnořených variant. Publikuje produktové limity agentů, nástrojů, SMS a hovorů ze společných konstant servisní vrstvy, místo volných technických stropů parseru. Automatická kontrola ověřuje všechny ukázky požadavků a odpovědí proti schématům. Chování API, chybové kódy a nastavení poskytovatelů se nemění.
- 13. 9. 2026 (1.14.6):
POST /v1/messagesa MCPsend_smsvracíinsufficient_credit(HTTP 402, causeaccount), dokud účet nemá kladný pohybtopup(karta i automatické dobíjení) neboadmin(ruční korekce majitele). Končí dřívější strop 3 SMS pro účty bez vlastního aktivního čísla a aktivní číslo už výjimku nedává. První dobití se drží jako trvalý příznak účtu, takže dlouhá historie pohybů zákazníka nikdy nezablokuje. - 13. 9. 2026 (1.14.5): Nový kód
workflow_node_tool_missingvewarningsuPOST/PATCH /v1/agents, u publikace i vrácení konceptu a u MCPcreate_agent,update_agent,publish_agent_draftarollback_agent_draft. Platí pro oba poskytovatele, protože smazaný nástroj se do fáze nepřenese ani na vlastním motoru.workflow_node_tool_not_syncedzůstává jen pro nástroj, který na účtu je, ale agent ho nemá mezi svými. Šablona Recepce nově doporučuje dvě věty do základního promptu: neodhadovat provozní údaje a ptát se jen na jednu věc najednou. - 12. 9. 2026 (1.14.4): Průvodce rozlišuje identifikátory OAuth souhlasů od API klíčů i při obnově starší uložené volby. Nedostupné ověření není považováno za odvolaný přístup.
- 12. 9. 2026 (1.14.3): Doplněny katalogové soubory katty-studio.mp3 a katty-telefon.mp3 stejným generátorem a obsahem jako ostatní hlasy. Hlas agenta, poskytovatel ani nastavení telefonního provozu se nemění.
- 12. 9. 2026 (1.14.2): Popisky kopírování a dalšího kroku odpovídají zvolenému způsobu připojení. Codex desktop při použití API klíče vede ke konfiguraci config.toml. Zavření mobilního menu zachovává návrat fokusu.
- 12. 9. 2026 (1.14.1): Přihlášení zachovává cíl průvodce. Volba prostředí se ukládá k účtu odděleně od skutečného MCP ověření. Ruční návody zahrnují Claude Code, Codex CLI i desktop a API klíč jako alternativu. Nápověda a názvy Hlasoví agenti, Telefonní čísla a Data a integrace jsou sjednocené.
- 12. 9. 2026 (1.14.0): Při vynechaném
useForOutboundTaskszáleží naVOLAI_ENGINE_DEFAULT_FOR_NEW, dostupnosti motoru a seznamuVOLAI_ENGINE_DEFAULT_FOR_NEW_LANGUAGES(bez nastavenícs,sk). Samotný jazyk motor nezaručuje. Explicitnítruežádá motor,falsezačne na ElevenLabs. Platí pro portál,POST /v1/agentsi MCPcreate_agent. Po založení ověřprovideravoiceId; přepojení může vyvolat další pokus o změnu poskytovatele. - 12. 9. 2026 (1.13.0): Pole workflow je v POST a PATCH /v1/agents, v konceptu agenta i v MCP nástrojích create_agent, update_agent a save_agent_draft. Hovor, který fázemi prošel, nese workflowPath v GET /v1/calls a GET /v1/calls/{id}. Nová varování workflow_*, workflow_not_synced_to_provider a workflow_node_tool_not_synced upozorní na problémy s nastavením fází.
- 12. 9. 2026 (1.12.5):
voiceIdpro agenta na ElevenLabs:katty(výchozí, hlas šablony) nebo syrové ElevenLabs id;janauž v katalogu ani u ElevenLabs není (dva agenti z 12. 9. odpoledne přepnuti na Katty, hlas odstraněn z workspace).GET /v1/voices?provider=elevenlabsa MCPlist_voicessprovider: elevenlabsvracíkatty. Záskok motoru na ElevenLabs pro Milenu, Terezu a Katarinu je také Katty. - 12. 9. 2026 (1.12.4): Pomalé čtení stavu už nepřerušuje pravidelný polling. Evidence úspěšného MCP čtení se dohledá podle aktivního přístupu i při chybě zápisu pomocného indexu. Ověření nadále vyžaduje get_balance nebo list_agents přes MCP.
- 12. 9. 2026 (1.12.3): Opraven anglický odkaz na ochranu kalendářových dat a zobrazení aktivního filtru cíle i v účtu bez dosavadního vyhodnocení. Obě jazykové varianty mají regresní testy odkazů a nedostupných integrací.
- 12. 9. 2026 (1.12.2): MCP průvodce používá existující evidenci úspěšných čtení aktivním API klíčem nebo OAuth souhlasem, bez simulovaného ověření. Filtr goal=unknown v GET /v1/calls a MCP list_calls zahrnuje i záznamy bez hodnocení cíle. Technické dokončení neznamená splněný cíl. REST a MCP nadále vracejí jednotlivé záznamy; portál je seskupuje do konverzací.
- 12. 9. 2026 (1.12.1):
voiceIdpro agenta na ElevenLabs:jana(výchozí, hlas šablony) nebo syrové ElevenLabs id;anetprojde jen agentovi, který ji už má, jinak 400validations vysvětlením (dřív 502eleven_labs_errorod ElevenLabsvoice_live_moderated_not_allowed).GET /v1/voices?provider=elevenlabsa MCPlist_voicessprovider: elevenlabsvracíjana. Agent na ElevenLabs bezvoiceIddostane Janu výslovně (záznam nese její id). Registrace SIP: operátor vracel403 INVALID_USERu linek koupených přes API, dokud se u linky jednou nepřepne SIP protokol vypnout/zapnout; opraveno u všech linek a při nákupu nové linky se dělá automaticky. - 12. 9. 2026 (1.12.0): OAuth authorization code + PKCE S256, DCR, resource-bound opaque tokens, refresh rotation/replay detection, OIDC discovery/JWKS/userinfo a revokace. Access token 10 minut, refresh nejvýše 30 dní, souhlas nejvýše 90 dní. Změna hesla zneplatní OAuth přístup. MCP annotations výslovně rozlišují přepisy, placené akce, zprávy a externí vedlejší efekty.
- 12. 9. 2026 (1.11.0):
GET /v1/numbers/{e164}/sipa MCPget_sip_credentials:outboundTrunkAddress=sip.volai.cz(vlastní SIP proxy volai s digest ověřením, realmsip.volai.cz; naměřeno: platforma odmítne INVITE větší než UDP MTU, přes TCP tentýž hovor projde),transport=tcp(schéma nověenum [tcp, udp], UDP funguje také),port5060 beze změny. Watchdog hlídá healthz proxy (SIP_PROXY_HEALTHZ_URL): ops e-mail při nedostupnosti, zastavené synchronizaci ověřovacích dat nebo certifikátu pod 14 dní. Post-call webhook ElevenLabs má v produkci HMAC tajemství, zapíná se per agent (ELEVENLABS_POST_CALL_WEBHOOK_ID). - 12. 9. 2026 (1.10.0):
GET /v1/numbers/{e164}/sipa MCPget_sip_credentials:outboundTrunkAddressse řídí samostatnou konfigurací (může být shodná seserver), popisy polí bez zmínek o realmu;inboundSignallingCidrsbeze změny. Post-call webhook ElevenLabs páruje příchozí hovory přesmetadata.phone_call.call_sid(dřív četl SIP Call-IDcall_id, který se nikdy neshodoval s klíčemcall:sidz initiation webhooku) sdílenoufindExistingCallByKeyss cronemconversations-sync(pořadícall:conv->call:attempt->call:sid). Per-agent nastavení post-call webhooku (platform_settings.workspace_overrides.webhooks) migruje cron, jakmile je nastavenéELEVENLABS_POST_CALL_WEBHOOK_ID; do té doby hovory dál uzavírá cron. Post-call z vlastního motoru přijímáphone_call.external_number: nullacaller_presentation; prefixuri_u volajícího se odstraňuje jako v initiation webhooku. Cíl přepojení hovoru (transfer_to_number) se skládá ze samostatnéVOLAI_SIP_TRANSFER_HOST, ne z veřejné SIP domény. Nový interní zdroj ověřovacích dat pro SIP proxy (GET /api/internal/sip-subscribers, mimo v1, bearer + IP allowlist + rate limit). - 12. 9. 2026 (1.9.0):
POST/PATCH /v1/agentsa MCPcreate_agent/update_agentteď mohou vrátit druhý kód vewarnings:first_message_too_long, nezávisle nafirst_message_no_ai_disclosure- a stejnéwarningsod teď vrací i publikace konceptu agenta (POST /v1/agents/{id}/draft/publish, MCPpublish_agent_draft) a jeho vrácení na dřívější revizi (POST /v1/agents/{id}/draft/rollback, MCProllback_agent_draft), kde dřív chyběly úplně - obojí totiž propisuje první větu na živého agenta. Odhad počítá slova, číslice po znacích a velké zkratky do čtyř znaků; delší velké slovo se čte jako jedno slovo, ať firma psaná kapitálkami odhad uměle nenafoukne. Jediný práh (odhadovaná doba nad 7 sekund) se měří nad tím, co volající doopravdy slyší - pozdrav plus věta o nahrávání, když je zapnuté. Nezměněná výchozí šablona pozdravu varování nikdy nedostane, jen text, který zákazník upravil. - 12. 9. 2026 (1.8.2): V dokumentaci, integračních návodech i chybových hláškách najdeš přístupy pod názvem AI asistent. MCP jasně říká, že hlasový motor je potřeba až pro spuštění odchozího úkolu; založit lze i úkol s agentem na ElevenLabs.
- 12. 9. 2026 (1.8.1): OpenAPI doplňuje Idempotency-Key pro 14 podporovaných operací, response hlavičky a nepovinné JSON tělo s revision při smazání úkolu. Oprava popisů bez změny chování placených akcí:
useForOutboundTasksrozlišuje true/false/vynechání, úkoly mají limit 1000 příjemců abilling_unknownzachovává původní hovor i rezervaci do zjištění ceny. Daňové doklady kreditu jsou dostupné v REST a MCP, API klíč může přes REST odvolat jen sám sebe, odpojení integrace je REST/portál. Oprava údaje z 1.6.1:preview_task_csvnení MCP nástroj; CSV náhled jePOST /v1/tasks/csv-previewnebo portál. Instalační příkazy sdílejí generátor s průvodcem, přepínače příkladů mají unikátní kotvy a Python zachovává JSON hodnoty. - 11. 9. 2026 (1.8.0): Nové REST
POST /v1/dnc/{e164}/unblocka odpovídající MCP nástrojunblock_destinationruší automatickou blokaci destinace; fungují i pro blokace založené před tímhle nasazením. Starší blokace mohou ve výpisuGET /v1/dncalist_dncchybět, protože vznikly před jeho indexem, ale přímé odblokování podle čísla funguje. Indexované blokace se vracejí vedle beze změny zachovanéhonumbersv poliblocked: [{e164, blockedAt, expiresAt}], kde jsou časy unix milisekundy. Po odblokování se čítač neúspěšných pokusů počítá od nuly - tři nové neúspěšné pokusy na stejné číslo blokaci vrátí a odblokovat lze opakovaně.groupCallsByConversation(sdílený primitiv pro /hovory, export CSV, navigaci Předchozí/Další i statistiky) řadí podlerepresentative.startedAtsestupně, dřív podlekey, tedy podle abecedy identifikátoru konverzace.TestCallOutcomemá novou hodnotuno_answeroddělenou odfailed, ať panel netvrdí příčinu, kterou nezná. Vokativ jména psaného celými verzálkami je nově taky verzálkami (RADEK->RADKU) v e-mailu i v hlavičce Přehledu. - 11. 9. 2026 (1.7.1):
agent_busy(HTTP 409,cause: "busy") přibyl do sdílené chybové mapyPUBLIC_ERROR_HTTP/PUBLIC_ERROR_CAUSE(lib/types.ts). Vrací jiswitchAgentProvider(lib/service/engine-provider.ts) - jediná admin akce portálu, která poskytovatele agenta přepíná, REST v1 ani MCP takový vstup nemají (agents.switch_providerv katalogu schopností,lib/capabilities.ts). Kontrolu dělá nový klientGET /v1/calls/active(lib/engine.tslistActiveCalls): hovor agenta se páruje PRIMÁRNĚ podle poleagent_id, které motor u běžícího hovoru nese od nasazení verze s tímhle polem, číslo zůstává záloha pro starší motor bez něj. - 11. 9. 2026 (1.7.0):
POST/PATCH /v1/agentsa MCPcreate_agent/update_agent/save_agent_draftberou nové polevoicemail: {enabled, action: "mark"|"hangup"|"message", message?}- jen u agenta sprovider: "engine", jinakvoicemail_requires_engine;messageje povinná přiaction: "message", do 400 znaků (invalid_voicemail_message).GET /v1/agentsvrací nastavenou hodnotu. Post-call z motoru neseanswered_by/voicemail_reason/voicemail_message_left/voicemail_detected_at_secs;answered_bymá přednost před dosavadním odhadem z přepisu hovoru (lib/answered-by.ts) jen hodnotamihumanavoicemail-unknownse bere jako "motor nerozhodl" a použije se odhad z přepisu.GET/list_calls/get_callu odchozích hovorů motoru navíc vracívoicemailReason(čtvrtá hodnotahuman_reply- krátká odpověď člověka),voicemailMessageLeftavoicemailDetectedAtSecs. - 11. 9. 2026 (1.6.5): Motor u odchozího hovoru ukončeného před zvednutím smaže místnost a pošle post-call: prázdný přepis,
call_duration_secs: 0a nové aditivní polemetadata.engine.termination_reason(no_answernebodisconnected_before_answer). Hovor dostanestatus: no_answer,endReason: no_answera cenu 0 jako dřív, jen hned. RekonciliaceGET /v1/callspáruje odchozí hovory motoru přescall_sida u nespojených posílá nulovou délku.GET /openapi.json:answeredBymádescriptiono omezení na odchozí hovory. - 11. 9. 2026 (1.6.4):
POST /v1/tasksaPATCH /v1/tasks/{id}(icreate_task/update_taskv MCP) přijímajírecipientsdo 1000 položek,POST /v1/tasks/csv-previewdo 1000 řádků. Nová kontrola velikosti záznamu úkolu (2 MB serializovaného JSONu) vracívalidations polemrecipients. - 11. 9. 2026 (1.6.3): Initiation webhook ElevenLabs:
agent_idz payloadu se teď porovnává selevenAgentIdNEBOidagenta dohledaného přes routing čísla - cizíagent_iddostane jen minimální odpověď bezconversation_config_override; stejná kontrola chrání uzavírání konverzace v post-call webhooku i cronu synchronizace konverzací. Cron synchronizace CDR: nerozpoznaný odchozí CDR záznam z vlastní linky (mimo demo číslo), starší než 600 s a bez nejasně spárovatelného existujícího záznamu, se naúčtuje jakokind: "sip"odchozí sazbou bez agentní přirážky (vGET /v1/callsse objeví skind: "sip"; čítačchargedSipje jen v odpovědi cronu, ne ve veřejném API); mladší nebo nejasně spárovatelný záznam se dál jen podrží pro ruční kontrolu.CallKindrozšířen o"sip". Tvar CDR záznamu skutečného SIP klienta zatím nemá produkční ověření (žádný registrovaný softphone) - proto obě pojistky. - 11. 9. 2026 (1.6.2): Nový endpoint
POST /v1/tasks/{id}/items/{itemId}/resolves tělem{ action: "retry" | "skip", revision }a MCP nástrojresolve_task_item; nový chybový kóditem_not_resolvable(409, account),task_not_editableu běžícího nebo hotového úkolu. Synchronizace hovorů motoru páruje vlastní odchozí nohu podle relay linky a času začátku, nezvednutý odchozí hovor zavírá jakono_answer, po uzavření uvolňuje tenant kvótu souběžných hovorů.relay_lease_limitpři vytáčení úkolu je dočasný stav bez započítání pokusu. - 11. 9. 2026 (1.6.1):
POST /v1/tasks/csv-previewa portál rozpoznávají sloupec telefonu bez ohledu na velikost písmen, mezery a koncovou dvojtečku a přijímají aliasy (telefon,tel,mobil,phone number); v odpovědi je sloupec vždyphone. Jednosloupcový vstup bez hlavičky, jehož první hodnota je telefon, se bere jako data. Bez sloupce telefonu vrací náhled jedinou chybuphoneu hlavičky, nePhone is requiredna každém řádku. Kontraktagent_not_readyse nemění. Oprava popisu 12. 9. 2026: původní zmínka nástroje MCP byla nesprávná; náhled CSV je pouze REST/portál. - 11. 9. 2026 (1.6.0):
GET /v1/numbers/{e164}/sipa MCPget_sip_credentialsvrací navícoutboundTrunkAddress,port,transportainboundSignallingCidrsvedleserver/username/password; MCPcreate_relay_leasea popis nástrojeget_sip_credentialsteď výslovně rozlišujíserver(registrace) odoutboundTrunkAddress(odchozí trunk platformy). Dokumentace na/docs/vlastni-agent, integrace ElevenLabs i blog už dooutbound_trunk_config.addressnedosazujíserver, jenoutboundTrunkAddress. - 11. 9. 2026 (1.5.1):
GET /v1/calls,GET /v1/calls/{id}, webhookcall.completeda MCPlist_calls/get_call:answeredByje přítomné jen přidirection: "out"(i u starších záznamů).POST /v1/messagesasend_sms: účet bez aktivního čísla a bez kladného pohybutopup/refund/adminv ledgeru dostane po třech odeslaných SMSinsufficient_credit(HTTP 402, causeaccount). - 8. 9. 2026 (1.5.0): Nové REST endpointy:
GET/PATCH /v1/account,PUT /v1/account/billing,GET /v1/api-keys,DELETE /v1/api-keys/{id}(self-revoke);PATCH /v1/calls/{id}a rozšířené queryGET /v1/callsofrom,to,agentId,flagged,goal,outcome;POST /v1/tools/test,POST /v1/tools/{id}/test,DELETE /v1/webhookaGET /v1/tools/{id}navíc vracíagents;POST /v1/agents/{id}/draft/rollback;GET /v1/numbers/{e164},GET/POST /v1/numbers/waitlist,DELETE /v1/numbers/waitlist/{offerId},GET /v1/numbers/{e164}/sip/status;POST /v1/integrations,DELETE /v1/integrations/{id},POST /v1/integrations/{id}/events/{eventId}/propose;GET /v1/changelog(bez klíče,x-volai-versionna všech v1 odpovědích včetně chyb, 429 a/openapi.json). Odpovídajících 16 nových MCP nástrojů:get_account,update_account,update_billing_details,list_api_keys,annotate_call,test_tool,remove_webhook,list_webhook_deliveries,rollback_agent_draft,reconcile_agent_draft_operation,test_call,get_number,join_number_waitlist,leave_number_waitlist,get_sip_status,get_changelog- odvolání cizího API klíče, tvorba API klíče a odpojení integrace/karty zůstávají REST-only nebo jen v portálu (spec §3). Nový katalog schopností nesecapabilitypole u každého endpointu a nástroje; strážné testy ověřují, že chybová tabulka a ukázka odpovědi na/docs/apisedí na skutečných chybových kódech u všech endpointů. Aditivní, žádný existující status ani kód se nemění. Nový souborcontent/changelog.jsonje jediný zdroj pravdy:/novinky, sekce Historie změn na/docs/api, sekce Versioning v SKILL.md, RSS (/en/feed/<oblast>),GET /v1/changeloga MCPget_changelogjsou nad ním jen generované pohledy. Aditivní, žádný existující obsah nezmizel. Nové REST endpointy:GET/POST /v1/tasks,GET/PATCH/DELETE /v1/tasks/{id},POST /v1/tasks/{id}/start,POST /v1/tasks/{id}/pause,POST /v1/tasks/{id}/reconcile,POST /v1/tasks/csv-preview. Odpovídajících 7 nových MCP nástrojů:list_tasks,get_task,create_task,update_task,pause_task,reconcile_task,start_task(ten vyžaduje zopakovat skutečný počet příjemců a rozpočet, jinak vrátí chybu s vypsanými skutečnými čísly) - smazání úkolu a náhled CSV zůstávají jen REST a portál (spec §3). Portál: tlačítko Smazat úkol v detailu úkolu s opsáním názvu. Aditivní, žádný existující status ani kód se nemění. Nové REST endpointy:GET /v1/credit/ledger,POST /v1/credit/topup,GET/PATCH /v1/credit/auto-topup,POST /v1/credit/auto-topup/setup,POST/DELETE /v1/credit/auto-topup/card,GET /v1/billing/documents,GET /v1/billing/documents/{id},GET /v1/billing/documents/{id}/pdf;GET /v1/balancenavíc vracírunwayanotice. Odpovídajících 6 nových MCP nástrojů:list_ledger,create_topup_link,get_auto_topup,disable_auto_topup,list_billing_documents,get_billing_document(get_balancerozšířen o stejnérunway/notice) -get_billing_documentnevrací PDF, to zůstává jen přes RESTGET /v1/billing/documents/{id}/pdf(binární výstup); zapnutí automatického dobíjení, změna částky a karty zůstávají jen přes odkaz na Stripe Checkout, MCP nemá ani jedno z toho (spec §2, §3). Aditivní, žádný existující status ani kód se nemění.GET /v1/accountvrací nové polenotifications.productUpdates(výchozí zapnuto); přepínač je i v Nastavení portálu. Denní e-mailový souhrn (cron0 6 * * *UTC) posílá jen účtům s ověřeným e-mailem aproductUpdates !== false, nejvýš jeden e-mail na účet a den. HlavičkaList-Unsubscribea jednoklikové odhlášení bez cookies platí od teď i pro reaktivační e-mail, pokud je na serveru nastavenéUNSUBSCRIBE_SECRET- bez něj e-mail odejde i tak, jen bez odkazu na odhlášení. Aditivní, žádný existující status ani kód se nemění. - 8. 9. 2026 (1.4.3): Každá vlastnost vstupního schématu všech 44 MCP nástrojů nese vlastní
description(vidí ji klient vtools/list; u tělaPATCH .../events/{eventId}aPUT /v1/agents/{id}/draftiopenapi.json). Fakturační endpointyGET /v1/integrations/{id}/invoices[/{invoiceId}]mají v dokumentaci a v OpenAPI seznam chyb podle skutečné dosažitelnosti -integration_storage_errorz nich zmizel, z API nikdy nepřicházel - a validace jejich query vrací lidskou hlášku jako zbytek v1 (stejněGET .../events). Aditivní, žádný status ani kód se nemění. - 8. 9. 2026 (1.4.2): Oprava čtení a potvrzených úprav Apple událostí: iCloud odmítá hledání podle UID, proto výpis vrací neprůhledné identifikátory zdrojových souborů CalDAV. externalId předávej beze změny jako eventId; Apple identifikátory uložené ze starší verze načti znovu. Neplatný Apple identifikátor vrací 400 calendar_invalid_query. Google identifikátory se nemění.
- 8. 9. 2026 (1.4.1):
POST /v1/agentsacreate_agentberouuseForOutboundTasks(volba vlastního hlasového motoru volai při zakládání, stejná jako zaškrtávátko „Používat v odchozích úkolech“ v portálu; bez pole platí výchozí nastavení, dnes ElevenLabs). Aditivní, žádný status ani kód se nemění. - 8. 9. 2026 (1.4.0): Apple Calendar používá stejný kalendářový tok v REST i MCP jako Google. Fakturoid a ABRA Flexi přinesly endpointy
GET /v1/integrations/{id}/invoices[/{invoiceId}]a nástrojelist_invoicesaget_invoice(rozhraní faktury jen čte).GET /v1/integrationsalist_integrationsvrací navícproviderss připraveností konfigurace a odkazem pro připojení. Přihlašovací údaje poskytovatele je pořád nutné připojit v portálu. Aditivní, žádný status ani kód se nemění. - 7. 9. 2026 (1.3.0): Přibyly kalendářové endpointy
GET /v1/integrations,GET /v1/integrations/{id}/calendars,GET /v1/integrations/{id}/events,GET/PATCH /v1/integrations/{id}/events/{eventId}a šest MCP nástrojů (list_integrations,list_calendars,list_calendar_events,get_calendar_event,propose_calendar_update,confirm_calendar_update) - Google Kalendář tak vstoupil do veřejného rozhraní (čtení a potvrzená úprava události), REST je na 50 endpointech a MCP na 42 nástrojích. Každá chybová odpověď nese navíccause(request/account/busy/service- kdo chybu opraví) aaction(jedna věta, co udělat). Hlášky kóduvalidationříkají pole, skutečnou hodnotu a přijatý strop místo surového textu validátoru; stropy vstupu u jména, instrukcí, cíle a podkladů agenta jsou desetinásobkem produktových limitů, takže limit hlásí vždy produktová chyba s přesným číslem. MCP chyby mají stejná pole vestructuredContent.error(včetněrequestId) a text s prefixem podle příčiny. Vše je aditivní, statusy ani kódy se nemění. - 6. 9. 2026 (1.2.0): Endpointy
/v1/agents/{id}/draft*a/simulateztratily obaloka chybový prostý řetězec - chyby mají od teď stejný tvar{error:{code,message,requestId,docsUrl}}jako zbytek v1;revisionv tělech požadavků se přejmenovala naexpectedRevision; přibylohasMore/nextBeforeu stránkování, hlavičkyX-Request-IdaRateLimit-*,POST /v1/webhook/test,GET /v1/webhook/deliveriesaGET /openapi.json. Endpointy konceptu byly veřejné už od 5. 9. 2026, ale bez stabilního obalu - jsou proto ze záruky (pravidlo 1 sekce Verzování) do verze 1.2.0 vyjmuté.
Úplný a průběžně aktualizovaný seznam je na stránce Novinky (i jako RSS kanál).
Konvence
Zvyklosti, které platí napříč endpointy - ne jen u jednoho z nich.
Identifikátory
Každé ID nese prefix podle typu záznamu a je jinak neprůhledné (dál ho neparsuj):
vk_ API klíč, ag_ agent, ad_ koncept agenta, ado_ operace nad konceptem, c_ hovor, msg_ SMS zpráva, tl_ nástroj, whd_ doručení webhooku, rl_ relay lease, int_ připojení (integrace), inv_ daňový doklad (GET /v1/billing/documents), l_ položka historie kreditu, task_ úkol, item_ příjemce v úkolu, attempt_ pokus o vytočení položky úkolu, req_ ID požadavku (viz Formát chyby výš).
Časy
Časová razítka jsou skoro všude unixové milisekundy (createdAt, startedAt, boughtAt, issuedAt, taxableAt) - VÝJIMKA jsou pole napojeného kalendáře A dokladů: start, end, fetchedAt (kalendář) a parametry timeMin/timeMax jsou řetězce RFC 3339 (2026-09-08T10:00:00.000Z), nikdy číslo; GET /v1/integrations/{id}/invoices a .../invoices/{externalId} jsou taky řetězce - fetchedAt stejně RFC 3339, dueDate je čisté datum (2026-09-08) přímo od Fakturoidu/ABRA Flexi, nebo null, když ho poskytovatel nedal.
Stránkování - tři schémata a výpisy bez
GET /v1/messages, GET /v1/calls a GET /v1/billing/documents berou limit + before (ms razítko, exkluzivní) a vrací hasMore/nextBefore - podrobně viz Stránkování výš. Události napojeného kalendáře (GET /v1/integrations/{id}/events) místo toho používají neprůhledný pageToken/nextPageToken - timeMin/timeMax/search musí mezi stránkami zůstat stejné, pageToken sám o sobě to nezajistí. GET /v1/credit/ledger bere jen limit (1-200, výchozí 50), žádný kurzor - vždy začíná od nejnovější položky. GET /v1/tasks taky nemá kurzor a vrací nejvýš 100 nejnovějších úkolů. GET /v1/webhook/deliveries taky nemá kurzor a vrací nejvýš posledních 50 doručení (úspěšná, neúspěšná i testovací). Hledání v napojených dokladech se taky tiše ořízne - prvních 40 řádků u Fakturoidu nebo 50 u ABRA Flexi, bez kurzoru na další; místo stránkování dotaz zúži. Všechno ostatní, co vrací seznam (agenti, čísla, nástroje, API klíče, seznam nevolat, hlasy), vrací celou množinu najednou - není co stránkovat.
Neznámé a české parametry
Neznámý query parametr se skoro všude tiše ignoruje (ať starší klient nespadne na jeden navíc poslaný parametr) - výjimkou jsou endpointy napojeného kalendáře a napojených dokladů (/v1/integrations/{id}/...), které neznámý parametr odmítnou chybou 400 validation, protože ho posílají dál poskytovateli a tiše zahozený filtr by tam vypadal jako chybějící data, ne jako chyba; a z jiného důvodu i GET /v1/credit/ledger a GET /v1/billing/documents, jejichž query schéma je schválně striktní, ať překlep v limit/before spadne hlasitě místo tichého ignorování.
Pár polí schválně nese české jméno: tok adresy k číslu (GET /v1/numbers/address-options, pak POST /v1/numbers/orders - prosté POST /v1/numbers bere jen e164/region a adresu ignoruje) posílá psc, obec, cobce, ulice (jen tam, kde adresa ulici má) a cp - přesně jak je pojmenuje číselník RÚIAN (vlastní adresní registr operátora), odkud se číslo objednává, ať se hodnota mezi nimi nikdy tiše nepřeloží špatně. GET /v1/calls/{id}/recording?stahnout=1 je jediný český parametr mimo tenhle tok (stáhnout jako přílohu místo zobrazení v prohlížeči). Všechno ostatní - identifikátory, pole i parametry - je anglicky.
Kvóty na jednom místě
Každá kvóta je zmíněná i u svého endpointu výš - tady je jen souhrn:
- 60 požadavků/min na API klíč (REST a MCP si limit dělí, viz Rate limits výš)
- SMS: 1 za 2 s a 100/den na účet, až po prvním dobití kreditu
- SMS odesílané ze SMS čísla (
fromNumber): navíc 20 zpráv za den na účet v prvních 30 dnech od koupě čísla, potom 50; nejvýš dvě SMS čísla na účet - Odchozí hovory (agent, most, zkušební): 10/min a 1000/den na účet, nejvýš 2 souběžné hovory přes vestavěného agenta
- Zkušební hovor bez vlastního čísla (
POST /v1/callssesystemPromptmístoagentId/from): navíc 3/24 h na účet A sdílený strop 30/hod napříč VŠEMI účty dohromady - do sdíleného stropu narazíš i bez vlastního zavinění. POST /v1/agents/{id}/test-call: 3/den na účetPOST /v1/tools/testa.../{id}/test: 10/min na účetPOST /v1/agents/{id}/simulate: 20/hod na účetPOST /v1/webhook/test: 10/hod na účetGET /v1/changelog: 30/min na IP adresu (bez API klíče)- Úkoly: běžící úkol vytočí nejvýš JEDNOHO příjemce za jeden běh cronu (
*/2 * * * *) a jeden běh se dotkne nejvýš 20 úkolů napříč VŠEMI účty - i s kreditem a otevřeným oknem volání jsou tak volání z jednoho úkolu od sebe zhruba dvě minuty, a při vytížení (přes 20 běžících úkolů) se úkoly střídají spravedlivě, ne jeden po druhém do konce.
Opakování webhooku
Neúspěšné doručení dostane až 3 pokusy po 3 sekundách v rámci téhož odeslání. U hovorových událostí (call.completed, call.failed, call.no_answer, call.missed) a u message.received tím doručování nekončí: událost zůstává ve frontě a doručení se v následujících minutách ještě zopakuje, nejvýš do 5 kol - dedupuj podle event_id v těle, kdyby ti výjimečně dorazila víckrát. message.sent a testovací webhook.test frontu nemají: po neúspěchu se jen zaloguje a znovu se neposílá. Průběh (včetně mezistavů před posledním kolem, attempts je součet pokusů napříč VŠEMI koly) uvidíš v GET /v1/webhook/deliveries (nebo list_webhook_deliveries).
Zastarávání
v1 zatím jen přibývá (viz Verzování výš) - jedinou výjimkou byla verze 1.5.1, která u PŘÍCHOZÍCH hovorů přestala vracet answeredBy (pole u nich nikdy nemělo smysluplnou hodnotu, u odchozích hovorů se nemění). Skutečné zrušení pole v v1 volai zatím neudělalo. Až k tomu dojde, pole dostane deprecated: true v GET /openapi.json a odpověď ponese hlavičky Deprecation/Sunset aspoň 90 dní předem, MCP odpověď, která se pole dotkne, navíc dostane položku ve warnings (stejné pole, jaké dnes nese upozornění na chybějící informaci o AI podle Aktu o umělé inteligenci) - samo odebrání přijde vždy jen jako nová hlavní verze (v2), nikdy tiše uvnitř v1.
Hovory vs. konverzace - viz stejnojmenný odstavec v sekci Hovory níž, než budeš sčítat počty.
Přihlašovací údaje (heslo, token, aplikační heslo) pošli jen tehdy, když ho uživatel už má někde, odkud ho umíš přečíst (proměnná prostředí nebo soubor, který sám pojmenoval) - nikdy si o něj neříkej v konverzaci a nikdy ho neopakuj zpátky; platí dnes pro Apple Kalendář a ABRA Flexi (viz sekce o kalendáři a dokladech níž).
Co přes API nejde
Telefonii ovládáš přes API a MCP celou - čísla, hovory, SMS, agenty, webhooky, relay i seznam nevolat. Profil účtu, fakturační adresa a firemní údaje jdou přes API taky (sekce Účet výš). Pár věcí ale zůstává jen v portálu, záměrně:
| Co | Kde to je a proč |
|---|---|
| Dobití kreditu | Portál /kredit (jednorázově i automatické dobíjení). Platba kartou je krok člověka - agent, který si sám doplní kredit, aby mohl dál volat, je přesně to, co nechceme. Když akce narazí na insufficient_credit, řekni to uživateli a pošli ho sem. |
| Vytvoření nového API klíče | Portál /api-a-mcp. Výpis (GET /v1/api-keys) a odvolání VLASTNÍHO klíče (DELETE /v1/api-keys/{id}) jdou přes API - jen vytvoření nového klíče ne: klíčem by se vyráběl další klíč, únik jednoho by pak znamenal trvalý přístup, který se nedá odebrat. |
| Změna hesla | Portál /nastaveni. Jméno, jazyk účtu i fakturační adresa jdou přes PATCH /v1/account a PUT /v1/account/billing (sekce Účet výš) - heslo ne, je to čistě prohlížečová akce s vlastním potvrzením. |
| Daňové doklady | Portál /kredit, sekce Doklady - ke každému dobití kreditu tam čeká PDF ke stažení. Přes API se doklad nedá vystavit ani stáhnout: je to účetní dokument s vlastní číselnou řadou, který se nikdy nemění a nesmí vzniknout dvakrát. |
| SMS na hlasových číslech | Nikde - hlasová čísla volai SMS nepřijímají. SMS přijímá jen doplněk SMS číslo, viz sekce SMS čísla níž. |
Opačným směrem toho v MCP schválně chybí víc: uvolnění zakoupeného čísla (DELETE /v1/numbers/{e164}) je v REST API i v portálu, ale ne mezi MCP nástroji - nevratná akce, na kterou je jedna špatně pochopená věta málo. Stejně schválně chybí i výdej nahrávky (binární tělo, GET /v1/calls/{id}/recording), detail jedné zprávy nebo jednoho nástroje (výpisy list_messages/list_tools nesou stejná pole, jen ne pro jediné ID) a samostatný nástroj pro zkušební hovor - make_call s agentId vytočí stejný hovor jako POST /v1/agents/{id}/test-call, jen bez jeho přísnějšího denního limitu 3 hovorů.
Účet
Profil, tísňová adresa, fakturační údaje a přehled API klíčů. Tvorba nových API klíčů (POST /v1/api-keys) se nevystavuje - klíč, který razí klíče, by mohl ze ztráty jednoho udělat trvalý přístup. Nový klíč vytvoříš v portálu (sekce Přístupy a API). E-mailová upozornění (callSummary, lowCredit, reactivation, productUpdates) jdou přes tohle rozhraní jen ČÍST - zápis je výhradně v portálu, protože lowCredit je jediná brzda mezi docházejícím kreditem a tichým vyčerpáním.
GET/v1/account
Profil, tísňová adresa, fakturační údaje a stav e-mailových upozornění (jen čtení).
Požadavek
curl https://volai.cz/v1/account \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"account": {
"id": "u_8f2a1c9d3b47",
"email": "radek@example.com",
"name": "Radek Klein",
"locale": "cs",
"emailVerified": true,
"createdAt": 1755000000000,
"companyName": "Ukázková s.r.o.",
"address": { "street": "Na Zámku 636", "city": "Nehvizdy", "zip": "250 81" },
"billing": null,
"notifications": { "callSummary": true, "lowCredit": true, "reactivation": true, "productUpdates": true, "weeklySummary": true }
}
}Chybové stavy
- 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu.
PATCH/v1/account
Mění jméno a jazyk účtu. locale řídí jazyk e-mailů a daňových dokladů, NE jazyk téhle odpovědi - REST a MCP mluví vždy anglicky. Aspoň jedno pole musí být přítomné.
Požadavek
curl -X PATCH https://volai.cz/v1/account \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"locale":"en"}'Odpověď
{
"account": {
"id": "u_8f2a1c9d3b47",
"email": "radek@example.com",
"name": "Radek Klein",
"locale": "en",
"emailVerified": true,
"createdAt": 1755000000000,
"companyName": "Ukázková s.r.o.",
"address": { "street": "Na Zámku 636", "city": "Nehvizdy", "zip": "250 81" },
"billing": null,
"notifications": { "callSummary": true, "lowCredit": true, "reactivation": true, "productUpdates": true, "weeklySummary": true }
}
}Chybové stavy
- 400
validationTělo požadavku není platný JSON objekt, neobsahuje ani jedno pole k úpravě,nameje prázdný řetězec nebo přesahuje 200 znaků, nebolocalenenícsanien. - 400
invalid_nameJméno po odstranění mezer na začátku a na konci zůstalo prázdné. - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu.
PUT/v1/account/billing
Ukládá tísňovou adresu a firemní údaje. address, když je přítomné, nese ulici, město i PSČ najednou - žádné se nedá poslat samostatně. company, ico a dic se slučují s tím, co je uložené: chybějící pole se NEMĚNÍ, jen prázdný řetězec ("") pole smaže (u dic i jeho ověření ve VIES). Zahraniční DIČ z EU se ověří v registru VIES; vies v odpovědi je vyplněné jen tehdy, když výsledek nese ověřené DIČ (čerstvě, nebo z podrženého staršího ověření). Tuzemské DIČ (CZ...) se neověřuje - na sazbu nemá vliv.
Požadavek
curl -X PUT https://volai.cz/v1/account/billing \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"company":"Ukázková s.r.o.","dic":"SK9999999999","address":{"street":"Na Zámku 636","city":"Nehvizdy","zip":"250 81"}}'Odpověď
{
"billing": {
"company": "Ukázková s.r.o.",
"ico": null,
"dic": "SK9999999999",
"dicCountry": "SK",
"dicVerified": true,
"dicName": "Ukázková s.r.o."
},
"address": { "street": "Na Zámku 636", "city": "Nehvizdy", "zip": "250 81" },
"vies": { "dic": "SK9999999999", "country": "Slovakia", "name": "Ukázková s.r.o." }
}Chybové stavy
- 400
validationTělo požadavku není platný JSON objekt, obsahuje neznámé pole (schéma je striktní),company/ico/dicpřesahuje 120/20/20 znaků,addressobsahuje neznámé pole,address.streetneboaddress.cityje prázdné nebo přesahuje 200 znaků, neboaddress.zipmá méně než 3 nebo víc než 10 znaků. - 400
invalid_addressUlice nebo město po odstranění mezer na začátku a na konci zůstaly prázdné (třeba pole složené jen z mezer), nebo PSČ neprojde normalizací - nevypadá jako poštovní směrovací číslo. - 400
invalid_icoKontrolní součet IČO nesedí. - 400
invalid_dicDIČ nemá platný tvar (tuzemskéCZa 8-10 číslic, zahraniční kód země a číslo registru). - 400
foreign_vat_unsupportedKód země u DIČ není členský stát EU - přenesení daňové povinnosti platí jen uvnitř EU. - 400
vat_id_not_foundEvropský registr plátců (VIES) tohle DIČ nezná. Bez ověření se účtuje česká DPH. - 503
vat_registry_unavailableRegistr VIES je momentálně nedostupný - zkus to znovu později; starší ověření (pokud existuje) zůstává v platnosti. - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu.
GET/v1/api-keys
Seznam API klíčů na účtu. id je jen prvních 12 znaků otisku klíče - plný otisk ven nejde nikdy.
Požadavek
curl https://volai.cz/v1/api-keys \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"apiKeys": [
{
"id": "3f9a2c8e1b04",
"label": "Production integration",
"prefix": "vk_8h2j4kx",
"createdAt": 1750000000000,
"lastUsedAt": 1757280000000
}
]
}DELETE/v1/api-keys/{id}
Self-revoke: přes API smí klíč odvolat JEN SÁM SEBE, ne cizí klíč na účtu - jinak by ukradený klíč odstřihl všechny ostatní integrace a sám zůstal aktivní. Odvolání ostatních klíčů je jen v portálu. Po odvolání jde majiteli e-mail bez ohledu na to, kdo odvolání zadal.
Požadavek
curl -X DELETE https://volai.cz/v1/api-keys/3f9a2c8e1b04 \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"revoked": true
}Chybové stavy
- 404
not_foundKlíč s tímhleidna účtu není. - 403
api_key_self_onlyidv cestě patří jinému klíči, než kterým je požadavek autentizovaný - přes API lze odvolat jen sám sebe.
Kredit
balanceHal i všechny sazby v tomhle API jsou bez DPH - volai je plátce DPH, ale DPH se řeší až při dobíjení kreditu kartou v portálu (přehled na stránce /cenik), API samotné s ní nepočítá. Podrobný průvodce s příklady toku je na /docs/kredit.
GET/v1/balance
Aktuální zůstatek kreditu na účtu, plus runway (odhad, na kolik dní kredit vydrží při současném tempu útraty) a notice (stejné upozornění jako na /prehled v portálu, null když žádné není) - obojí ADITIVNĚ, existující klient čtoucí jen balanceHal/balanceCzk/currency se nerozbije.
Požadavek
curl https://volai.cz/v1/balance \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"balanceHal": 8730,
"balanceCzk": 87.30,
"currency": "CZK",
"runway": { "dailyAverageHal": 2910, "runwayDays": 3 },
"notice": { "kind": "runway", "days": 3 }
}Chybové stavy
- 503
ledger_unavailableZůstatek nebo historii pohybů se momentálně nedaří přečíst - zkus to znovu za chvíli.
GET/v1/credit/ledger
Historie pohybů kreditu, nejnovější první, BEZ kurzoru (jen limit, 1-200, výchozí 50). description u každého záznamu je anglický popis SLOŽENÝ z type - uložená česká poznámka ven nejde nikdy.
Požadavek
curl "https://volai.cz/v1/credit/ledger?limit=3" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"ledger": [
{ "id": "l_9f2a1c8e", "ts": 1757280000000, "type": "call_out", "amountHal": -420, "grossHal": null, "description": "Outbound call" },
{ "id": "l_7c1e9a2f", "ts": 1757193600000, "type": "number_fee", "amountHal": -9900, "grossHal": null, "description": "Monthly number fee for +420601234567" },
{ "id": "l_3b7e1c9a", "ts": 1757107200000, "type": "topup", "amountHal": 50000, "grossHal": 60500, "description": "Card top-up" }
]
}Chybové stavy
- 400
validationlimitje mimo rozsah 1-200, nebo požadavek nese neznámý parametr navíc. - 503
ledger_unavailableZůstatek nebo historii pohybů se momentálně nedaří přečíst - zkus to znovu za chvíli.
POST/v1/credit/topup
Vytvoří odkaz na Stripe Checkout pro jednorázové dobití pevnou částkou v korunách. Nic se nestrhne, dokud platbu sám nedokončí ČLOVĚK v prohlížeči. Podporuje Idempotency-Key.
Požadavek
curl -X POST https://volai.cz/v1/credit/topup \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: topup-2026-09-08-01" \
-d '{"amountCzk": 500}'Odpověď
{
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4"
}Chybové stavy
- 400
validationamountCzkchybí, není celé kladné číslo, nebo tělo obsahuje neznámé pole. - 400
invalid_amountČástka není jedna z pevně nabízených hodnot. - 400
billing_address_requiredFakturační adresa na účtu chybí nebo je neúplná - bez ní nejde vystavit platný daňový doklad. Doplň ji přesPUT /v1/account/billing. - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu. - 503
stripe_not_configuredPlatby jsou pro tenhle běh volai vypnuté - netýká se konkrétně tvého požadavku. - 502
stripe_errorStripe odmítl vytvořit platební relaci - zkus to znovu za chvíli.
GET/v1/credit/auto-topup
Stav automatického dobíjení: zapnuto/vypnuto, práh, částka, uložená karta (jen značka a poslední čtyři číslice), útrata a strop za tenhle kalendářní měsíc.
Požadavek
curl https://volai.cz/v1/credit/auto-topup \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"autoTopup": {
"enabled": true,
"thresholdHal": 10000,
"amountHal": 50000,
"card": { "brand": "visa", "last4": "4242" },
"spentThisMonthHal": 50000,
"monthlyCapHal": 1000000,
"disabledReason": null
}
}PATCH/v1/credit/auto-topup
VÝHRADNĚ vypnutí ({"enabled": false}) a/nebo změna prahu ({"thresholdHal": ...}) - zapnutí a změna částky jde jen přes POST .../setup (Stripe Checkout), nikdy přímým zápisem, ať s uloženou kartou nemůže holé enabled: true spustit strhávání bez člověka u karty.
Požadavek
curl -X PATCH https://volai.cz/v1/credit/auto-topup \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"thresholdHal": 20000}'Odpověď
{
"autoTopup": {
"enabled": true,
"thresholdHal": 20000,
"amountHal": 50000,
"card": { "brand": "visa", "last4": "4242" },
"spentThisMonthHal": 50000,
"monthlyCapHal": 1000000,
"disabledReason": null
}
}Chybové stavy
- 400
validationTělo obsahujeenabled: trueneboamountHal(obojí patří jen doPOST .../setup),thresholdHalje mimo nabízenou řadu, nebo tělo neobsahuje anienabled, anithresholdHal. - 400
autotopup_not_configuredAutomatické dobíjení ještě nikdy neprošloPOST .../setup- není co vypnout, změnit ani jakou kartu vyměnit. - 400
invalid_amountČástka není jedna z pevně nabízených hodnot.
POST/v1/credit/auto-topup/setup
Vytvoří Stripe Checkout, jehož dokončení OKAMŽITĚ strhne amountHal jako první dobití a teprve tím uloží kartu pro budoucí automatická dobití - funguje i s kartou už uloženou z dřívějška. Jediná cesta, jak dobíjení zapnout nebo mu změnit částku; pouhou změnu prahu bez platby dělá PATCH výš. Fakturační adresa je povinná. Podporuje Idempotency-Key.
Požadavek
curl -X POST https://volai.cz/v1/credit/auto-topup/setup \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: autotopup-setup-2026-09-08-01" \
-d '{"thresholdHal": 10000, "amountHal": 50000}'Odpověď
{
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4"
}Chybové stavy
- 400
validationthresholdHalneboamountHalchybí, nejsou celá nezáporná/kladná čísla, nebo tělo obsahuje neznámé pole. - 400
invalid_amountČástka není jedna z pevně nabízených hodnot. - 400
billing_address_requiredFakturační adresa na účtu chybí nebo je neúplná - bez ní nejde vystavit platný daňový doklad. Doplň ji přesPUT /v1/account/billing. - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu. - 503
stripe_not_configuredPlatby jsou pro tenhle běh volai vypnuté - netýká se konkrétně tvého požadavku. - 502
stripe_errorStripe odmítl vytvořit platební relaci - zkus to znovu za chvíli.
POST/v1/credit/auto-topup/card
Vytvoří Stripe Checkout v režimu výměny karty pro automatické dobíjení - nic se nestrhne, jen se uloží nová karta.
Požadavek
curl -X POST https://volai.cz/v1/credit/auto-topup/card \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4"
}Chybové stavy
- 400
autotopup_not_configuredAutomatické dobíjení ještě nikdy neprošloPOST .../setup- není co vypnout, změnit ani jakou kartu vyměnit. - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu. - 503
stripe_not_configuredPlatby jsou pro tenhle běh volai vypnuté - netýká se konkrétně tvého požadavku. - 502
stripe_errorStripe odmítl vytvořit platební relaci - zkus to znovu za chvíli.
DELETE/v1/credit/auto-topup/card
Odpojí uloženou kartu OKAMŽITĚ - smaže se CELÁ konfigurace automatického dobíjení (práh i částka), ne jen karta. Další zapnutí jde jen znovu přes POST .../setup, který rovnou strhne první dobití.
Požadavek
curl -X DELETE https://volai.cz/v1/credit/auto-topup/card \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"removed": true
}GET/v1/billing/documents
Seznam vystavených daňových dokladů k dobitím kreditu, nejnovější první. before je kurzor (Unix ms, exkluzivní) - pošli nextBefore z předchozí stránky. Úložiště samo nikdy nevrátí víc než 100 záznamů na jedno volání, i když limit požaduje víc.
Požadavek
curl "https://volai.cz/v1/billing/documents?limit=2" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"documents": [
{
"id": "inv_4kX9mQ2pRtLz",
"number": "VF2026000042",
"issuedAt": 1757280000000,
"taxableAt": 1757280000000,
"netHal": 50000,
"vatHal": 10500,
"grossHal": 60500,
"vatRatePercent": 21,
"reverseCharge": false,
"kind": "invoice",
"description": "Prepaid credit for volai telecommunications services",
"customer": { "name": "Radek Klein", "street": "Na Zámku 636", "city": "Nehvizdy", "zip": "250 81" },
"paymentRef": "pi_3PQr7s2eZvKYlo2C1a2b3c4d",
"pdfUrl": "https://volai.cz/v1/billing/documents/inv_4kX9mQ2pRtLz/pdf"
}
],
"hasMore": false,
"nextBefore": null
}Chybové stavy
- 400
validationlimitnebobeforeje mimo povolený rozsah, nebo požadavek nese neznámý parametr navíc.
GET/v1/billing/documents/{id}
Data jednoho daňového dokladu - částky, DPH, zákazník, platební reference a odkaz na PDF.
Požadavek
curl https://volai.cz/v1/billing/documents/inv_4kX9mQ2pRtLz \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"document": {
"id": "inv_4kX9mQ2pRtLz",
"number": "VF2026000042",
"issuedAt": 1757280000000,
"taxableAt": 1757280000000,
"netHal": 50000,
"vatHal": 10500,
"grossHal": 60500,
"vatRatePercent": 21,
"reverseCharge": false,
"kind": "invoice",
"description": "Prepaid credit for volai telecommunications services",
"customer": { "name": "Radek Klein", "street": "Na Zámku 636", "city": "Nehvizdy", "zip": "250 81" },
"paymentRef": "pi_3PQr7s2eZvKYlo2C1a2b3c4d",
"pdfUrl": "https://volai.cz/v1/billing/documents/inv_4kX9mQ2pRtLz/pdf"
}
}Chybové stavy
- 404
invoice_not_foundDoklad s tímhleidna účtu není (cizí i neexistujícíidhlásí stejnou chybu).
GET/v1/billing/documents/{id}/pdf
Stáhne stejný doklad jako application/pdf - sází se čerstvě při každém stažení, neukládá se.
Požadavek
curl https://volai.cz/v1/billing/documents/inv_4kX9mQ2pRtLz/pdf \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-o invoice.pdfChybové stavy
- 404
invoice_not_foundDoklad s tímhleidna účtu není (cizí i neexistujícíidhlásí stejnou chybu).
Úkoly
Úkol vytočí seznam příjemců jedním agentem podle předem nastavených pravidel (rozpočet, volací okno, počet pokusů) - nic se nevytáčí, dokud ho sám nespustíš (POST .../start). Kompletní průvodce s CSV importem, stavy a globální propustností je na /docs/ukoly.
GET/v1/tasks
Seznam úkolů na účtu, bez stránkování (strop 100 úkolů).
Požadavek
curl https://volai.cz/v1/tasks \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"tasks": [
{
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 50000,
"reservedBudgetHal": 0,
"spentHal": 0,
"status": "draft",
"revision": 0,
"createdAt": 1757280000000,
"updatedAt": 1757280000000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "pending", "attempts": [] }
]
}
]
}POST/v1/tasks
Založí úkol ve stavu draft - nic se nevytáčí. agentId může být jakýkoli aktivní agent, i na ElevenLabs - požadavek na motor (provider: "engine", volba při založení agenta přes useForOutboundTasks: true) se kontroluje až u POST .../start, kde pak selže s engine_required. Nejvýš 1000 recipients. Bez retryPolicy má maxAttempts rozsah 1-3 a výchozí 1; s volitelným retryPolicy: "lorela_enterprise" rozsah 1-4 a výchozí 4. Volitelné expiresAt (kladné bezpečné celé číslo, Unix ms) brání novým hovorům od konce kampaně, včetně prvního. Politika i konec se vracejí v detailu úkolu. Podporuje Idempotency-Key.
Požadavek
curl -X POST https://volai.cz/v1/tasks \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: task-2026-09-08-01" \
-d '{
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"maxAttempts": 2,
"budgetHal": 50000,
"recipients": [
{ "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" } }
]
}'Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 50000,
"reservedBudgetHal": 0,
"spentHal": 0,
"status": "draft",
"revision": 0,
"createdAt": 1757280000000,
"updatedAt": 1757280000000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "pending", "attempts": [] }
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma (chybějící pole, špatný typ, víc než 1000 příjemců nebo úkol větší než 2 MB, neplatné telefonní číslo u některého příjemce...). - 404
agent_not_foundAgent s tímhleagentIdna účtu není, nebo není aktivní. - 400
budget_too_lowbudgetHalnepokryje ani jeden pokus v maximální délce hovoru (maxDurationSecs).
GET/v1/tasks/{id}
Detail úkolu VČETNĚ issues - dry-run validace toho, co úkolu dnes brání ve startu (počítá se čerstvě, nic se neukládá).
Požadavek
curl https://volai.cz/v1/tasks/task_9f3a2c1d \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 50000,
"reservedBudgetHal": 0,
"spentHal": 0,
"status": "draft",
"revision": 0,
"createdAt": 1757280000000,
"updatedAt": 1757280000000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "pending", "attempts": [] }
],
"issues": []
}
}Chybové stavy
- 404
task_not_foundŽádný úkol s tímhleidna účtu není.
PATCH/v1/tasks/{id}
Upraví pravidla editovatelného úkolu (name, recipients, callingWindow, maxAttempts, retryPolicy, expiresAt, maxDurationSecs, budgetHal) - agentId, taskType a source po založení měnit nejdou. revision je POVINNÁ (optimistická souběžnost). Politiku lze zapnout jen před prvním pokusem; stejnou lze znovu poslat i později. Vynechané maxAttempts, retryPolicy a expiresAt se nemění. maxAttempts: 4 vyžaduje politiku v tomto požadavku nebo už uloženou u úkolu.
Požadavek
curl -X PATCH https://volai.cz/v1/tasks/task_9f3a2c1d \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"revision": 0, "budgetHal": 80000}'Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 80000,
"reservedBudgetHal": 0,
"spentHal": 0,
"status": "draft",
"revision": 1,
"createdAt": 1757280000000,
"updatedAt": 1757280060000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "pending", "attempts": [] }
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma, nebo neobsahujerevision. - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision. - 409
task_not_editableÚkol jerunning/completed, neboneeds_attentionbez možnosti obnovy - pravidla teď měnit nejdou. - 409
items_immutableSeznam příjemců (recipients) nejde nahradit poté, co se aspoň jeden pokus o vytočení odehrál nebo byl kontakt auditovaně přeskočen po nákupu.
POST/v1/tasks/{id}/start
Spustí (nebo po pauze obnoví) vytáčení příjemců - KAŽDÝ zvednutý hovor se účtuje ihned, rozpočet se rezervuje před vytočením. Podporuje Idempotency-Key.
Požadavek
curl -X POST https://volai.cz/v1/tasks/task_9f3a2c1d/start \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: task-start-2026-09-08-01" \
-d '{"revision": 1}'Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 80000,
"reservedBudgetHal": 0,
"spentHal": 0,
"status": "running",
"revision": 2,
"createdAt": 1757280000000,
"updatedAt": 1757280120000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "pending", "attempts": [] }
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma, neobsahujerevision, nebo už uplynuloexpiresAt. - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision. - 409
task_not_startableÚkol není ve stavudraft/ready/paused, nebo nemá žádného čekajícího příjemce. - 409
task_needs_attentionPřed dalším startem je potřebaPOST .../reconcile- něco se za běhu úkolu změnilo. - 404
agent_not_foundAgent s tímhleagentIdna účtu není, nebo není aktivní. - 403
agent_suspendedAgenta úkolu ručně pozastavil provozovatel volai - dokud pozastavení trvá, úkol nejde spustit ani znovu spustit po pauze. Pozastavený celý účet vrací místo tohoaccount_suspended. - 409
engine_requiredAgent úkolu není na motoru volai - odchozí kampaně dnes vyžadují motor, ne ElevenLabs. - 409
agent_not_readyKoncept agenta buď není publikovaný, nebo publikovaná verze není otestovaná - publikuj ho (POST /v1/agents/{id}/draft/publish) a pak otestuj publikovanou verzi (POST /v1/agents/{id}/simulate) před startem. - 503
engine_contract_unavailableMotor momentálně neinzeruje podporu pro proměnné a stropy odchozích úkolů - zkus start znovu později. - 409
window_closedMimo nastavené volací okno (callingWindow) - počkej na otevření, nebo ho uprav přesPATCH.
POST/v1/tasks/{id}/pause
Zastaví další vytáčení PŘED dalším pokusem; hovor, který se právě volá, pauza nepřerušuje. Bez Idempotency-Key - opakování se stejnou revizí je bez rizika.
Požadavek
curl -X POST https://volai.cz/v1/tasks/task_9f3a2c1d/pause \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"revision": 2}'Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"status": "paused",
"revision": 3,
"budgetHal": 80000,
"reservedBudgetHal": 0,
"spentHal": 684,
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"createdAt": 1757280000000,
"updatedAt": 1757280180000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "completed", "attempts": [{ "id": "attempt_5d4c3b", "startedAt": 1757280100000, "finishedAt": 1757280160000, "providerCallId": "c_7a2b9c1d", "outcome": "completed", "costHal": 684 }], "actualCostHal": 684 }
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma, nebo neobsahujerevision. - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
task_not_runningPauza jde jen u běžícího (running) úkolu. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision.
POST/v1/tasks/{id}/items/{itemId}/resolve
Samostatná varianta po ověřeném nákupu přijímá action: skip, reason: customer_purchased, revision, operationId a evidenceRef (oba neprůhledné identifikátory do 128 znaků). Přeskočí jen neaktivní pending položku v draft úkolu nebo pending/failed v paused úkolu bez nevypořádaných hovorů a rezervací. Zachovává historii, ceny i DNC; GET vrací neměnný doklad items[].resolution. Stejnou operaci lze zopakovat po nejisté odpovědi bez nového zápisu; jiný doklad už vyřízené položky je 409 revision_conflict. Původní větev bez reason: Rozhodne o kontaktu čekajícím na kontrolu (items[].status: "review"): běžný retry ho vrátí mezi čekající bez započítání dalšího pokusu, skip ho uzavře jako přeskočený. S retryPolicy: "lorela_enterprise" vrací ruční retry chybu validation; povolené jsou jen automaticky naplánované pokusy. Kontakt ve stavu review se může objevit už u běžícího úkolu, ale resolve jde jen u úkolu, který neběží - u běžícího vrací 409 task_not_editable, takže počkej na needs_attention, nebo úkol pozastav (pause). U reviewReason: "dial:destination_auto_blocked" nejdřív zruš blokaci (POST /v1/dnc/{e164}/unblock) a teprve potom dej retry; u dial:cannot_call_own_number, dial:cannot_call_volai_number, dial:invalid_number, dial:unsupported_country a dial:blocked_destination pomůže jen skip. Výjimkou je reviewReason: "billing_unknown": providerCallId i rezervovaný rozpočet zůstávají připojené do POST .../reconcile; po retry nový pokus čeká na doúčtování původního hovoru a po skip už se znovu nevolá, ale původní hovor může být později naúčtovaný (jeho rezervace se dál počítá do rozpočtu). Po retry proto úkol zůstane needs_attention, dokud se cena neusadí; po skip přejde do paused a jde spustit, pokud zbývá práce, jinak počká v needs_attention a po usazení ceny se dokončí. Hovor, který se vůbec nevytočil, se usadí hned na 0. U ostatních důvodů přejde po vyřízení posledního kontaktu z needs_attention do paused (start ho obnoví) nebo completed.
Požadavek
curl -X POST https://volai.cz/v1/tasks/task_9f3a2c1d/items/item_1a2b3c/resolve \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"action": "retry", "revision": 5}'Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 80000,
"reservedBudgetHal": 2400,
"spentHal": 0,
"status": "needs_attention",
"revision": 6,
"createdAt": 1757280000000,
"updatedAt": 1757280240000,
"reviewReason": "billing_unknown",
"items": [
{
"id": "item_1a2b3c",
"phone": "+420777123456",
"variables": { "jmeno": "Jana Novakova" },
"paymentStatus": "not_applicable",
"status": "pending",
"attempts": [
{ "id": "attempt_7c2d", "startedAt": 1757280180000, "finishedAt": 1757280230000, "providerCallId": "c_late_price", "outcome": "completed" }
],
"reviewReason": "billing_unknown",
"providerCallId": "c_late_price",
"estimatedCostHal": 2400,
"reservedCostHal": 2400
}
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma (actionjeretryneboskip,revisionnezáporné celé číslo), neboitemIdna úkolu není, nebo ručníretryodmítá politikalorela_enterprise. - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
task_not_editableÚkol není v povoleném stavu. Pro přeskočení po nákupu použijdraftnebopaused; běžící úkol nejdřív pozastav a doúčtuj aktivní hovory. - 409
item_not_resolvableKontakt nelze vyřídit touto variantou. Běžná větev vyžadujereview;customer_purchasedvyžaduje neaktivnípendingv draftu nebopending/failedv paused úkolu bez nevypořádaných hovorů. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision.
POST/v1/tasks/{id}/reconcile
Sladí stav úkolu se skutečnými hovory po přerušení - bezpečné volat kdykoli, i opakovaně. revision je NA ROZDÍL od start/pause NEPOVINNÁ.
Požadavek
curl -X POST https://volai.cz/v1/tasks/task_9f3a2c1d/reconcile \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{}'Odpověď
{
"task": {
"id": "task_9f3a2c1d",
"status": "completed",
"revision": 3,
"budgetHal": 80000,
"reservedBudgetHal": 0,
"spentHal": 684,
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"createdAt": 1757280000000,
"updatedAt": 1757280240000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "completed", "attempts": [{ "id": "attempt_5d4c3b", "startedAt": 1757280100000, "finishedAt": 1757280160000, "providerCallId": "c_7a2b9c1d", "outcome": "completed", "costHal": 684 }], "actualCostHal": 684 }
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma (revision, je-li uvedená, musí být nezáporné celé číslo). - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision.
POST/v1/tasks/{id}/process
Sladí stav skutečných hovorů a zkusí zpracovat nejvýše jednoho splatného příjemce již běžícího úkolu. Vyžaduje aktuální revision; úkol nikdy sám nespustí ani neobnoví. Používá stejné volací okno, blokace, rezervaci rozpočtu, kredit, kapacitu a atomický claim jako cron. Volitelná uložená volba dispatchOrder: "first_attempts_first" dá přednost splatným kontaktům bez skutečného pokusu; odmítnutí před vytočením (countsAsAttempt: false) jejich přednost nezruší. Výchozí pořadí zůstává nezměněné a budoucí nextAttemptAt se nepřeskakuje. Po nejasném výsledku nejdřív načtěte stav, neopakujte slepě požadavek. Nový logický tik potřebuje nový Idempotency-Key, i když se revize nezměnila.
Požadavek
curl -X POST https://volai.cz/v1/tasks/task_9f3a2c1d/process \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: task-process-2026-10-08-tick-001" \
-d '{"revision": 2}'Odpověď
{
"status": "idle",
"task": {
"id": "task_9f3a2c1d",
"name": "Payment reminder - September",
"agentId": "ag_4e91a2f0",
"taskType": "custom",
"source": "manual",
"callingWindow": { "timezone": "Europe/Prague", "start": "09:00", "end": "18:00", "days": [1, 2, 3, 4, 5] },
"maxAttempts": 2,
"maxDurationSecs": 120,
"budgetHal": 80000,
"reservedBudgetHal": 0,
"spentHal": 0,
"status": "running",
"revision": 2,
"createdAt": 1757280000000,
"updatedAt": 1757280120000,
"items": [
{ "id": "item_1a2b3c", "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "paymentStatus": "not_applicable", "status": "pending", "attempts": [], "nextAttemptAt": 1757280180000 }
]
}
}Chybové stavy
- 400
validationTělo nesedí na schéma, nebo neobsahujerevision. - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision. - 409
task_not_runningÚkol není běžící nebo byl před vytočením pozastaven. Načtěte aktuální stav; process úkol sám neobnoví. - 409
task_pausedÚkol není běžící nebo byl před vytočením pozastaven. Načtěte aktuální stav; process úkol sám neobnoví. - 409
claim_lostVýsledek dispatch nelze bezpečně potvrdit. Načtěte nebo rekonciliujte úkol a zkontrolujte hovor; požadavek slepě neopakujte. - 500
dispatch_result_unpersistedVýsledek dispatch nelze bezpečně potvrdit. Načtěte nebo rekonciliujte úkol a zkontrolujte hovor; požadavek slepě neopakujte. - 409
agent_version_changedPublikovaná verze agenta se změnila. Zkontrolujte ji a před dalším spuštěním úkolu ji znovu otestujte. - 403
agent_suspendedAgenta úkolu ručně pozastavil provozovatel volai - dokud pozastavení trvá, úkol nejde spustit ani znovu spustit po pauze. Pozastavený celý účet vrací místo tohoaccount_suspended. - 503
engine_contract_unavailableMotor momentálně neinzeruje podporu pro proměnné a stropy odchozích úkolů - zkus start znovu později. - 409
window_closedMimo nastavené volací okno (callingWindow) - počkej na otevření, nebo ho uprav přesPATCH.
DELETE/v1/tasks/{id}
Smaže úkol i všechny jeho položky - jen ve stavu draft/ready/paused/completed/needs_attention BEZ položky in_progress. revision čte ?revision= NEBO JSON tělo {"revision": ...} (query má přednost).
Požadavek
curl -X DELETE "https://volai.cz/v1/tasks/task_9f3a2c1d?revision=3" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"deleted": true
}Chybové stavy
- 400
validationrevisionchybí, nebo není nezáporné celé číslo (ani v query, ani v těle). - 404
task_not_foundŽádný úkol s tímhleidna účtu není. - 409
revision_conflictÚkol se mezitím změnil - načti ho znovu (GET) a zopakuj s aktuálnírevision. - 409
task_not_deletableÚkol má položkuin_progress, nebo je ve stavurunning- počkej, až doběhne, nebo ho nejdřív zastav (pause).
POST/v1/tasks/csv-preview
Naparsuje a ověří CSV příjemců PŘED založením nebo úpravou úkolu - nic se neukládá, chyby na jednotlivých řádcích jdou do pole errors ve 200 odpovědi, ne do HTTP chyby.
Požadavek
curl -X POST https://volai.cz/v1/tasks/csv-preview \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"csv": "phone,jmeno\n+420777123456,Jana Novakova\nneplatne,Petr Svoboda\n"}'Odpověď
{
"headers": ["phone", "jmeno"],
"delimiter": ",",
"rows": [
{ "line": 2, "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" }, "errors": [] },
{ "line": 3, "variables": { "jmeno": "Petr Svoboda" }, "errors": [{ "field": "phone", "message": "Invalid phone number", "row": 3 }] }
],
"validRows": [
{ "phone": "+420777123456", "variables": { "jmeno": "Jana Novakova" } }
],
"errors": [{ "field": "phone", "message": "Invalid phone number", "row": 3 }]
}Chybové stavy
- 400
validationTělo neobsahujecsvjako řetězec, nebocsvpřesahuje 1 000 000 znaků.
Čísla
GET/v1/numbers/{e164}/callback-routing
Přečte opt-in politiku zpětného volání vlastního čísla. Výchozí směrování čísla zůstává stejné.
Požadavek
curl "https://volai.cz/v1/numbers/+420601234567/callback-routing" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{"callbackRouting":{"agentIds":["ag_campaign"],"lookbackSecs":604800}}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu.
PUT/v1/numbers/{e164}/callback-routing
Uloží výslovný seznam vlastních aktivních agentů motoru pro zákazníky s jednoznačným skutečným odchozím hovorem z tohoto čísla během lookbackSecs (60-604800 sekund). Neznámý, nejednoznačný nebo neověřený volající zůstane u výchozího agenta. Prázdné agentIds politiku vypne. Volitelná firstMessage platí jen pro ověřený callback. Volitelná missedFirstMessage (do 500 znaků) nahradí firstMessage u zákazníka, jehož předchozí odchozí hovor neměl rozhovor (nezvednuto, záznamník, hlasové menu, nikdo nepromluvil) - takový zákazník nabídku ještě neslyšel; bez ní platí firstMessage pro všechny. Motor dostane u ověřeného callbacku i volai_callback_kind (missed nebo contacted). engineSyncRequired: true znamená, že je nutné samostatně aktivovat webhooks.inbound_route_url v konfiguraci motoru výchozího agenta a ověřit ji čtením; tento požadavek živou konfiguraci motoru nepřepisuje. Detail ověřeného příchozího hovoru obsahuje callbackOf.callId a případně serverové taskId a taskItemId.
Požadavek
curl -X PUT "https://volai.cz/v1/numbers/+420601234567/callback-routing" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"agentIds":["ag_campaign"],"lookbackSecs":604800}'Odpověď
{"callbackRouting":{"agentIds":["ag_campaign"],"lookbackSecs":604800},"engineSyncRequired":true}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu.
GET/v1/numbers
Seznam telefonních čísel na účtu, u každého aktuální směrování.
Požadavek
curl https://volai.cz/v1/numbers \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"numbers": [
{
"e164": "+420601234567",
"routing": { "mode": "agent", "agentId": "ag_kx91fa2b", "hasSipPassword": false, "sipTarget": "engine" },
"monthlyFeeHal": 2500,
"boughtAt": 1756111640000,
"region": "objednavka",
"regionLabel": "Czech number",
"billingMonths": 1
}
]
}GET/v1/numbers/{e164}
Detail jednoho vlastního čísla - stejný tvar jako položka výpisu GET /v1/numbers. Hodí se, když znáš jen E.164 (typicky agent přes MCP) a nechceš stránkovat celý výpis.
Požadavek
curl "https://volai.cz/v1/numbers/+420601234567" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"number": {
"e164": "+420601234567",
"routing": { "mode": "agent", "agentId": "ag_kx91fa2b", "hasSipPassword": false, "sipTarget": "engine" },
"monthlyFeeHal": 2500,
"boughtAt": 1756111640000,
"region": "objednavka",
"regionLabel": "Czech number",
"billingMonths": 1
}
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu.
POST/v1/numbers
Koupí číslo. Prázdné tělo {} přiřadí kterékoli volné z aktuální nabídky, nebo pošli konkrétní { "e164": "..." } z GET /v1/numbers/available. Předvolbu vybereš přes { "region": "brno" } - hodnoty praha, brno, internet, bratislava; číslo z jiného kraje se objednává přes POST /v1/numbers/orders. Strhne se měsíční poplatek 25,00 Kč (u slovenského čísla, nabídka bratislava, rovnou 75,00 Kč - platí se billingMonths měsíců dopředu a stejná částka se strhává znovu po každých billingMonths měsících), směrování začíná na none - nastav ho hned dál přes PATCH.
Požadavek
curl -X POST https://volai.cz/v1/numbers \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{}'Odpověď
{
"number": {
"e164": "+420266266647",
"routing": { "mode": "none", "hasSipPassword": false },
"monthlyFeeHal": 2500,
"boughtAt": 1756111640000,
"region": "praha",
"regionLabel": "Prague",
"billingMonths": 1
}
}Chybové stavy
- 400
validationTělo požadavku nesedí na schéma (e164/region přes 32 znaků nebo špatný typ), nebo region není žádná ze zavedených nabídek. - 402
insufficient_creditKredit nepokryje měsíční poplatek 25,00 Kč. U slovenského čísla (nabídkabratislava) musí kredit pokrýt rovnoumonthlyFeeHal * billingMonths. Účet, který ještě nikdy nedobil kredit, smí z uvítacího kreditu držet jedno číslo (počítá se i rozpracovaná objednávka); další číslo jde koupit až po prvním dobití. Nic neúčtujeme. - 404
number_unavailableTohle konkrétní číslo mezitím koupil někdo jiný - vyber si prosím jiné z aktuální nabídky (GET /v1/numbers/available). - 503
pool_emptyČísla z aktuální nabídky nám došla - objednej z jiného kraje (POST /v1/numbers/orders), nebo se v portálu přihlas do čekačky.
GET/v1/numbers/waitlist
Stav čekačky na každou nabídku ze zásoby (praha/brno/internet/bratislava) - joined říká, jestli na ní účet čeká, available jestli je zrovna skladem.
Požadavek
curl https://volai.cz/v1/numbers/waitlist \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"offers": [
{ "offerId": "praha", "label": "Prague", "joined": false, "available": true },
{ "offerId": "brno", "label": "Brno", "joined": true, "available": false },
{ "offerId": "internet", "label": "Internet number", "joined": false, "available": true },
{ "offerId": "bratislava", "label": "Bratislava", "joined": false, "available": true }
]
}Chybové stavy
- 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu.
POST/v1/numbers/waitlist
Přihlásí se do čekačky na vyprodanou nabídku (POST /v1/numbers selhal kódem pool_empty) - nekupuje číslo, jen zaregistruje zájem. Až se nabídka doplní, dostaneš e-mail. Prázdné tělo {} bere výchozí nabídku (praha).
Požadavek
curl -X POST https://volai.cz/v1/numbers/waitlist \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"offerId": "brno"}'Odpověď
{
"joined": true
}Chybové stavy
- 400
validationofferIdnení žádná z hodnot v nabídce (praha/brno/internet/bratislava). - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu.
DELETE/v1/numbers/waitlist/{offerId}
Odhlásí se z čekačky JEDNÉ nabídky (offerId v cestě) - čekačku na jiné nabídky nemění.
Požadavek
curl -X DELETE https://volai.cz/v1/numbers/waitlist/brno \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"left": true
}Chybové stavy
- 400
validationofferIdv cestě není žádná z hodnot v nabídce. - 404
user_not_foundUživatel, kterému patří API klíč, na účtu chybí - ojedinělý stav, obrať se na podporu.
GET/v1/numbers/available
Nabídka volných čísel k zakoupení (max 5 na region). numbers drží čísla ze zvoleného regionu (bez parametru pražská), regions vždycky celou nabídku najednou - včetně bratislava (slovenské číslo s odlišným poplatkem, viz POST /v1/numbers výš).
Požadavek
curl "https://volai.cz/v1/numbers/available?region=brno" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"region": "brno",
"numbers": ["+420510510129", "+420510510132"],
"regions": [
{
"id": "praha",
"label": "Prague",
"description": "A landline with a Prague area code.",
"numbers": ["+420266266643", "+420266266645"]
},
{
"id": "brno",
"label": "Brno",
"description": "A landline with a Brno area code.",
"numbers": ["+420510510129", "+420510510132"]
},
{
"id": "internet",
"label": "Internet number",
"description": "Area code 910, not tied to any region - works from anywhere.",
"numbers": ["+420910084099"]
},
{
"id": "bratislava",
"label": "Bratislava",
"description": "A Slovak number with the Bratislava area code +421 2. Billed three months upfront.",
"numbers": ["+421222205798"]
}
]
}Chybové stavy
- 400
validationregionmusí být jedno z id v nabídce (viz/cenik).
GET/v1/numbers/address-options
Adresy pro objednávku čísla z kraje, který není v nabídce. Kaskáda číselníku operátora: pošli psc a dostaneš obce, přidej obec a dostaneš části obce, cobce vrátí ulice a ulice čísla popisná. Jakmile je vybrané cp, přijde v poli recap čitelná adresa. Kódy si nevymýšlej - platí jen ty odsud. Rychlejší cesta bez kaskády je query, viz callout níž.
Požadavek
curl "https://volai.cz/v1/numbers/address-options?psc=70200&obec=554821&cobce=413950" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"obce": [{ "value": "554821", "label": "Ostrava" }],
"casti": [{ "value": "413950", "label": "Moravská Ostrava" }],
"ulice": [{ "value": "353710", "label": "28. října" }],
"cp": [],
"recap": null
}Chybové stavy
- 400
validationquery je delší než 200 znaků, neobsahuje PSČ, nebo operátor pro rozpoznanou úroveň nenabízí žádnou odpovídající volbu. - 502
provisioning_failedAdresy se od operátora nepodařilo načíst vůbec. - 503
orders_disabledObjednávky jsou dočasně pozastavené.
Rychlejší cesta: celá adresa jedním dotazem (query)
Místo kaskády pošli query s celou adresou (např. "Nádražní 100, 702 00 Ostrava") - server ji za tebe odjede celou. Z textu se čte napřímo jen PSČ, zbytek se pouze porovnává s nabídkami, které pro danou úroveň vrátil operátor - kódy si server nikdy nevymýšlí.
curl -G https://volai.cz/v1/numbers/address-options \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
--data-urlencode "query=Nádražní 100, 702 00 Ostrava"{
"obce": [],
"casti": [],
"ulice": [],
"cp": [],
"recap": "28. října 102/1, Ostrava, 70200",
"selection": {
"psc": "70200",
"obec": "554821",
"cobce": "413950",
"ulice": "353710",
"cp": "3180026"
}
}Když je adresa nejednoznačná, vrátí se jen ta úroveň, kde se to pozná (ambiguousLevel: obec/cobce/ulice/cp) s nabídkou k výběru v příslušném poli, například:
{
"obce": [
{ "value": "554821", "label": "Ostrava" },
{ "value": "554813", "label": "Fulnek" }
],
"casti": [],
"ulice": [],
"cp": [],
"recap": null,
"selection": { "psc": "70200", "obec": "", "cobce": "", "ulice": "", "cp": "" },
"ambiguousLevel": "obec",
"message": "The given address is ambiguous - choose the municipality (obec) from the options. Repeat the query WITHOUT query and with the step parameters: psc=70200, obec=<value from the options>."
}selection vždy nese, co se rozpoznalo předtím - pokračuje se stejným krokovým parametrem (psc/obec/cobce/ulice/cp), jaký by se použil bez query. Nejde-li adresu rozpoznat vůbec, nebo dojde-li časový rozpočet uprostřed zjišťování, přijde místo recap srozumitelná zpráva v poli message a poctivě rozpracovaný selection - odtud pokračuj krokovými parametry dál.
query a krokové parametry se NEKOMBINUJÍ v jednom požadavku - pošleš-li obojí najednou, endpoint vrátí validation. Po nejednoznačné odpovědi tedy nezopakuj stejné query s přidaným obec (nebo jinou úrovní) z nabídky - další dotaz pošli BEZ query, jen krokovými parametry. Přesný tvar (i s hodnotami, které se už rozpoznaly) je vypsaný přímo v poli message té nejednoznačné odpovědi.
POST/v1/numbers/orders
Objedná číslo z kraje mimo nabídku (Ostrava, Plzeň, Budějovice...). Kódy adresy musí přijít z GET /v1/numbers/address-options. Endpoint počká, než u operátora založíme tísňovou adresu provozovny a koupíme číslo - obvykle do minuty; hotové číslo pak vrátí v poli e164 se stavem done. Když se to napoprvé nepovede, vrátí objednávku ve stavu pending a dokončí ji cron. Poplatek 25,00 Kč se strhne až s hotovým číslem.
Požadavek
curl -X POST https://volai.cz/v1/numbers/orders \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"psc":"70200","obec":"554821","cobce":"413950","ulice":"353710","cp":"3180026"}'Odpověď
{
"order": {
"id": "Xa3Kd9pQmR2v",
"status": "pending",
"address": "70200",
"createdAt": 1756111640000,
"updatedAt": 1756111640000
}
}Chybové stavy
- 400
validationTělo požadavku nesedí na schéma - psc/obec/cobce/cp chybí nebo je prázdné, nebo pole přesahuje svůj limit délky (ulice je nepovinná). - 400
incomplete_addressChybí psc, obec, cobce nebo cp (ulice je nepovinná - ne každá adresa ji má). - 402
insufficient_creditKredit nepokryje měsíční poplatek 25,00 Kč. Účet, který ještě nikdy nedobil kredit, smí z uvítacího kreditu držet jedno číslo (počítá se i rozpracovaná objednávka); další jde objednat až po prvním dobití. Nic neúčtujeme. - 503
orders_disabledObjednávky jsou dočasně pozastavené. - 409
idempotency_conflictStejný Idempotency-Key už byl použit pro jinou adresu objednávky.
GET/v1/numbers/orders
Stav objednávek: pending (ve frontě), provisioning (právě pořizujeme), done (číslo je v poli e164 a patří účtu), failed (důvod v poli error, nic se neúčtovalo), cancelled (zrušená zákazníkem, dokud čekala ve frontě - nic se neúčtovalo).
Požadavek
curl https://volai.cz/v1/numbers/orders \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"orders": [
{
"id": "Xa3Kd9pQmR2v",
"status": "done",
"address": "28. října 102/1, Ostrava, 70200",
"e164": "+420596123456",
"createdAt": 1756111640000,
"updatedAt": 1756118840000
}
]
}POST/v1/numbers/orders/{id}/cancel
Zruší objednávku, která ještě čeká ve frontě (pending) - bez těla, vrátí ji se stavem cancelled. Nic se neúčtuje (poplatek jde až s hotovým číslem) a účet bez prvního dobití tak může objednat znovu. Objednávku, kterou právě pořizujeme (provisioning), zrušit nejde - vrátí 409 in_progress, zkus to za pár minut; hotovou (done) ani neúspěšnou (failed) také ne (409 invalid_transition) - hotové číslo uvolníš přes DELETE /v1/numbers/{e164}. Opakované zrušení už zrušené objednávky je neškodné (vrátí ji beze změny).
Požadavek
curl -X POST https://volai.cz/v1/numbers/orders/Xa3Kd9pQmR2v/cancel \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"order": {
"id": "Xa3Kd9pQmR2v",
"status": "cancelled",
"address": "28. října 102/1, Ostrava, 70200",
"createdAt": 1756111640000,
"updatedAt": 1756112240000
}
}Chybové stavy
- 404
not_foundObjednávka neexistuje nebo nepatří tvému účtu. - 409
in_progressObjednávku právě pořizujeme (provisioning, nebo si ji zrovna bere cron) - zrušit půjde až hotové číslo uvolnit. Zkus to za pár minut. - 409
invalid_transitionObjednávka je hotová (done- číslo uvolni přesDELETE /v1/numbers/{e164}), nebo už skončila neúspěchem (failed- není co rušit).
DELETE/v1/numbers/{e164}
Uvolní číslo zpátky do zásoby - odpojí směrování i registraci u agenta. Zaplacený měsíc se nevrací.
Požadavek
curl -X DELETE "https://volai.cz/v1/numbers/+420601234567" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"released": true
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu. - 502
release_failedOdpojení směrování v síti se nepodařilo bezpečně potvrdit, číslo se do zásoby nevrací. Zkus to prosím znovu za chvíli, nebo napiš podpoře.
PATCH/v1/numbers/{e164}
Změní směrování čísla.
mode: "agent"+agentId- hovory bere hlasový agent.mode: "forward"+forwardTo(E.164) - přesměrování, platíš obě nohy.mode: "sip"+sipUri- směruje na tvůj SIP server (viz SIP) - nepovinně i s přihlášením přes sipUsername a sipPassword, když to cílová ústředna vyžaduje. Vynechané pole (v těle PATCH úplně chybí) se ponechá tak, jak je uložené - u obou polí stejně, takže třeba změna samotného sipUri nevyžaduje znovu poslat uložené jméno ani heslo. Výjimka: když v sipUri měníš i server (část za zavináčem), musíš heslo poslat znovu - uložené heslo nepošleme na jiný server, než pro který jsi ho zadal. Zrušit autentizaci jde jen výslovně - pošli sipUsername i sipPassword jako prázdné řetězce. Odpověď navíc vždy nese hasSipPassword (nepovinné, jen pro čtení) - true znamená, že je k číslu uložené SIP heslo; samotné sipPassword se přes API nikdy nevrací.mode: "none"- hovory na číslo se nikam nesměrují a síť je odmítne.
sipTarget v routing je nepovinné informativní pole, které nastavuje volai - klient ho nikdy neposílá. Hodnota "engine" znamená, že číslo obsluhuje agent na vlastním motoru volai. Jakákoli jiná hodnota nebo chybějící pole znamená, že na motoru NENÍ (typicky agent na ElevenLabs) - chybějící pole samo o sobě neber jako jistý důkaz ElevenLabs, jediný spolehlivý signál je hodnota "engine".
Požadavek
curl -X PATCH "https://volai.cz/v1/numbers/+420601234567" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"routing": {"mode": "agent", "agentId": "ag_kx91fa2b"}}'Odpověď
{
"number": {
"e164": "+420601234567",
"routing": { "mode": "agent", "agentId": "ag_kx91fa2b", "hasSipPassword": false, "sipTarget": "engine" },
"monthlyFeeHal": 2500,
"boughtAt": 1756111640000,
"region": "objednavka",
"regionLabel": "Czech number",
"billingMonths": 1
}
}Chybové stavy
- 400
validationrouting.mode vyžaduje odpovídající pole (agentId / forwardTo / sipUri). U routing.mode: "sip" navíc platí pro sipUsername a sipPassword: vyplň buď obě, nebo žádné, bez dvojtečky, zavináče, mezery, uvozovky a zpětného lomítka a nejvýš 64 znaků každé. Když jsou vyplněné oba přihlašovací údaje, navíc nesmí volané číslo v sipUri (část před zavináčem) obsahovat dvojtečku a server v sipUri (za zavináčem) nesmí mít port - s přihlašovacími údaji se to zatím nepodporuje. Stejný kód dostaneš i tehdy, když k číslu s uloženým heslem změníš server v sipUri a nepošleš sipPassword znovu. - 400
invalid_sip_urisipUri nemá tvar sip:uzivatel@server (volitelně s portem) - platí jen pro routing.mode: "sip". Stejný kód dostaneš i tehdy, když operátor zápis OVĚŘENÉHO směrování (s vyplněným sipUsername i sipPassword) definitivně odmítne, nebo po zápisu vrátí jiný cíl, než jsme poslali - opakování beze změny vstupu nepomůže. U směrování bez přihlašovacích údajů se stejná situace hlásí jako routing_failed. - 402
insufficient_creditÚčet ještě nikdy nedobil kredit a číslo zatím není přesměrované - přesměrování hovorů (routing.mode: "forward") jde zapnout až po prvním dobití, protože se účtuje zpětně z výpisu operátora a bez brzdy během hovoru. Agent, SIP i příchozí hovory fungují dál. Číslo, které už přesměrované je, jde přesměrovat na jiný cíl i bez dobití. Nic neúčtujeme. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu. - 502
routing_failedPožadované směrování se teď nepotvrdilo (přesměrování, SIP, odpojení, nebo potvrzení směrování na motor) - dočasný výpadek v síti, zkus to znovu za chvíli. - 502
engine_unavailableU routing.mode: "agent" s agentem na vlastním motoru volai: motor teď neodpovídá, přiřazení čísla se nepovedlo. Zkus to prosím znovu za chvíli, nebo napiš podpoře. - 502
engine_readback_mismatchU routing.mode: "agent" s agentem na vlastním motoru volai: motor odpověděl, ale při zpětném čtení se ukázalo jiné namapování, než jsme poslali. Zkus to znovu.
GET/v1/numbers/{e164}/sip
SIP údaje čísla - pro vlastní softphone/PBX i pro odchozí trunk hlasové platformy (ElevenLabs, Vapi...). Nastavení krok za krokem je na stránce SIP.
| Pole | Význam |
|---|---|
server | Doména pro REGISTER vlastního softphonu nebo PBX. Není pro odchozí trunk hlasové platformy - na to slouží outboundTrunkAddress. |
outboundTrunkAddress | Adresa odchozího SIP trunku tvé platformy (u ElevenLabs pole outbound_trunk_config.address). Zadej přesně tuhle hodnotu bez ohledu na to, jestli se shoduje se server - jiná adresa znamená, že se hovor v síti nesměruje a platforma ohlásí timeout. |
username / password | Přihlašovací údaje k lince - stejné pro REGISTER i pro trunk s digest autentizací. |
port / transport | Port a doporučený transport pro SIP signalizaci - TCP (velký INVITE s SDP se do UDP MTU nemusí vejít a platforma ho pak vůbec neodešle), UDP funguje také. |
inboundSignallingCidrs | Odkud přichází naše SIP signalizace k tvé ústředně nebo platformě - allowlist příchozího trunku (např. ElevenLabs allowed_addresses, Vapi gateways). |
server a outboundTrunkAddress nejsou zaměnitelné: server je určený pro REGISTER softphonu nebo ústředny, outboundTrunkAddress pro odchozí trunk platformy - do trunku patří vždycky hodnota z outboundTrunkAddress, ať už se se server shoduje, nebo ne; jiná adresa znamená, že se hovor v síti nesměruje a platforma ohlásí timeout (podrobně na stránce SIP a v návodu na vlastního agenta).
Požadavek
curl "https://volai.cz/v1/numbers/+420601234567/sip" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"server": "sip.volai.cz",
"username": "123456",
"password": "a1b2c3d4e5f6",
"outboundTrunkAddress": "sip.volai.cz",
"port": 5060,
"transport": "tcp",
"inboundSignallingCidrs": ["81.31.45.0/24"]
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu. - 502
sip_credentials_unavailableSIP heslo linky se nepodařilo dohledat. Zkus to za chvíli znovu, případně kontaktuj podporu.
GET/v1/numbers/{e164}/sip/status
Skutečný stav SIP registrace čísla ve směrování Vlastní SIP ústředna a poslední příchozí hovor na něj - na rozdíl od pole routing.mode jde o PRAVDIVĚ ověřený stav, ne odvozený z nastavení. registration je null, když číslo míří na CIZÍ ústřednu (sipa: cíl bez výzvy) - u ní se hodí jen lastInbound.
Požadavek
curl "https://volai.cz/v1/numbers/+420601234567/sip/status" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"target": { "kind": "own_line", "host": null },
"registration": { "registered": true },
"lastInbound": {
"at": 1756118900000,
"status": "completed",
"from": "+420777123456",
"recent": true
}
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundČíslo neexistuje nebo nepatří tvému účtu. - 400
not_sip_modeČíslo není ve směrování „Vlastní SIP ústředna“.
Zprávy
SMS přijímá jen doplněk SMS číslo
Hlasová čísla volai (pevná a VoIP) SMS nepřijímají. Příjem SMS a odesílání z vlastního čísla umí doplněk SMS číslo (sekce SMS čísla níž): české mobilní číslo jen pro SMS, bez hovorů. Přijaté zprávy přečteš v GET /v1/messages?direction=in, v MCP nástroji list_messages nebo ve webhooku message.received a uchováváme je 90 dní. Nad 300 přijatých zpráv za hodinu na jedno SMS číslo se webhook message.received pro další zprávy neposílá; zprávy se dál ukládají. Ověřovací kódy od služeb (banky, Google a podobně) nezaručujeme - číslo je určené pro psaní s lidmi. Zprávy odeslané bez fromNumber odcházejí pod sdíleným jménem SMSinfo, na které příjemce neodpoví a které nemá doručenky.
GET/v1/messages
Historie SMS, od nejnovější. Bez parametru direction jen odeslané zprávy, s direction=in jen zprávy přijaté na tvém SMS čísle a s direction=all obojí dohromady podle času vzniku. Přijatá zpráva má direction: "in", status: "received" a source: "inbound"; from je odesílatel (telefonní číslo, nebo textové jméno) a to je tvoje SMS číslo. Výpis přijatých zpráv drží nejvýš 1 000 nejnovějších zpráv na účet, takže starší z něj zmizí i dřív než za 90 dní.
Požadavek
curl "https://volai.cz/v1/messages?limit=20&direction=all" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"messages": [
{
"id": "msg_7c1f9a2e",
"to": "+420777123456",
"from": "volai",
"body": "Ahoj z volai! - Moje Appka",
"status": "sent",
"failReason": null,
"priceHal": 136,
"segments": 1,
"createdAt": 1756111500000,
"source": "api",
"direction": "out",
"smsNumber": null,
"deliveryStatus": null
},
{
"id": "msg_3d9b5e71",
"to": "+420770112233",
"from": "+420777123456",
"body": "Díky, přijdu v pátek v 10:00.",
"status": "received",
"failReason": null,
"priceHal": 0,
"segments": 1,
"createdAt": 1756111900000,
"source": "inbound",
"direction": "in",
"smsNumber": "+420770112233",
"deliveryStatus": null
}
],
"hasMore": false,
"nextBefore": null
}Chybové stavy
- 400
validationlimit musí být kladné celé číslo; before musí být kladné celé číslo (časové razítko v ms); direction musí býtout,inneboall.
POST/v1/messages
Odešle SMS. Jen česká a slovenská čísla (+420 / +421). Cena 1,36 Kč za segment - delší (nebo znaky mimo GSM-7 abecedu, typicky česká diakritika) zprávy se dělí na víc segmentů a platí se za každý zvlášť, viz segments v odpovědi. Jde až po prvním dobití kreditu - uvítací kredit SMS neodemkne.
Bez fromNumber odcházejí zprávy pod sdíleným jménem SMSinfo - operátoři pro české sítě povolují jen schválená jména, vlastní jméno odesílatele u sdíleného odesílatele nastavit nejde a příjemce na SMSinfo neodpoví. Pole from v odpovědi je u takové zprávy jen interní štítek volai, příjemce ho nevidí; u zprávy odeslané ze SMS čísla je v from to číslo. Svou identitu proto napiš přímo do textu zprávy, tak jako v příkladu níž.
Zprávu odešleš ze svého SMS čísla polem fromNumber (číslo z GET /v1/sms-numbers). Příjemce pak vidí tvoje číslo místo SMSinfo. Z čísla jde odeslat jen na česká čísla (+420), zpráva stojí 1,90 Kč za segment (bez DPH) a odesílání má denní strop na účet: 20 zpráv v prvních 30 dnech od koupě čísla, potom 50. Pole from v požadavku se dál ignoruje.
- Bez diakritiky (GSM-7 abeceda) se do jednoho segmentu vejde 160 znaků, delší text se dělí po 153.
- S diakritikou nebo jiným znakem mimo GSM-7 (UCS-2) je limit 70 znaků na segment, delší text se dělí po 67.
- Tip: chceš-li se vejít do jednoho segmentu, piš bez diakritiky -
Prilis zlutoucky kunmístoPříliš žluťoučký kůň.
Požadavek
curl -X POST "https://volai.cz/v1/messages" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: REPLACE_WITH_UNIQUE_POST_V1_MESSAGES_ID" \
-d '{"to":"+420777123456","body":"Ahoj z volai! - Moje Appka"}'Před spuštěním nahraď REPLACE_WITH_UNIQUE… jedinečným ID této akce, například UUID, a ulož si ho. Při opakování stejného požadavku po timeoutu použij stejné ID. Pro jinou akci nebo změněné tělo použij nové ID, i když voláš jiný endpoint.
Odpověď
{
"id": "msg_7c1f9a2e",
"status": "sent",
"priceHal": 136,
"segments": 1
}Chybové stavy
- 400
validationTělo požadavku nesedí na schéma - chybí to nebo body, nebo body přesahuje 2000 znaků. - 400
invalid_numberTo není platné české nebo slovenské telefonní číslo. - 400
invalid_bodyText zprávy musí mít 1 až 765 znaků. - 400
unsupported_countryČíslo mimo ČR/SR - v MVP nepodporujeme. - 400
recipient_cannot_receive_smsPevná linka - SMS by nedorazila. Nic neúčtujeme. - 400
unsupported_charactersText obsahuje emoji nebo jiný znak, který telefonní síť nedoručí. Nic neúčtujeme. - 400
recipient_is_virtual_numberPříjemce je číslo volai. Na hlasové číslo volai (i vlastní) SMS nedorazí vůbec, přijímá jen hovory. Na SMS číslo volai nedorazí SMS od sdíleného jména SMSinfo: pošli ji ze svého SMS čísla s polemfromNumber. Nic neúčtujeme. - 400
recipient_rejectedTelefonní síť tohle číslo nepřijímá - bývá to virtuální nebo neexistující číslo. Nic neúčtujeme. - 400
invalid_from_numberfromNumbernení aktivní SMS číslo tvého účtu. Zkontroluj ho vGET /v1/sms-numbers; číslo ve stavureleasingpoužít nejde. Nic neúčtujeme. - 400
from_number_unsupported_destinationZe SMS čísla jde odesílat jen na česká čísla (+420). Slovenské číslo pošli bezfromNumber, přes sdílené jméno SMSinfo. Nic neúčtujeme. - 402
insufficient_creditKredit nepokryje cenu všech segmentů zprávy, nebo účet ještě nikdy nedobil kredit - SMS ze sdíleného odesílatele SMSinfo jdou až po prvním dobití, uvítací kredit na ně použít nejde ani s vlastním číslem. Nic neúčtujeme. - 403
sms_numbers_unavailableOdesílání ze SMS čísla není pro tenhle účet teď k dispozici. Nic neúčtujeme; bezfromNumberjde zpráva odeslat přes SMSinfo. - 409
recipient_opted_outPříjemce poslal na tvoje SMS číslo STOP a další zprávy z něj nepřijímá, dokud nepošle START. Opakování nepomůže a nic neúčtujeme. - 429
rate_limitedVíc než 1 SMS za 2 vteřiny, nebo přes 100 SMS na účet dnes. Při odesílání ze SMS čísla (fromNumber) platí navíc denní strop na účet: 20 zpráv v prvních 30 dnech od koupě čísla, potom 50. - 502
send_failedTelefonní síť žádost odmítla. Kredit jsme nestrhli, zkus to prosím znovu. - 502
send_failed_operatorChyba na naší straně (odesílatel nebo kredit u operátora). Kredit jsme nestrhli, zkus to prosím za chvíli. - 502
sms_gateway_failedBrána operátora dočasně selhala. Kredit jsme nestrhli, zkus to za pár minut. - 502
send_unknownVýsledek odeslání se nepodařilo spolehlivě potvrdit; zpráva přesto mohla odejít - účtuje se, neposílej ji prosím znovu naslepo.
status zprávy: pending (uložená, ještě se odesílá), sent (operátor přijal zprávu k odeslání, případně do fronty; nejde o potvrzení doručení příjemci), failed (operátor odmítl, u zprávy ze SMS čísla případně až dodatečně - neúčtuje se, už stržený kredit se vrátí, priceHal 0), received (zpráva přijatá na tvé SMS číslo, vždy s direction: "in" a priceHal 0) a unknown (potvrzení o odeslání nedorazilo, typicky timeout na straně operátora) - přesto se účtuje plnou cenou, protože zpráva mohla dojít. Dostaneš-li unknown, zprávu prosím neposílej znovu naslepo - ozvi se podpoře, případný duplicitní kredit vrátíme.
U status: "failed" navíc dostaneš failReason: unsupported_characters (emoji nebo znak, který síť nedoručí), unsupported_recipient (síť číslo nepřijímá), forbidden_sender a low_balance (chyba na naší straně), gateway_failed (brána operátora), network_rejected (jiné odmítnutí), opted_out (příjemce poslal na tvoje SMS číslo STOP). U ostatních stavů je null.
deliveryStatus (delivered nebo undelivered) je doručenka operátora a vzniká jen u zpráv odeslaných z tvého SMS čísla. U zpráv přes sdílené jméno SMSinfo, které doručenky nemá, a u přijatých zpráv je null. Stav sent zůstává potvrzením přijetí operátorem a doručení nedokládá. Zpráva s undelivered se účtuje, protože ji operátor přijal. Když operátor dodatečně ohlásí selhání, změní se status zprávy na failed, priceHal klesne na 0 a kredit za ni se vrátí.
Příklad: zpráva s diakritikou nad 70 znaků = víc segmentů
Tahle zpráva má 112 znaků a obsahuje diakritiku, takže se počítá jako UCS-2 (limit 67 znaků na segment u vícedílné zprávy) - vyjde na 2 segmenty, tedy 2,72 Kč, ne 1,36 Kč:
curl -X POST https://volai.cz/v1/messages \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"to": "+420777123456", "body": "Příliš žluťoučký kůň úpěl ďábelské ódy - a tahle věta má přes sedmdesát znaků, takže spadne do druhého segmentu."}'{
"id": "msg_9a3f1c7d",
"status": "sent",
"priceHal": 272,
"segments": 2
}GET/v1/messages/{id}
Detail jedné zprávy.
Požadavek
curl https://volai.cz/v1/messages/msg_7c1f9a2e \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"message": {
"id": "msg_7c1f9a2e",
"to": "+420777123456",
"from": "volai",
"body": "Ahoj z volai! - Moje Appka",
"status": "sent",
"failReason": null,
"priceHal": 136,
"segments": 1,
"createdAt": 1756111500000,
"source": "api",
"direction": "out",
"smsNumber": null,
"deliveryStatus": null
}
}Chybové stavy
- 404
not_foundZpráva neexistuje nebo nepatří tvému účtu.
SMS čísla
GET/v1/sms-numbers
SMS čísla účtu (doplněk SMS číslo): česká mobilní čísla, na která přijímáš SMS a ze kterých je odesíláš. Každé nese status (active, nebo releasing, dokud uvolnění běží či čeká na zopakování), poplatek monthlyFeeHal za 30denní období a nextChargeAt, kdy je splatné další. Výpis funguje i tehdy, když nové koupě nejsou dostupné.
Požadavek
curl https://volai.cz/v1/sms-numbers \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"smsNumbers": [
{
"number": "+420770112233",
"status": "active",
"createdAt": 1756111640000,
"monthlyFeeHal": 39000,
"nextChargeAt": 1758703640000
}
]
}POST/v1/sms-numbers
Koupí účtu české mobilní SMS číslo. Tělo požadavku se neposílá, číslo vybereme my. Číslo přijímá SMS (přečteš je v GET /v1/messages?direction=in nebo událostí webhooku message.received) a zprávy z něj odešleš polem fromNumber v POST /v1/messages. Hovory nepřijímá ani nevolá. Z kreditu se hned strhne 390,00 Kč bez DPH za první 30denní období a pak znovu každých 30 dní; zaplacené období se při uvolnění nevrací. Účet může mít nejvýš dvě SMS čísla a koupě jde až po prvním dobití kreditu. Když se po koupi u operátora něco nepovede, číslo se zase uvolní a nic se neúčtuje. Když běží jiná koupě téhož účtu, dostaneš 429 rate_limited - počkej pár vteřin a zopakuj to. Doručení zpráv od každého odesílatele, včetně ověřovacích kódů, nezaručujeme.
Požadavek
curl -X POST https://volai.cz/v1/sms-numbers \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"smsNumber": {
"number": "+420770112233",
"status": "active",
"createdAt": 1756111640000,
"monthlyFeeHal": 39000,
"nextChargeAt": 1758703640000
}
}Chybové stavy
- 402
insufficient_creditKredit nepokryje poplatek 390,00 Kč za první období, nebo účet ještě nikdy nedobil kredit - SMS číslo jde koupit až po prvním dobití a uvítací kredit ho neodemkne. Nic neúčtujeme. - 403
sms_numbers_unavailableDoplněk SMS číslo teď pro tenhle účet není k dispozici. Nic neúčtujeme; kdybys přístup čekal, napiš na podpora@volai.cz. - 409
sms_number_limitÚčet už má nejvyšší povolený počet SMS čísel (dvě). Jedno uvolni přesDELETE /v1/sms-numbers/{e164}a pak kup další. Nic neúčtujeme. - 503
sms_number_out_of_stockOperátor teď nemá volné české mobilní číslo. Nic neúčtujeme, zkus to za chvíli znovu.
DELETE/v1/sms-numbers/{e164}
Uvolní SMS číslo: vrátí se operátorovi a znovu ho získat nejde, zprávy poslané na něj už k tobě nedorazí. Poplatek za běžící 30denní období se nevrací. Když uvolnění u operátora selže, číslo zůstane ve stavu releasing a stejným požadavkem ho uvolníš znovu.
Požadavek
curl -X DELETE "https://volai.cz/v1/sms-numbers/+420770112233" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"released": true
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo. - 404
not_foundSMS číslo neexistuje nebo nepatří tvému účtu. - 502
release_failedUvolnění se u operátora teď nepovedlo. Číslo zůstává tvoje ve stavureleasing, zopakuj stejný požadavek za chvíli. Zaplacené období se nevrací.
Hovory
GET/v1/calls
Historie hovorů, od nejnovějšího. direction (in nebo out) omezí výpis na jeden směr. Filtry from/to (Unix ms, startedAt v rozsahu, from <= to), agentId, flagged (true/false), goal (success/failure/unclear/no_conversation/not_evaluated, nebo zpětně kompatibilní unknown - záznamy bez jasného výsledku: goal.result chybí nebo je unknown (nejasné a bez hodnocení vždy, hovory bez rozhovoru jen s výsledkem unknown) - viz pole goal u hovoru), outcome (agent/transferred/no_answer/other, viz sloupec Účtování u tabulky kind níž). Neznámé parametry se ignorují. Hovor vs. konverzace: GET /v1/calls vrací jednotlivé ZÁZNAMY hovoru - každá noha telefonního spojení je vlastní řádek. Portálová tabulka /hovory seskupuje související nohy (příchozí noha na agenta plus odchozí noha přepojení) do jedné KONVERZACE - úspěšně přepojený hovor se proto v portálu ukáže jako jeden řádek, ale přes API/MCP až jako dva záznamy (noha, která přepojila, má outcome: "transferred"; přijímající noha si drží svůj vlastní outcome). Počítáš-li hovory z API, počítej s tím.
Požadavek
curl "https://volai.cz/v1/calls?limit=20" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"calls": [
{
"id": "c_8f2ac1d4",
"direction": "in",
"from": "+420777123456",
"to": "+420601234567",
"status": "completed",
"startedAt": 1756111400000,
"durationSecs": 47,
"priceHal": 236,
"agentId": "ag_kx91fa2b",
"note": null,
"flag": null,
"handledAt": null,
"rating": null,
"goal": null,
"hasConversation": true,
"source": "inbound",
"kind": "inbound",
"endReason": "completed",
"hasRecording": true,
"data": {
"jmeno": "Jana Nováková",
"pocet_kav": 2,
"spechalo": "bezna"
}
}
],
"hasMore": false,
"nextBefore": null
}Chybové stavy
- 400
validationlimit/before musí být kladné celé číslo, direction musí být „in“ nebo „out“; from musí být menší nebo rovno to, pošleš-li oba; agentId nesmí přesáhnout 64 znaků; flagged/goal/outcome mimo povolené hodnoty.
POST/v1/calls
Zahájí odchozí hovor na to. Pošli právě JEDNO z: agentId (vede ho tvůj hlasový agent podle svého systemPrompt), from (přímé spojení dvou čísel bez agenta - bridge, viz níž) nebo systemPrompt (zkušební hovor bez vlastního čísla - žádný nákup ani zakládání agenta předem, viz níž). Nikdy víc než jedno, nikdy žádné. U varianty agentId lze navíc poslat variables (vlastní hodnoty do promptu) a ringingTimeoutSecs (jak dlouho nechat vyzvánět, viz callout níž).
Požadavek
curl -X POST "https://volai.cz/v1/calls" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: REPLACE_WITH_UNIQUE_POST_V1_CALLS_ID" \
-d '{"to":"+420777123456","agentId":"ag_kx91fa2b","variables":{"jmeno_zakaznika":"Jana","cislo_objednavky":"A-42"},"ringingTimeoutSecs":30}'Před spuštěním nahraď REPLACE_WITH_UNIQUE… jedinečným ID této akce, například UUID, a ulož si ho. Při opakování stejného požadavku po timeoutu použij stejné ID. Pro jinou akci nebo změněné tělo použij nové ID, i když voláš jiný endpoint.
Odpověď
{
"id": "c_9d4e2b7f",
"status": "initiated"
}Chybové stavy
- 400
invalid_numberto není platné telefonní číslo. - 400
validationChybí, nebo je jich víc než jedno, z agentId/from/systemPrompt; u agentId variables mimo limit (max 20 klíčů, klíč 64 znaků, hodnota 512 znaků) nebo ringingTimeoutSecs mimo rozsah 5-60; u systemPrompt chybí/nad 1200 znaků, firstMessage nad 300 znaků, nebo ringingTimeoutSecs mimo rozsah 5-30. - 400
on_dncČíslo máš na seznamu nevolat (/v1/dnc). - 400
destination_auto_blockedDestinace je po opakovaných neúspěších automaticky blokovaná na 30 dní - blokaci jde zrušit v portálu (Nastavení) nebo přesPOST /v1/dnc/{e164}/unblock. - 400
cannot_call_own_numberOchrana proti smyčce - na vlastní volai číslo se volat nedá. - 400
cannot_call_volai_numberOchrana proti smyčce - cíl je volai číslo jiného účtu. - 404
bridge_needs_numberBridge (from) potřebuje aspoň jedno vlastní volai číslo na účtu. - 409
destination_busyNa stejné číslo ti právě běží jiný hovor. - 404
agent_not_foundagentId neexistuje nebo nepatří tvému účtu. - 404
agent_no_numberAgent nemá přiřazené telefonní číslo. - 403
agent_suspendedAgenta ručně pozastavil provozovatel volai - hovor přes něj teď nejde uskutečnit. Pozastavený celý účet vrací místo tohoaccount_suspended. - 402
insufficient_creditKredit nepokryje minimum pro zahájení hovoru. - 503
capacity_busyVšechny odchozí linky jsou právě obsazené, zkus to za minutu. - 503
trial_calls_disabledU systemPrompt: zkušební hovor je dočasně vypnutý provozním přepínačem - zavolej přes vlastního agenta (agentId). - 403
trial_email_unverifiedU systemPrompt: jen pro účty s ověřeným e-mailem. - 500
trial_not_configuredU systemPrompt: sdílený demo agent volai není správně nastavený - dočasná chyba na naší straně. - 502
call_rejectedU systemPrompt: hlasová platforma spojení hned odmítla, nic se neúčtovalo. - 429
rate_limitedLimit hovorů, nic se neúčtuje. S agentId: nejvýš 10 hovorů za minutu a 1000 za den na účet, nebo vyčerpaný limit odchozích minut vlastního hlasového motoru - pak odpověď neseRetry-After(za kolik vteřin to zkusit znovu). U systemPrompt: vyčerpaný denní limit 3 zkušebních hovorů na účet, nebo dočasně vytížený sdílený limit napříč všemi účty. - 502
callback_failedU bridge (from): telefonní operátor rovnou odmítl objednávku spojení, hovor se vůbec nesestavil. Kredit se nestrhl. - 502
engine_unavailableS agentId na agentovi vlastního hlasového motoru: motor teď neodpovídá (výpadek, ne limit) - zkus to za chvíli, a když to trvá, napiš na podporu s requestId z chyby. Když motor žádost přijal, ale jeho odpověď nedorazila včas, hovor mohl přesto vzniknout: v historii zůstane jakoinitiated, skutečný výsledek i cenu doplníme, a stejné číslo je asi 15 minut zamčené (destination_busy), ať mu nevoláš dvakrát. Vyčerpaný limit odchozích hovorů je naopak 429rate_limited.
Vlastní proměnné a doba vyzvánění
variables je objekt řetězec-řetězec, který agent dostane jako dynamické proměnné - v promptu se na ně odkážeš zápisem {{jmeno_zakaznika}}. Limity: nejvýš 20 klíčů, klíč do 64 znaků, hodnota do 512 znaků. Klíč smí obsahovat jen písmena, číslice a podtržítko a nesmí začínat číslicí ani předponou system__ nebo volai_ (obě jsou vyhrazené, požadavek s takovým klíčem odmítneme). Jména attempt_id, caller_number, called_number, trial_prompt a trial_first_message jsou rezervovaná - doplňujeme je sami a tvoje stejnojmenné hodnoty se zahodí.
ringingTimeoutSecs je 5 až 60 vteřin, výchozí 25. Po uplynutí se nevyzvednutý hovor ukončí a v detailu dostane endReason: "no_answer". Delší vyzvánění znamená vyšší šanci, že to zákazník zvedne, ale taky delší dobu blokovaného odchozího slotu.
Bez agenta: přímé spojení dvou čísel (bridge)
Místo agentId pošli from - vlastní číslo nebo jiné číslo zákazníka. volai nejdřív zavolá na from, a jakmile ho někdo zvedne, vytočí to. Obě nohy se účtují zvlášť po 0,92 Kč/min. Když operátor na objednávku neodpoví (výpadek sítě), vrátíme hovor jako zahájený (initiated): mohl proběhnout a jeho skutečný výsledek i cenu doplní synchronizace s operátorem. Neopakuj ho hned - stejné číslo zůstane asi 10 minut zamčené.
curl -X POST https://volai.cz/v1/calls \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"to": "+420777123456", "from": "+420601234567"}'Zkušební hovor bez vlastního čísla
Místo agentId/from pošli systemPrompt (instrukce pro agenta na tenhle jeden hovor, nejvýš 1200 znaků) a volitelně firstMessage (úvodní věta, nejvýš 300 znaků). Hovor jde ze sdíleného demo čísla volai, ne z tvého vlastního - odpověď proto nese navíc trial: true a from (demo číslo). voiceId u týhle varianty poslat nejde, jede na výchozím hlase. ringingTimeoutSecs má nižší strop 5 až 30 (výchozí 25) - drží se slot ze sdíleného fondu.
curl -X POST https://volai.cz/v1/calls \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{
"to": "+420777123456",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí a mluvíš stručně a přátelsky.",
"firstMessage": "Dobrý den, tady zkušební agent volai, jak vám mohu pomoct?"
}'{
"id": "c_2f7a91mn",
"status": "initiated",
"trial": true,
"from": "+420266266641"
}Jen pro účty s ověřeným e-mailem, nejvýš 3 hovory za 24 hodin na účet (plus sdílený strop napříč všemi účty, ať nával nezahltí demo číslo). Účtuje se úplně normálně vč. agentní přirážky - žádná sleva. Kdo potřebuje víc, koupí si vlastní číslo (POST /v1/numbers) a založí agenta (POST /v1/agents) - tam tenhle strop neplatí.
Kdyby byl zkušební hovor dočasně vypnutý (provozní přepínač), vrátí systemPrompt srozumitelnou chybu (trial_calls_disabled) místo hovoru; použij mezitím vlastního agenta (agentId).
GET/v1/calls/active
Načte všechny nakonfigurované uzly vlastního motoru pro jedno vlastní agentId. Jde o živý snímek, odlišný od historie hovorů. complete znamená platné odpovědi všech uzlů a úplné údaje o vlastnictví. outboundCount zahrnuje i nezmapované hovory; inboundCount počítá zpětná volání samostatně. Každý odchozí řádek má neprůhledné nativeRef, startedAt (Unix ms) a resolved. Pouze ověřené hovory úloh obsahují callId, taskId, itemId a phoneSha256. Chybějící vazba zůstává viditelná jako resolved: false. checkedAt je ISO čas dokončení snímku a enginesChecked počet uzlů. Nulu odchozích hovorů lze doložit jen při complete: true, outboundCount: 0 a unresolvedOutboundCount: 0; chyba ani neúplný snímek nulu nedokazují. Endpoint pokrývá pouze telefonní hovory vlastního motoru, nikoli webové relace nebo jiné poskytovatele. Platí stávající sdílený limit API klíče.
Požadavek
curl 'https://volai.cz/v1/calls/active?agentId=ag_example' -H 'Authorization: Bearer vk_TVUJ_KLIC'Odpověď
{
"data": {
"agentId": "ag_example",
"complete": true,
"checkedAt": "2026-10-09T17:59:00.000Z",
"enginesChecked": 2,
"outboundCount": 0,
"inboundCount": 0,
"unresolvedOutboundCount": 0,
"outbound": []
}
}Chybové stavy
- 400
validationOčekávané vazby nebo dotaz na agenta chybí, nejsou platné nebo už neodpovídají hovoru. - 404
agent_not_foundAgent neexistuje nebo patří jinému účtu. - 502
engine_unavailableNativní stav se nepodařilo ověřit; nelze předpokládat, že hovory skončily. - 503
engine_not_configuredPřipojení k vlastnímu motoru není nakonfigurované.
POST/v1/calls/{id}/hangup
Ukončí jeden vlastní odchozí hovor úlohy na vlastním motoru. Pošli všechny čtyři očekávané vazby: expectedAgentId, expectedTaskId, expectedItemId a expectedPhoneSha256 (SHA-256 přesného cílového čísla E.164 malými hexadecimálními znaky). Server před jediným nativním zavěšením ověří historii úlohy, kontext volání, místnost, účet, agenta, směr i čas zahájení. Trvalý záznam podle call ID zabrání opakovanému požadavku poskytovateli včetně souběhu a timeoutu; Idempotency-Key není potřeba. Výsledek má callId, outcome a endConfirmed: hung_up znamená potvrzení přesného hovoru motorem, already_ended vyžaduje konečný uložený stav i nepřítomnost na všech uzlech a unknown nikdy neznamená úspěch. Po nejasném výsledku zkontroluj živé hovory a uložený stav; opakované volání tohoto endpointu pouze ověřuje stav a další zavěšení neposílá. Po ukončení znovu načti aktivní hovory. Příchozí, cizí, samostatné hovory a jiní poskytovatelé jsou odmítnuti. Rozsah kampaně, povolený čas a uzávěrku hlídá řídicí proces; endpoint nemění účtování ani stav úlohy.
Požadavek
curl -X POST https://volai.cz/v1/calls/c_example/hangup -H 'Authorization: Bearer vk_TVUJ_KLIC' -H 'Content-Type: application/json' -d '{"expectedAgentId":"ag_example","expectedTaskId":"task_example","expectedItemId":"item_example","expectedPhoneSha256":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}'Odpověď
{
"data": {
"callId": "c_example",
"outcome": "hung_up",
"endConfirmed": true
}
}Chybové stavy
- 400
validationOčekávané vazby nebo dotaz na agenta chybí, nejsou platné nebo už neodpovídají hovoru. - 404
call_not_foundHovor neexistuje nebo nepatří tvému účtu. - 502
engine_unavailableNativní stav se nepodařilo ověřit; nelze předpokládat, že hovory skončily. - 503
engine_not_configuredPřipojení k vlastnímu motoru není nakonfigurované.
GET/v1/calls/{id}
Detail hovoru. Volitelně waitSecs (viz callout níž) nechá server počkat na výsledek místo pollování. U hovorů s agentem obsahuje navíc transcript (přepis po replikách, každá s nepovinným polem timeInCallSecs - vteřiny od začátku hovoru, chybí, pokud repliku poskytovatel časem neoznačil) a summary (krátké shrnutí) - viz Webhooky pro stejný tvar doručený automaticky po skončení hovoru. Ve výpisu i v detailu chodí navíc answeredBy (jen u ODCHOZÍCH hovorů: human, voicemail, ivr (zvedlo hlasové menu - automat; motor okamžitě zavěsí) nebo unknown, když motor nerozhodl nebo přepis chybí; u příchozích hovorů pole chybí, protože stručná odpověď volajícího není hlasová schránka). Motor rozhoduje hodnotami human, voicemail a ivr; unknown znamená, že se motor do konce detekčního okna nerozhodl, a od 1.33.0 zůstává unknown (dřív se místo něj bral odhad z přepisu, který krátkou odpověď jako „Ano.“ po dohraném úvodu považoval za záznamník). Odhad z přepisu (human nebo voicemail, unknown u prázdného přepisu; hlasové menu nepozná) platí jen u hovorů bez hodnoty z motoru. Odchozí hovory obsloužené vlastním hlasovým motorem volai k tomu nesou voicemailReason (phrase, long_monologue, beep, human_reply, ivr_phrase nebo digits - human_reply znamená, že hovor zvedl člověk tak krátkou odpovědí, že si toho detektor všiml (ne že jde o schránku), ivr_phrase je fráze hlasového menu, digits hláška operátora čtoucí volané číslo po jednotlivých číslicích), voicemailMessageLeft (motor přečetl nastavený vzkaz do schránky) a voicemailDetectedAtSecs (za kolik vteřin od zvednutí padlo rozhodnutí detektoru - i u hovoru, který zvedl člověk) - všechna tři pole dává jen motor, ElevenLabs klasifikace z přepisu (answeredBy bez explicitní hodnoty) důvod ani čas nezná. Odchozí hovor na motoru nese i optOutRequested: true, když si volaný v hovoru výslovně řekl, ať mu už nevoláme (třeba „už mi nevolejte“, i v posledních vteřinách po rozloučení) - číslo je pak automaticky v seznamu nevolat účtu (GET /v1/dnc) a politika opakování úlohy další pokus nenaplánuje; hovor bez takové repliky klíč nemá. Dál chodí endReason (completed, no_answer, busy, rejected, capacity, blocked, loop_guard, credit_blocked, suspended, engine_error, caller_loop, failed) a kind (agent, bridge, relay, inbound, transfer, sip) - viz tabulku níž. Vlna nástrojů a nahrávek přidala dvě další pole: data (co si agent z hovoru zapsal podle svých dataFields; hodnota null znamená, že to nezaznělo) a hasRecording (hovor má nahrávku ke stažení, viz endpoint níž). Starší hovory tahle pole nemají a v odpovědi chybí. durationSecs je ve vteřinách; u hovorů na vlastním motoru volai může jít o desetinné číslo (zaokrouhlené na dvě desetinná místa). Odpověď nese anotace majitele účtu, vždy přítomné, null když nenastavené: note (string), flag ({reason, flaggedAt} | null), handledAt (Unix ms nebo null) a goal ({result: "success"|"failure"|"unknown", rationale, reason} | null, vyplněné jen po vyhodnocení cíle agenta; reason je "no_caller_speech"|"evaluation_error"|null a říká, proč vyšel výsledek "unknown" - null u skutečně nejasného hodnocení) - viz PATCH /v1/calls/{id} níž. Odpověď dál vždy nese hasConversation (boolean | null) - jestli hovor vůbec měl rozhovor s volajícím; false u nespojeného hovoru, záznamníku nebo hlasového menu, null u staršího záznamu bez dost signálu k rozhodnutí. Hovor u agenta s fázemi (plán workflow uzlů) obsloužený vlastním hlasovým motorem volai (provider: "engine") navíc nese workflowPath - viz sekci Fáze hovoru (workflow) u agentů výš; hovor agenta na ElevenLabs pole nikdy nemá, i když fázemi prošel, protože ho zapisuje jen post-call motoru.
Požadavek
curl https://volai.cz/v1/calls/c_8f2ac1d4 \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"call": {
"id": "c_8f2ac1d4",
"direction": "in",
"from": "+420777123456",
"to": "+420601234567",
"status": "completed",
"startedAt": 1756111400000,
"durationSecs": 47,
"priceHal": 236,
"agentId": "ag_kx91fa2b",
"note": null,
"flag": null,
"handledAt": null,
"rating": null,
"goal": null,
"hasConversation": true,
"source": "inbound",
"kind": "inbound",
"endReason": "completed",
"hasRecording": true,
"data": {
"jmeno": "Jana Nováková",
"pocet_kav": 2,
"spechalo": "bezna"
},
"transcript": [
{ "role": "agent", "message": "Dobrý den, tady recepce kavárny Nula, jak vám mohu pomoct?", "timeInCallSecs": 0 },
{ "role": "caller", "message": "Chtěl bych si objednat dva latte s sebou.", "timeInCallSecs": 4 },
{ "role": "agent", "message": "Jasně, dva latte na vyzvednutí, bude to za patnáct minut.", "timeInCallSecs": 9 }
],
"summary": "Zákazník si objednal dva latte s sebou, vyzvednutí za 15 minut."
}
}Chybové stavy
- 404
call_not_foundHovor neexistuje nebo nepatří tvému účtu. - 400
validationwaitSecs není celé číslo 0 až 45.
Čekat na výsledek místo pollování (waitSecs)
Hned po POST /v1/calls zavolej GET /v1/calls/{id} s waitSecs (0 až 45, výchozí 0) - server odpoví, až hovor dojde do koncového stavu (completed/failed/missed/no_answer) a vrátí i transcript a summary rovnou, nebo po uplynutí waitSecs, podle toho, co nastane dřív.
curl -X GET "https://volai.cz/v1/calls/c_9d4e2b7f?waitSecs=30" \
-H "Authorization: Bearer vk_TVUJ_KLIC"{
"call": {
"id": "c_9d4e2b7f",
"direction": "out",
"from": "+420601234567",
"to": "+420777123456",
"status": "completed",
"startedAt": 1756111400000,
"durationSecs": 47,
"priceHal": 269,
"agentId": "ag_kx91fa2b",
"note": null,
"flag": null,
"handledAt": null,
"rating": null,
"goal": null,
"hasConversation": true,
"source": "api",
"kind": "agent",
"endReason": "completed",
"hasRecording": true,
"answeredBy": "human"
}
}Vypršel-li čas dřív, než hovor skončil, stillRunning je true a pole nesou aktuální (ne)koncový stav - nikdy to nechybuje. Zkus GET (nebo MCP get_call) znovu, klidně s vyšším waitSecs.
{
"call": {
"id": "c_9d4e2b7f",
"direction": "out",
"from": "+420601234567",
"to": "+420777123456",
"status": "ringing",
"startedAt": 1756111400000,
"agentId": "ag_kx91fa2b",
"note": null,
"flag": null,
"handledAt": null,
"rating": null,
"goal": null,
"hasConversation": null,
"source": "api"
},
"stillRunning": true
}GET/v1/calls/{id}/recording
Nahrávka hovoru. Na rozdíl od zbytku API tahle odpověď není JSON - formát těla určuje hlavička content-type skutečné odpovědi (přípona v content-disposition jí odpovídá): u agenta na ElevenLabs audio/mpeg (MP3, 128 kbps, 16 kHz mono), u agenta na vlastním motoru volai dnes audio/ogg. Formát se nikdy nepřevádí - řiď se touhle hlavičkou, ne pevně předpokládaným typem. Nahrávku ti nekopírujeme k sobě: proud jde z hlasové platformy rovnou skrz nás, my jen ověříme, že hovor patří tvému účtu.
?stahnout=1 přepne content-disposition na attachment (prohlížeč soubor uloží místo přehrání) - přípona souboru v ní (.mp3 / .ogg, jinak .bin) vždy odpovídá skutečnému content-type výš. Rozsahy (Range) tahle routa nenabízí - je pro strojovou integraci, která si stáhne celý soubor. Nahrávají se jen hovory agenta, který má recordCalls zapnuté, a držíme je 90 dní od hovoru.
Požadavek
curl https://volai.cz/v1/calls/c_8f2ac1d4/recording \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-OJChybové stavy
- 404
call_not_foundHovor neexistuje nebo nepatří tvému účtu. - 404
no_recordingHovor nahrávku nemá - nevedl ho agent, nebo mělo nahrávání vypnuté. - 410
recording_expiredNahrávka byla, ale uplynulo 90 dní a je smazaná. Přepis hovoru zůstává.
PATCH/v1/calls/{id}
Anotace hovoru, kterou si k němu majitel účtu vede sám - poznámka, nahlášení chyby agenta s důvodem a ruční „vyřízeno“. Aspoň jedno ze tří polí musí být přítomné. note (string nebo null, max 2000 znaků) - null poznámku smaže. flag ({reason} max 500 znaků, nebo null) - nastavení nahlášení SMAŽE handledAt (nahlášený hovor přestává být „vyřízený“), flag: null nahlášení zruší beze změny handled. handled (boolean) - true nastaví handledAt na teď, false ho vrátí na null. flag (ne-null) a handled: true v JEDNOM požadavku nejdou dohromady (400 validation) - nahlášení a potvrzené vyřízení se navzájem vylučují, pošli je ve dvou voláních.
Požadavek
curl -X PATCH https://volai.cz/v1/calls/c_8f2ac1d4 \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"note": "Volal kvůli reklamaci, přeposlat na podporu.", "flag": {"reason": "Agent nerozuměl dotazu na fakturu."}}'Odpověď
{
"call": {
"id": "c_8f2ac1d4",
"direction": "in",
"from": "+420777123456",
"to": "+420601234567",
"status": "completed",
"startedAt": 1756111400000,
"durationSecs": 47,
"priceHal": 236,
"agentId": "ag_kx91fa2b",
"source": "inbound",
"kind": "inbound",
"endReason": "completed",
"hasRecording": true,
"data": { "jmeno": "Jana Nováková" },
"note": "Volal kvůli reklamaci, přeposlat na podporu.",
"flag": { "reason": "Agent nerozuměl dotazu na fakturu.", "flaggedAt": 1756111460000 },
"handledAt": null,
"rating": null,
"goal": { "result": "failure", "rationale": "Zákazník si objednal dva latte s sebou, vyzvednutí za 15 minut.", "reason": null },
"hasConversation": true
}
}Chybové stavy
- 400
validationŽádné znote/flag/handledv těle není přítomné,notepřesahuje 2000 znaků,flag.reasonchybí nebo přesahuje 500 znaků, nebo tělo obsahujeflag(ne-null) společně shandled: true. - 404
call_not_foundHovor neexistuje nebo nepatří tvému účtu.
Stav hovoru: pole status
status je jediné pole, které se u hovoru mění v čase. Prvních pět minut po zahájení se ještě může posunout, pak už je konečné - čtyři z těch stavů jsou koncové.
| status | Význam |
|---|---|
initiated | Hovor je objednaný, ještě nezačal zvonit. |
ringing | Zvoní u volaného. |
in_progress | Hovor běží. |
completed | Koncový. Spojený a ukončený hovor - u drtivé většiny čekej durationSecs > 0 (výjimka: hovor s endReason: credit_blocked nebo suspended níže má i délku i cenu 0). Cenu 0 má i hovor s endReason: caller_loop (automat na druhém konci, do pěti minut), ten ale délku má. |
no_answer | Koncový. Odchozí hovor zvonil, volaný ho nezvedl. |
missed | Koncový. Příchozí hovor zůstal bez odezvy. |
failed | Koncový. Obvykle hovor se vůbec nespojil - platforma ho odmítla nebo selhala síť. Výjimka (karta K6, audit R02): endReason: engine_error znamená, že se hovor SPOJIL, ale skončil technickou chybou na naší straně - nese transcript a zpravidla i nahrávku (když ji motor stihl uložit) a nikdy se neúčtuje. Důvod vždy upřesňuje endReason. |
Druh hovoru: pole kind
kind říká, kudy hovor vznikl - a tím i jak se účtuje. Je to jediné pole, podle kterého ve faktuře odlišíš hovor vlastního (BYO) agenta od hovoru zabudovaného, protože u relaye se neplatí agentní přirážka.
| kind | Co to je | Účtování |
|---|---|---|
agent | Odchozí hovor zabudovaného hlasového agenta. | 0,92 Kč/min + 2,50 Kč/min |
bridge | Přímé spojení dvou čísel bez agenta. | 0,92 Kč/min za každou ze dvou nohou |
relay | Odchozí hovor tvého vlastního agenta přes POST /v1/relay. | 0,92 Kč/min, bez agentní přirážky |
inbound | Příchozí hovor na tvoje číslo. | 0,50 Kč/min (+ agent, pokud ho vedl) |
transfer | Druhá noha, která vznikla přepojením příchozího hovoru na člověka. Agent po přepojení z hovoru odchází, takže se tahle noha účtuje jako běžný odchozí hovor. | 0,92 Kč/min, bez agentní přirážky |
sip | Hovor vytočený přímo ze zaregistrovaného SIP klienta (softphone, vlastní ústředna) k tvé lince, mimo naše API - doúčtovaný zpětně ze záznamů sítě. | 0,92 Kč/min, bez agentní přirážky |
Proč hovor skončil: pole endReason
endReason doplňujeme u všech uzavřených hovorů. Pozor: hovor zablokovaný kvůli dluhu nebo ručnímu pozastavení provozovatelem má status completed, ale endReason je credit_blocked, resp. suspended, a cena 0 - podle samotného status ho od proběhlého hovoru nepoznáš. Totéž platí pro hovor, na jehož druhém konci byl automat opakující pořád tutéž hlášku (caller_loop): má status completed, ale pokud trval nejvýš pět minut, je jeho cena 0. Tři varianty „nevyzvednuto“ jsou schválně rozlišené, ne jeden společný stav.
| endReason | Význam |
|---|---|
completed | Hovor proběhl a byl regulérně ukončen. |
no_answer | Zvonilo, volaný to nezvedl. |
busy | Obsazovací tón - to NENÍ totéž co nezvednutí. |
rejected | Platforma spojení rovnou odmítla. |
capacity | Odchozí linky (relay pool) byly plné. |
blocked | Cíl je na seznamu nevolat nebo v automatické 30denní blokaci (viz Seznam nevolat níž). |
loop_guard | Ochrana proti volání na vlastní/cizí volai číslo. |
credit_blocked | Příchozí hovor na agenta, jehož majitel je v dluhu nad limit - agent hned po úvodní větě zavěsí, cena 0. |
suspended | Příchozí hovor na agenta, kterého (nebo jehož celý účet) ručně pozastavil provozovatel volai - agent hned po úvodní větě zavěsí, cena 0. |
failed | Hovor se vůbec nespojil (platforma nebo síť). |
engine_error | Hovor se spojil, ale skončil technickou chybou hlasového motoru na naší straně - ne vinou volaného. Neúčtuje se. |
caller_loop | Příchozí hovor, kde volající byl automat opakující pořád tutéž hlášku (fronta, vytáčecí systém) - volai ho po krátkém čekání na člověka ukončí. Hovor má status completed a kladnou délku, ale do pěti minut se neúčtuje (cena 0); delší hovor se účtuje jako každý jiný. |
Agenti
GET/v1/agents
Seznam hlasových agentů na účtu.
Požadavek
curl https://volai.cz/v1/agents \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"agents": [
{
"id": "ag_pw7q2vnd",
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, tady recepce kavárny Nula, jak vám mohu pomoct?",
"voiceId": "7JbZPqJGWUfXXBim0T8U",
"provider": "elevenlabs",
"createdAt": 1756111000000,
"status": "active",
"toolIds": ["tl_5c2a91f4"],
"dataFields": [
{
"key": "jmeno",
"type": "string",
"description": "Jméno volajícího, které sám řekl."
}
],
"recordCalls": true,
"goal": null,
"knowledge": null,
"notifyEmail": true,
"silencePromptSecs": 10,
"laughter": "auto",
"missedCallSms": { "enabled": false },
"suspended": false
},
{
"id": "ag_kx91fa2b",
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, tady recepce kavárny Nula, jak vám mohu pomoct?",
"voiceId": "milena",
"provider": "engine",
"numberE164": "+420601234567",
"createdAt": 1756111000000,
"status": "active",
"toolIds": ["tl_5c2a91f4"],
"transferTo": "+420777123456",
"transferCondition": "Volající výslovně žádá spojení s člověkem.",
"dataFields": [
{
"key": "jmeno",
"type": "string",
"description": "Jméno volajícího, které sám řekl."
},
{
"key": "spechalo",
"type": "string",
"description": "Jak moc věc spěchala.",
"enumValues": ["nizka","bezna","vysoka"]
}
],
"recordCalls": true,
"goal": null,
"knowledge": null,
"notifyEmail": true,
"silencePromptSecs": 10,
"laughter": "auto",
"missedCallSms": { "enabled": false },
"suspended": false
}
]
}POST/v1/agents
Vytvoří nového hlasového agenta. Povinný je jen name a systemPrompt - jak takový prompt napsat dobře je na stránce Hlasový agent . Když pošleš numberE164, agent se na číslo rovnou napojí. POST vrací jen id; následným GET /v1/agents/{id} přečti skutečné provider. transferTo po uložení spustí pokus převést agenta z ElevenLabs na motor, ale při pozastavení, nedostupnosti nebo chybě může zůstat na ElevenLabs, kde přepojení nefunguje. Hlas vybere voiceId: explicitní useForOutboundTasks: true nahradí známý hlas nepodporovaný motorem, včetně katty, výchozím hlasem motoru. Mimo tuto výjimku přijme motor hlasy katalogu kromě hlasů ElevenLabs (katty, starší anet); syrové ElevenLabs ID nebo jiný nekompatibilní hlas vrátí 400. Při false musí prvotní hlas patřit ElevenLabs (katty nebo syrové ElevenLabs ID; anet už ElevenLabs novým agentům nepřiděluje a volai ho odmítne chybou 400) a úspěšný převod kvůli transferTo ho může změnit na výchozí hlas motoru. Bez voiceId agent použije u motoru Milenu a u ElevenLabs hlas šablony (Katty). Volitelná pole (toolIds, transferTo, transferCondition, dataFields, recordCalls, goal, knowledge, notifyEmail, useForOutboundTasks, voicemail) popisuje tabulka pod endpointy.
Požadavek
curl -X POST "https://volai.cz/v1/agents" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: REPLACE_WITH_UNIQUE_POST_V1_AGENTS_ID" \
-d '{"name":"Recepční","systemPrompt":"Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí a odpovídáš na otázky o otevírací době. Nikdy nevymýšlej ceny, které neznáš. Hovor ukonči shrnutím objednávky.","firstMessage":"Dobrý den, tady recepce kavárny Nula, jak vám mohu pomoct?","language":"cs","numberE164":"+420601234567","toolIds":["tl_5c2a91f4"],"transferTo":"+420777123456","transferCondition":"Volající chce mluvit s obsluhou, nebo řeší reklamaci.","dataFields":[{"key":"jmeno","type":"string","description":"Jméno volajícího, které sám řekl."},{"key":"pocet_kav","type":"number","description":"Kolik káv si volající objednal."}],"recordCalls":true}'Před spuštěním nahraď REPLACE_WITH_UNIQUE… jedinečným ID této akce, například UUID, a ulož si ho. Při opakování stejného požadavku po timeoutu použij stejné ID. Pro jinou akci nebo změněné tělo použij nové ID, i když voláš jiný endpoint.
Odpověď
{
"id": "ag_kx91fa2b"
}Chybové stavy
- 400
invalid_nameJméno agenta musí mít 1 až 60 znaků. - 400
invalid_system_promptInstrukce agenta musí mít 10 až 6000 znaků. - 400
invalid_languagelanguage musí být cs, sk, en, de nebo pl. - 400
agent_limitNa účtu už je maximální počet agentů (10). - 400
tool_limitV toolIds je víc než 10 nástrojů. - 400
invalid_data_fieldsdataFields mají neplatný klíč, typ, popis nebo je jich víc než 10. - 400
invalid_goalgoal je moc dlouhý - vejde se do 300 znaků. - 400
invalid_knowledgeknowledge je moc dlouhý - vejde se do 20000 znaků. - 400
transfer_looptransferTo míří na volai číslo téhož účtu - hovor by se vracel sám na sebe. - 400
blocked_destinationtransferTo je prémiová linka se zvláštním tarifem. - 400
invalid_numbertransferTo není platné telefonní číslo. - 400
invalid_voicemail_messagemessage ve voicemail chybí nebo je moc dlouhá - povinná při action "message", vejde se do 400 znaků. - 400
voicemail_requires_enginevoicemail vyžaduje prvotní volbu motoru: useForOutboundTasks: true nebo vynechané pole s motorem jako výchozím. false chybu vrátí i s transferTo, protože validace předchází pokusu o přepnutí. - 400
invalid_workflowNeplatný graf workflow (nedosažitelný uzel, chybějící vstupní uzel, rezervované jméno nástroje...); nic se neuloží, konkrétní důvod je vždy v message. - 404
calendar_integration_not_foundcalendar.integrationId neukazuje na kalendářové připojení tvého účtu - vyber ho znovu z GET /v1/integrations. - 400
calendar_invalid_calendarcalendar.calendarId není mezi kalendáři toho připojení, nebo je jen ke čtení (accessRole reader nebo freeBusyReader) - agent do něj schůzku nezapíše. Vyber kalendář s právem zápisu z list_calendars. - 400
calendar_invalid_timezonecalendar.timezone není platná IANA zóna, například "Europe/Prague". - 400
calendar_invalid_windowsOkna v calendar.windows nemají tvar HH:MM, překrývají se, nebo je jich na jeden den víc než čtyři. - 400
calendar_no_windowsKalendář je zapnutý, ale žádný den nemá okno - agent by neměl co nabídnout. - 400
calendar_invalid_rulesČíselná pravidla kalendáře jsou mimo meze, nebo je minimální předstih delší než horizont hledání. - 404
tool_not_foundNástroj z toolIds neexistuje nebo nepatří tvému účtu. - 404
not_foundnumberE164 neexistuje nebo nepatří tvému účtu. - 400
validationTvar vstupu nesedí - typicky voiceId, které neodpovídá žádné položce z GET /v1/voices ani nevypadá jako syrové ElevenLabs ID (chyba vyjmenuje platné hodnoty), nebo silencePromptSecs mimo meze 3 až 25. - 500
agent_template_missingŠablona pro založení agenta na naší straně chybí nebo je poškozená - dočasná chyba na naší straně, napiš prosím podpoře. - 503
engine_not_configuredVyžádal sis vlastní hlasový motor volai (useForOutboundTasks: true), ale motor nebo odchozí provoz na motoru teď nejsou nakonfigurované. Zkontroluj konfiguraci, nebo pole vynech - agent vznikne na ElevenLabs. - 503
engine_setup_incompleteAgent vznikl, ale příprava odchozích úkolů na vlastním motoru volai se nepovedla. Vytváření NEOPAKUJ - vznikl by duplicitní agent. Dohledej ho vGET /v1/agentspodle jména, zkontroluj jehoprovidera dokonči ho v portálu Agenti nebo s podporou; samotnýPATCH /v1/agents/{id}neumí poskytovatele zvolit.
GET/v1/agents/{id}
Detail jednoho agenta - stejná pole jako ve výpisu, jen pro jednoho. Smazaný agent se chová, jako by neexistoval: 404 agent_not_found. Při zakládání určuje prvotní platformu useForOutboundTasks: true zvolí vlastní motor, false ElevenLabs a vynechané pole použije výchozí nastavení nasazení. Protože POST vrací jen id, výsledek ověř tímto následným GET v poli provider. transferTo u agenta na ElevenLabs spustí pokus o převod na motor, který může být pozastavený, nedostupný nebo selhat; dokud provider zůstává elevenlabs, přepojení nefunguje. Při úspěchu se může změnit hlas. Změna language přes PATCH z jazyka, ve kterém noví agenti vznikají na ElevenLabs (dnes en, de, pl), na jazyk, ve kterém vznikají na motoru (cs, sk), spustí stejný pokus: při úspěchu agent dostane výchozí hlas motoru pro nový jazyk (Milena, Katarina), při selhání zůstane na ElevenLabs. Změna mezi cs a sk nic nepřesouvá. Ostatní přechody dělá volai (podpora). Agent na ElevenLabs bere jen anet nebo syrové ElevenLabs voice id; ostatní hlasy katalogu fungují jen na motoru. Odpověď navíc vždy nese pole laughterEffective ({active, reason, sensitiveCategory} | null) - živý stav politiky smíchu pro PUBLIKOVANOU konfiguraci, spočtený čerstvě mimo hovor. U agenta na ElevenLabs je to bez volání motoru vždy {active: false, reason: "not_engine", sensitiveCategory: null}; u agenta na motoru je reason jedna z několika hodnot (ok, agent_off, sensitive_prompt, voice_not_listed a další) a motor smí časem přidat novou - neznámou hodnotu zobraz jako vypnuto, ne jako chybu. Když motor neodpoví do 3 vteřin, je nedostupný, nebo agenta nezná (tichá 404 u starší verze motoru), je laughterEffective rovnou null - nikdy odhad.
Když motor neodpoví do 3 vteřin, je nedostupný nebo agenta nezná, vypadá odpověď takto: "laughterEffective": null - ne objekt s odhadnutými hodnotami.
Požadavek
curl https://volai.cz/v1/agents/ag_kx91fa2b \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"agent": {
"id": "ag_kx91fa2b",
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, tady recepce kavárny Nula, jak vám mohu pomoct?",
"voiceId": "milena",
"provider": "engine",
"numberE164": "+420601234567",
"createdAt": 1756111000000,
"status": "active",
"toolIds": ["tl_5c2a91f4"],
"transferTo": "+420777123456",
"transferCondition": "Volající výslovně žádá spojení s člověkem.",
"dataFields": [
{
"key": "jmeno",
"type": "string",
"description": "Jméno volajícího, které sám řekl."
},
{
"key": "spechalo",
"type": "string",
"description": "Jak moc věc spěchala.",
"enumValues": ["nizka","bezna","vysoka"]
}
],
"recordCalls": true,
"goal": null,
"knowledge": null,
"notifyEmail": true,
"silencePromptSecs": 10,
"laughter": "auto",
"missedCallSms": { "enabled": false },
"suspended": false,
"laughterEffective": {
"active": true,
"reason": "ok",
"sensitiveCategory": null
}
}
}Chybové stavy
- 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu.
GET/v1/agents/{id}/call-hold
Přečte vlastní trvalou stopku agenta. Odpověď je přímo {agentId, held, hold}; před zastavením held:false, hold:null. Neříká nic o administrátorské suspenzi ani dalších podmínkách volání.
Požadavek
curl https://volai.cz/v1/agents/ag_example/call-hold -H 'Authorization: Bearer vk_TVUJ_KLIC'Odpověď
{
"agentId": "ag_example",
"held": false,
"hold": null
}Chybové stavy
- 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu.
POST/v1/agents/{id}/call-hold
Trvale zastaví nové odchozí hovory vlastního agenta motoru a jeho ověřené zpětné kampaňové hovory. Tělo má přesně reason:budget_limit a operationId (1-128 znaků, písmena, čísla, tečka, podtržítko, dvojtečka a pomlčka; první znak písmeno nebo číslo). Stopka nemá expiraci ani obnovení. Stejné ID a obsah vrátí původní audit, jiná operace 409 revision_conflict; po nejisté odpovědi ověřte GET. hold obsahuje agentId, reason, operationId, fingerprint a createdAt. Nemění admin suspenzi, demo ani běžící hovory. Nezávislý výpadek callback resolveru stále ponechá výchozího agenta čísla. Idempotency-Key zde není zdrojem idempotence.
Požadavek
curl https://volai.cz/v1/agents/ag_example/call-hold -X POST -H 'Authorization: Bearer vk_TVUJ_KLIC' -H 'Content-Type: application/json' -d '{"reason":"budget_limit","operationId":"budget-stop-001"}'Odpověď
{
"agentId": "ag_example",
"held": true,
"hold": {
"agentId": "ag_example",
"reason": "budget_limit",
"operationId": "budget-stop-001",
"fingerprint": "14e5bfb3f57897b30d172ef4ba861b2a27e7beb1de278a94b47bc0f14c614f4c",
"createdAt": "2026-10-08T12:00:00.000Z"
}
}Chybové stavy
- 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 400
validationNeplatné tělo nebo nepodporovaný agent. Zvolte vlastního agenta motoru mimo sdílenou ukázku. - 409
revision_conflictExistuje jiné trvalé zastavení. Původní audit zůstal zachován; stav ověřte přes GET.
PATCH/v1/agents/{id}
Upraví existujícího agenta - stejná pole jako při vytvoření, všechna nepovinná. Pošli jen to, co se má změnit. Dvě z nich se ale posílají VŽDY CELÁ, protože nahrazují dosavadní seznam: toolIds a dataFields. Prázdné pole tedy funkci vypne ("toolIds": [] odebere agentovi všechny nástroje), kdežto chybějící klíč znamená „nech, jak to je“. Přepojení se vypíná prázdným řetězcem: "transferTo": "".
Požadavek
curl -X PATCH https://volai.cz/v1/agents/ag_kx91fa2b \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"firstMessage": "Dobrý den, kavárna Nula, co si dáte?"}'Odpověď
{
"agent": {
"id": "ag_kx91fa2b",
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, kavárna Nula, co si dáte?",
"voiceId": "milena",
"provider": "engine",
"numberE164": "+420601234567",
"createdAt": 1756111000000,
"status": "active",
"toolIds": ["tl_5c2a91f4"],
"transferTo": "+420777123456",
"transferCondition": "Volající výslovně žádá spojení s člověkem.",
"recordCalls": true,
"goal": null,
"knowledge": null,
"notifyEmail": true,
"silencePromptSecs": 10,
"laughter": "auto",
"missedCallSms": { "enabled": false },
"suspended": false
}
}Chybové stavy
- 400
invalid_nameJméno agenta musí mít 1 až 60 znaků. - 400
invalid_system_promptInstrukce agenta musí mít 10 až 6000 znaků. - 400
invalid_languagelanguage musí být cs, sk, en, de nebo pl. - 400
tool_limitV toolIds je víc než 10 nástrojů. - 400
invalid_data_fieldsdataFields mají neplatný klíč, typ, popis nebo je jich víc než 10. - 400
invalid_goalgoal je moc dlouhý - vejde se do 300 znaků. - 400
invalid_knowledgeknowledge je moc dlouhý - vejde se do 20000 znaků. - 400
transfer_looptransferTo míří na volai číslo téhož účtu. - 400
blocked_destinationtransferTo je prémiová linka se zvláštním tarifem. - 400
invalid_voicemail_messagemessage ve voicemail chybí nebo je moc dlouhá - povinná při action "message", vejde se do 400 znaků. - 400
voicemail_requires_enginevoicemail je jen pro agenta s provider "engine". Agenta na ElevenLabs převede na motor podpora (podpora@volai.cz); do té doby pole vynech. - 400
invalid_workflowNeplatný graf workflow (nedosažitelný uzel, chybějící vstupní uzel, rezervované jméno nástroje...); nic se neuloží, konkrétní důvod je vždy v message. - 404
calendar_integration_not_foundcalendar.integrationId neukazuje na kalendářové připojení tvého účtu - vyber ho znovu z GET /v1/integrations. - 400
calendar_invalid_calendarcalendar.calendarId není mezi kalendáři toho připojení, nebo je jen ke čtení (accessRole reader nebo freeBusyReader) - agent do něj schůzku nezapíše. Vyber kalendář s právem zápisu z list_calendars. - 400
calendar_invalid_timezonecalendar.timezone není platná IANA zóna, například "Europe/Prague". - 400
calendar_invalid_windowsOkna v calendar.windows nemají tvar HH:MM, překrývají se, nebo je jich na jeden den víc než čtyři. - 400
calendar_no_windowsKalendář je zapnutý, ale žádný den nemá okno - agent by neměl co nabídnout. - 400
calendar_invalid_rulesČíselná pravidla kalendáře jsou mimo meze, nebo je minimální předstih delší než horizont hledání. - 404
tool_not_foundNástroj z toolIds neexistuje nebo nepatří tvému účtu. - 404
agent_not_foundAgent neexistuje nebo nepatří tvému účtu. - 400
validationTvar vstupu nesedí - typicky voiceId, které neodpovídá žádné položce z GET /v1/voices ani nevypadá jako syrové ElevenLabs ID (chyba vyjmenuje platné hodnoty), nebo silencePromptSecs mimo meze 3 až 25. - 409
in_progressBuď na agentovi právě probíhá jiná změna (koncept nebo publikace), nebo předchozí změna proběhla, ale nešla bezpečně potvrdit - než tohle PATCH zopakuješ, přečtiGET /v1/agents/{id}/draft/operationa rozhodni podleoperation. - 502
engine_unavailableU agenta, který už běží na vlastním motoru volai: motor teď neodpovídá, úprava se neuložila. Zkus to prosím znovu za chvíli. - 503
engine_not_configuredU agenta, který už běží na vlastním motoru volai: motor je momentálně nenakonfigurovaný na naší straně, úprava se neuložila. Napiš prosím podpoře. - 502
engine_readback_mismatchU agenta, který už běží na vlastním motoru volai: motor uložil jinou konfiguraci, než jsme poslali, úprava se neuložila. Zkus to znovu.
DELETE/v1/agents/{id}
Smaže agenta u volai i u ElevenLabs. Číslo, které na něj bylo navěšené, zůstává tvoje - jen mu nastav nové směrování přes PATCH /v1/numbers/{e164}.
Požadavek
curl -X DELETE https://volai.cz/v1/agents/ag_kx91fa2b \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"deleted": true
}Chybové stavy
- 404
agent_not_foundAgent neexistuje nebo nepatří tvému účtu.
Odpovědi POST /v1/agents, PATCH /v1/agents/{id}, POST /v1/agents/{id}/draft/publish a POST /v1/agents/{id}/draft/rollback mohou nést nepovinné pole warnings. Několik kódů se týká první věty: first_message_no_ai_disclosure, když uložená první věta agenta nesděluje, že mluví digitální asistent (evropský AI Act, čl. 50), a first_message_too_long, když je odhadovaná mluvená doba TOHO, CO VOLAJÍCÍ SKUTEČNĚ SLYŠÍ (první věta plus věta o nahrávání, když je recordCalls zapnuté), nad 7 sekundami (asi 2,53 slova za sekundu; číslice vždy a velké zkratky do čtyř znaků se počítají po znacích). Nezměněná výchozí šablona první věty tenhle kód nikdy nespustí, jen text, který zákazník upravil. Kdo agentku přeruší, udělá to nejčastěji do jedné sekundy slyšitelné řeči. Agent s fázemi (pole workflow, viz sekce Fáze hovoru (workflow) níž) přidává do stejného pole dalších deset kódů - dead_end, empty_node, entry_phrase_never_spoken, missing_enter_phrase, short_condition, condition_about_agent, base_prompt_long, workflow_not_synced_to_provider, workflow_node_tool_not_synced a workflow_node_tool_missing (uzel odkazuje nástroj, který na účtu už není - smazaný; fázi je potřeba uložit bez něj) - a typicky je nese i tehdy, když první věta v pořádku je (šablona Recepce jich vrací tři). Varování, které patří konkrétní fázi nebo přechodu, nese navíc nodeId, nebo edgeId. Žádný z kódů uložení nezastaví - jen na ně upozorní. Pole v odpovědi chybí, jen když není co hlásit. Vrácení konceptu na dřívější revizi (draft/rollback) vrací warnings stejně jako publikace, protože taky propisuje první větu na živého agenta. Jen publikace a rollback (ne POST/PATCH /v1/agents) navíc můžou ve stejném poli vrátit number_changed_by_publish s hodnotami from/to (E.164, nebo null bez čísla), když republikace doopravdy změní telefonní číslo živého agenta - ani ten publikaci neblokuje. Samostatný kód calendar_pending_engine_switch se objeví, když má agent nastavený calendar (termíny podle kalendáře), ale běží na ElevenLabs - nastavení se uloží a začne fungovat, jakmile agent přejde na vlastní motor volai; zapnutí kalendáře ten přechod samo spouští. Agent s připojeným číslem (numberE164), jehož zadání (systemPrompt nebo firstMessage) používá {{promennou}} mimo sadu, kterou příchozí hovor doopravdy dodává (caller_number, called_number, attempt_id, volai_blocked, volai_block_reason, trial_prompt, trial_first_message a sedm system__* proměnných), dostane prompt_variables_unavailable_inbound - na příchozím hovoru se taková proměnná dosadí jako prázdný text. Když po odstranění všech {{...}} bloků z neprázdné první věty v ní nezůstane žádné písmeno ani číslice mimo proměnné, dostane first_message_empty. Samostatný kód agent_misuse_suspected se objeví, když konfigurace agenta (u odpovědí výš) obsahuje formulace, které mohou působit jako vydávání se za úřad či jinou instituci, nebo jako žádost o citlivé údaje - viz Podmínky volai § 10. Týž kód ve stejném tvaru vracejí v nepovinném poli warnings i PUT /v1/agents/{id}/draft a POST /v1/agents/{id}/simulate (koncept), POST /v1/calls (prompt zkušebního hovoru nebo variables), POST /v1/tasks a PATCH /v1/tasks/{id} (název úkolu a proměnné příjemců) a POST /v1/tools a PATCH /v1/tools/{id} (popis nástroje a jeho parametrů). Uložení ani odeslání neblokuje, jde jen o upozornění. Jen POST /v1/agents navíc vrací elevenlabs_by_explicit_choice, když požadavek poslal useForOutboundTasks: false u jazyka, kterému by nasazení jinak dalo vlastní motor volai (dnes cs a sk), a agent proto zůstal na ElevenLabs - bez hlasů motoru a bez funkcí, které běží jen na motoru. Agent se založí, varování jen upozorní; kdo chtěl agenta jen na příchozí hovory, má pole vynechat.
{
"id": "ag_kx91fa2b",
"warnings": [
{
"code": "first_message_no_ai_disclosure",
"message": {
"cs": "Podle evropského AI Act (čl. 50) musí první věta prozradit, že mluví digitální asistentka. Stačí: „Dobrý den, tady digitální asistentka firmy Novák.“ Bez toho za sdělení odpovídáš ty.",
"en": "Under the EU AI Act (Article 50), the first line must reveal that a digital assistant is speaking. For example: \"Hello, this is the digital assistant for Novak Inc.\" Without it, you are responsible for the disclosure."
}
}
]
}Nová pole agenta
POST /v1/agents i PATCH /v1/agents/{id} berou kromě jména, promptu, hlasu a čísla i tahle pole. Všechna jsou nepovinná při vytváření. toolIds, transferTo, transferCondition, dataFields a recordCalls u staršího agenta v odpovědi chybí, dokud je nikdo nenastaví. goal a knowledge se naopak vrací VŽDY - nenastavené jako null, ne jako chybějící klíč - a notifyEmail je vždycky boolean (chybí-li, znamená to zapnuto). Odpověď navíc vždy nese provider (engine nebo elevenlabs) - říká, na kterém poskytovateli agent doopravdy běží, obě hodnoty se v provozu vyskytují. Stejně tak vždy nese suspended (boolean) - true, když agenta ručně pozastavil provozovatel volai; takový agent nepřijímá ani neuskutečňuje hovory (agent_suspended) a pole přes API ani MCP nastavit nejde. useForOutboundTasks je výjimka - bere ho JEN POST /v1/agents, v PATCH není (existujícího agenta mezi poskytovateli přepíná volai, ne zákazník; sám to udělá po zapnutí transferTo nebo calendar a po změně language na jazyk, ve kterém noví agenti vznikají na motoru - viz detail agenta výš). voicemail je dostupné jen u agenta s provider: "engine" - u ostatních POST/PATCH s tímhle polem odmítne. silencePromptSecs (připomínka v tichu) se naopak přijímá a vrací u OBOU poskytovatelů - u agenta na ElevenLabs se hodnota jen uloží, zazní až po přepnutí na vlastní motor volai. workflow (fáze hovoru) je dostupné u obou poskytovatelů, ale ne stejně úplně - viz sekci Fáze hovoru (workflow) níž. laughter (smích agentky) je taky vždy přítomné, stejně jako goal/knowledge/notifyEmail výš - u staršího agenta bez nastavené hodnoty je to auto, nikdy chybějící klíč; přijímá se a ukládá u OBOU poskytovatelů, slyšet je ale jen u agenta na motoru s českým hlasem Cartesia.
| Pole | Co dělá |
|---|---|
toolIds | Pole id webhook nástrojů z GET /v1/tools, které smí agent během hovoru volat. Nejvýš 10. Nástroj patří účtu, takže ho může mít zapnutý víc agentů. |
transferTo | Číslo v E.164, na které agent přepojí volajícího, když si řekne o člověka. Prázdný řetězec přepojení vypne. Vlastní volai číslo účtu tu být nesmí (transfer_loop). |
transferCondition | Kdy má přepojit, napsané jako pokyn modelu (do 500 znaků). Když ho nepošleš, dosadíme výchozí větu. |
dataFields | Co si má agent z hovoru zapsat: pole objektů {key, type, description, enumValues}, nejvýš 10. key jsou malá písmena bez diakritiky, číslice a podtržítka; type je string, number nebo boolean; enumValues jde zadat jen u textového údaje. Vyplněné hodnoty pak chodí v poli data u hovoru. |
recordCalls | Nahrávat hovory tohohle agenta. Výchozí je zapnuto; při false nahrávka nevznikne a GET /v1/calls/{id}/recording vrátí no_recording. Když je zapnuté, agent to volajícímu automaticky řekne v první větě. Za to, že sdělení odpovídá zákonu pro tvoji situaci, i tak odpovídáš ty. |
goal | Cíl hovoru jednou větou - podle něj LLM soudce po hovoru vyhodnotí, jestli agent dosáhl toho, kvůli čemu volající zavolal (vyhodnocuje se jen u agenta na vlastním motoru volai, viz sekci Cíl agenta a hodnocení v dokumentaci Hlasového agenta). Nejvýš 300 znaků. PATCH s null nebo prázdným řetězcem cíl smaže. |
knowledge | Text, který agent zná navíc k instrukcím - ceník, otevírací dobu, časté dotazy. Připojí se na konec promptu. Nejvýš 20000 znaků. PATCH s null nebo prázdným řetězcem znalosti smaže. |
notifyEmail | Poslat majiteli účtu e-mail se shrnutím po každém hovoru tohohle agenta - dnes se posílá jen u agenta na vlastním motoru volai (provider: "engine"); u agenta na ElevenLabs se hodnota uloží, ale e-mail se zatím neodesílá. Výchozí je zapnuto. |
useForOutboundTasks | true vybere při založení vlastní motor, false začne na ElevenLabs a bez pole platí výchozí nastavení nasazení - to závisí na zapnutí motoru a povolených jazycích. Samotné cs nebo sk motor nezaručuje; při vypnutém výchozím motoru agent vzniká na ElevenLabs. POST vrací jen id, výsledek proto čti z provider v následném GET /v1/agents/{id}. Pole je jen při zakládání; další přechody dělá volai (podpora). transferTo navíc spouští pokus o převod z ElevenLabs na motor, jehož výsledek je potřeba ověřit. |
voicemail | Rozpoznání hlasové schránky u ODCHOZÍCH hovorů - objekt {enabled, action, message}. message je povinná při action: "message", do 400 znaků. PATCH ho bere jen u agenta s provider: "engine". U POST musí na motor mířit prvotní volba: explicitní useForOutboundTasks: true nebo vynechané pole s motorem jako výchozím. false selže s voicemail_requires_engine i s transferTo, protože validace předchází pokusu o převod. PATCH s null nastavení smaže. |
silencePromptSecs | Kolik vteřin ticha od volajícího vyvolá jednu připomínku ("Jste tam?"), celé číslo 3 až 25. null připomínku vypne. Chybí-li pole při POST, uloží se výchozích 10. Přijímá a ukládá se u OBOU poskytovatelů - u agenta na standardní platformě ElevenLabs (provider: "elevenlabs") se hodnota jen uloží a zazní až po přepnutí agenta na vlastní hlasový motor volai, který jediný umí připomínku přehrát. Hodnota mimo meze 3 až 25 se odmítne obecnou validační chybou (validation, 400) - žádný vlastní kód. |
workflow | Rozdělí hovor na fáze (uzly) - viz sekci Fáze hovoru (workflow) níž pro tvar, limity a příklad. PATCH s null fáze smaže a agent se vrátí na jednu fázi jako dosud. |
laughter | Jestli se agentka smí v hovoru zasmát, když se zasměje nebo zažertuje volající: auto nechá rozhodnutí na detekci citlivého tématu (dluhy, zdravotnictví, úřady, pohřebnictví), on přebije tuhle detekci, off ho vždy potlačí; skutečný výsledek pro danou konfiguraci ukazuje laughterEffective. Vynechané pole se při POST uloží jako auto a v odpovědi je laughter vždy přítomné, nikdy jako chybějící klíč. Přijímá a ukládá se u OBOU poskytovatelů, slyšet je ale jen u agenta na motoru s českým hlasem Cartesia - u ElevenLabs nemá žádný efekt. Změna platí od dalšího hovoru. |
Přepojení: co API opravdu udělá
Na vlastním hlasovém motoru volai jde přepojení mostem: agent vytočí cíl jako druhého účastníka a po zvednutí zmlkne. Na standardní platformě přepojení nefunguje. transferTo spustí pokus převést agenta na motor, ale při pozastavení, nedostupnosti nebo chybě může zůstat na ElevenLabs; výsledek ověř v provider. Shrnutí hovoru člověku předat neumíme ani na jedné platformě, žádný „warm transfer“ neexistuje.
Druhá noha je běžný odchozí hovor a tak se i účtuje: 0,92 Kč/min bez agentní přirážky. Ve výpisu hovorů ji poznáš podle kind: "transfer".
Fáze hovoru (workflow)
Volitelné pole workflow rozdělí hovor do fází (nodes). Uzel je ROZSAH, ne scénář: jen doplní prompt, znalosti a nástroje platné, dokud je hovor v něm, a volitelně větu, kterou agent řekne hned při vstupu. Přechod mezi uzly rozhoduje model sám tím, že zavolá nástroj - nikdy to nepředepisuješ jako pevný skript. Základní systemPrompt agenta by měl nést jen to, co platí VE VŠECH fázích (identitu, tón, jak se předává vzkaz); instrukce jedné fáze patří do jejího uzlu, jinak nemá účinek. Do základního promptu patří i dvě věty, bez kterých agent nejčastěji odpoví, co neví: „Provozní údaje, které nemáš v zadání (otevírací doba, lhůty, ceny, dostupnost lidí), neříkej a neodhaduj - řekni, že to upřesní kolega.“ a „Ptej se vždy jen na jednu věc najednou.“
entry je id uzlu, ve kterém hovor začíná. edges jsou přechody: condition (5 až 200 znaků) popisuje, KDY přejít, a musí mluvit o tom, co řekl VOLAJÍCÍ (nikdy o tom, co udělal agent nebo nástroj) - jde doslova do popisu nástroje, kterým model přechod provede. Limity: 2 až 8 uzlů, 1 až 24 hran, nejvýš 5 hran z jednoho uzlu, mezi dvěma uzly smí vést jen jedna hrana (v libovolném směru, duplicate_pair); uzlův prompt má nejvýš 2 000 znaků, knowledge nejvýš 4 000, prompt a knowledge dohromady nejvýš 4 000 na uzel, a toolIds nejvýš 10 nástrojů na uzel.
enterPhrase je věta vyslovená jednou při vstupu do uzlu (nejvýš 160 znaků). enterBehavior: "wait" řekne modelu, ať po ní v tomtéž tahu nic dalšího neříká a počká na volajícího - typicky u citlivé fáze jako oznámení úmrtí; vyžaduje vyplněné enterPhrase, jinak wait_without_phrase. Uzel bez vlastního enterPhrase dostane při vstupu výchozí krátkou větu (např. česky „Rozumím.“) jen na vlastním motoru volai (provider: "engine"); u agenta na ElevenLabs se při vstupu neozve nic - vlastní věta zní přirozeněji a je jediná, která zazní u obou, a proto ji editor dál doporučuje varováním missing_enter_phrase.
Uzel typu konec neexistuje - fáze samy o sobě hovor nikdy neukončí. Hovor pořád končí jen vestavěným ukončením, stejně jako dosud.
enterBehavior: "wait" se přenáší i k agentům na ElevenLabs, ne jen na vlastní hlasový motor volai (provider: "engine"); věta při vstupu na motoru zazní doslovně, u ElevenLabs jde do promptu fáze jako instrukce, ať ji řekne - model ji zpravidla řekne podobně, ale ne nutně stejnými slovy. Uzel BEZ vlastního enterPhrase u ElevenLabs neřekne při vstupu nic: výchozí krátkou větu (např. česky „Rozumím.“) doplňuje jedině vlastní motor volai. Dva rozdíly jsou větší. Nástroj přiřazený JEN uzlu (node.toolIds) se k agentovi na ElevenLabs zatím nepřenáší - fáze tam poběží bez něj, a odpověď na to upozorní kódem workflow_node_tool_not_synced; když ho tam chceš mít, přidej ho i mezi nástroje agenta (pole toolIds, v portálu záložka Pokročilé). Na vlastním motoru volai se uzlový nástroj přenáší beze změny. A workflowPath u hovoru zapisuje výhradně post-call vlastního motoru, takže hovor agenta na ElevenLabs ho nikdy nenese, i když fázemi prošel.
Neplatný graf (nedosažitelný uzel, chybějící vstupní uzel, rezervované jméno nástroje...) vrátí invalid_workflow a nic se neuloží; konkrétní důvod je vždy v message.
Příklad - recepce pohřební služby
{
"workflow": {
"version": 1,
"entry": "triaz",
"nodes": [
{
"id": "triaz",
"label": "Triáž",
"prompt": "Zjisti, proč volající volá, jednou otázkou. Pomáháš volajícím s ohlášením úmrtí, s výkopem hrobu nebo uložením urny a s poptávkou práce na pomníku."
},
{
"id": "umrti",
"label": "Úmrtí",
"prompt": "Zjisti jméno zesnulého, kde se úmrtí stalo, jestli je tělo v nemocnici nebo doma, kontakt a čas, kdy se ozvat. Slib, že pracovník pohřební služby zavolá do 15 minut. Otázky na pomník nebo jeho cenu tady neřeš - řekni jen, že to s pozůstalými probere kolega, nic nevysvětluj a vrať se k úmrtí. Pomník sám nezmiňuj.",
"enterPhrase": "Upřímnou soustrast.",
"enterBehavior": "wait"
},
{
"id": "vykop",
"label": "Výkop a uložení",
"prompt": "Volající řeší výkop hrobu, uložení urny nebo otevření hrobky. Zjisti termín, hřbitov a číslo hrobu, kontakt a jestli je potřeba domluvit s duchovním."
},
{
"id": "poptavka",
"label": "Poptávka práce",
"prompt": "Volající poptává novou práci na pomníku - nápis, opravu nebo rekonstrukci hrobu. Zjisti hřbitov, číslo hrobu, rozsah práce a kontakt na zpětné volání s cenou."
}
],
"edges": [
{
"id": "triaz_umrti",
"from": "triaz",
"to": "umrti",
"condition": "Volající oznamuje úmrtí blízké osoby nebo potřebuje pohřební službu."
},
{
"id": "triaz_vykop",
"from": "triaz",
"to": "vykop",
"condition": "Volající potřebuje výkop hrobu, uložení urny nebo otevření hrobky."
},
{
"id": "triaz_poptavka",
"from": "triaz",
"to": "poptavka",
"condition": "Volající poptává novou práci: pomník, nápis, opravu nebo rekonstrukci hrobu."
},
{
"id": "vykop_umrti",
"from": "vykop",
"to": "umrti",
"condition": "Volající během hovoru oznámí úmrtí blízké osoby."
},
{
"id": "poptavka_umrti",
"from": "poptavka",
"to": "umrti",
"condition": "Volající během hovoru oznámí úmrtí blízké osoby."
}
]
}
}Hovor, který fázemi prošel NA VLASTNÍM MOTORU VOLAI (provider: "engine"), nese v GET /v1/calls/{id} (i ve výpisu GET /v1/calls) navíc pole workflowPath: pole kroků {node, label, viaEdge, turnIndex, at, enterPhraseSpoken}, at jako unix ms. Vstupní krok má viaEdge: null. Hovor agenta na ElevenLabs pole nikdy nemá, i když fázemi prošel - zapisuje ho jen post-call motoru. Hovor bez fází klíč vůbec nemá.
Koncept agenta (draft)
Koncept (draft) je oddělený rozpracovaný snímek agenta - uložíš si do něj úpravu, prohlédneš si ji, klidně ji vyzkoušíš (simulace níž) a teprve pak ji jedním voláním nasadíš na živého agenta. PUT /v1/agents/{id}/draft NIKDY nesahá na poskytovatele hlasu (ElevenLabs ani vlastní motor volai) ani na telefonii - jen uloží koncept. POST /v1/agents/{id}/draft/publish ano - je to jediný krok konceptu, který živého agenta doopravdy mění.
Naproti tomu PATCH /v1/agents/{id} (sekce Agenti výš) sahá na poskytovatele SÁM A HNED, bez konceptu a bez mezikroku.
Publikace může vrátit kteroukoli chybu PATCH /v1/agents/{id} - je to týž zápis k poskytovateli.
Koncept, nebo PATCH?
PATCH - jsi jediný editor agenta a změna má být hned živá. Koncept - agenta souběžně edituje i člověk v portálu (portálový editor jede VÝHRADNĚ přes koncept, nikdy přes PATCH), chceš změnu zkontrolovat nebo vyzkoušet (simulace) před nasazením, nebo potřebuješ optimistickou souběžnost (expectedRevision ochrání před přepsáním cizí rozpracované změny).
Co se stane, když koncept obejdeš
Zámek na agentovi je SPOLEČNÝ pro PATCH /v1/agents/{id} a POST .../draft/publish - PATCH během probíhající publikace vrátí 409 in_progress. PATCH mimo probíhající publikaci ale KLIDNĚ projde: zvýší revision o 1, přepíše published na novou živou hodnotu, smaže marker tested (dřívější simulace už neplatí pro novou konfiguraci) a draft nechá beze změny. Rozpracovaný koncept (typicky člověk v portálu) pak při dalším uložení narazí na 409 revision_conflict - to je ZÁMĚR, ne chyba: konfliktní PATCH se nesmí ztratit v tichosti.
Editor agenta v portálu (/agent/{id}) jede VÝHRADNĚ přes koncept - i tam, kde majitel jen upraví jedno pole, portál interně volá save_agent_draft + publish_agent_draft.
Pole snímku konceptu
draft a published mají v každé odpovědi STEJNÝ tvar - AgentDraftSnapshot, kompletní snímek konfigurace agenta. Tělo PUT/publish je .strict() - na rozdíl od PATCH /v1/agents, který neznámý klíč tiše zahodí, tady neznámý klíč vrátí 400 validation. U pole workflow se při ukládání konceptu ověřuje JEN tvar JSONu - pravidla grafu (dosažitelnost fází, existující nástroje, limity na fázi) kontroluje až publikace a PATCH /v1/agents/{id}, takže koncept se uloží i s grafem, který publikace odmítne chybou invalid_workflow. Dvě výjimky z "kompletní snímek pokaždé" existují: chybějící silencePromptSecs ve snímku znamená BEZE ZMĚNY, ne vypnuto a ne výchozích 10 - u agenta na ElevenLabs nese uloženou hodnotu, která zazní až po přepnutí na vlastní motor volai. Stejně tak chybějící numberE164 znamená BEZE ZMĚNY - publikace nechá číslo živého agenta být; teprve null ho odpojí a řetězec připojí uvedené číslo, stejná trojice významů jako u PATCH /v1/agents/{id}. Za "beze změny" se počítá i řetězec, který se shoduje se ŽIVÝM číslem agenta v tu chvíli (ne s uloženou published verzí) - taková hodnota se chová jako chybějící klíč. Tohle se vyhodnocuje znovu při KAŽDÉM čtení konceptu proti tehdy aktuálně živému číslu, takže to není trvalé rozhodnutí: přesune-li se číslo později na jiného agenta mimo tenhle koncept, stejná uložená hodnota se stane výslovnou volbou a další publikace nebo rollback konceptu ho tomuhle agentovi vrátí zpátky - ne potichu, ale s varováním number_changed_by_publish ve warnings.
| Pole | Poznámka |
|---|---|
name, language, systemPrompt, provider | name, language, systemPrompt a provider jsou POVINNÉ - koncept je úplný snímek, ne dílčí patch. |
provider | provider ("engine" nebo "elevenlabs") musí přesně odpovídat aktuálnímu provider agenta, jinak invalid_draft - u POST/PATCH /v1/agents se naopak vůbec neposílá (server ho odvozuje sám). Je to jediné pole, které koncept nese navíc oproti běžnému agentovi. |
toolIds, dataFields | toolIds a dataFields mají strop 10 položek každé - stejný jako u POST /v1/agents a PATCH /v1/agents/{id} (viz tabulku Nová pole agenta výš). |
Zbylá pole (firstMessage, voiceId, transferTo, transferCondition, recordCalls, goal, knowledge, notifyEmail) mají stejný význam a meze jako u POST/PATCH /v1/agents - viz tabulku Nová pole agenta výš.
operation: co agenta právě blokuje
operation (u GET .../draft i GET .../draft/operation) je null, když agenta nic neblokuje, jinak objekt { id, kind, status, expectedRevision, createdAt, updatedAt }. Hodnoty kind a status jsou zúžené na to, co potřebuješ k rozhodnutí - interní detaily (kdo přesně operaci spustil, jaký byl přesný text chyby poskytovatele) ven nejdou.
| kind | Poznámka |
|---|---|
update | Živá úprava přes PATCH /v1/agents/{id} (mimo koncept). |
publish | Publikace uloženého konceptu (POST .../draft/publish). |
rollback | Návrat na dřívější publikovanou revizi z historie (POST .../draft/rollback) - stejně jako publish sahá na poskytovatele a telefonii. |
outbound_task | Dávkové vytáčení (odchozí kampaň) - agenta právě používá jiná dávková úloha; publikace/PATCH počká, až doběhne. |
| status | Poznámka |
|---|---|
running | Operace právě běží u poskytovatele. |
uncertain | Poskytovatel mohl, ale nemusel změnu provést - zkontroluj živého agenta a operaci NEOPAKUJ naslepo (viz POST .../draft/operation níž). |
drift | Živá konfigurace u poskytovatele se liší od toho, co si myslíme, že jsme poslali - vyžaduje ruční rozhodnutí. |
failed | Operace selhala jistě - koncept zůstal beze změny, klidně zkus znovu. |
done | Operace doběhla úspěšně (publikace, potvrzený návrat, nebo bezpečně vyřešená nejistota). |
tested (GET .../draft i odpověď POST .../simulate) je { revision, testedAt } | null - kdy byla naposled otestovaná PRÁVĚ TATO revize konceptu simulací. Jakákoli další úprava konceptu (PUT) marker smaže; simulace NENÍ podmínkou publikace, je to jen dobrovolná kontrola formulace před nasazením.
history je seznam { revision, publishedAt } posledních publikací (bez uložených snímků konfigurace) - kompletní historii včetně obsahu má jen portál.
GET/v1/agents/{id}/draft
Přečte koncept, poslední publikovanou konfiguraci, revizi (pro expectedRevision dalších volání), poslední výsledek simulace (tested) a to, jestli agenta právě něco blokuje (operation).
Požadavek
curl https://volai.cz/v1/agents/ag_kx91fa2b/draft \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"draft": {
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, kavárna Nula, co si dáte?",
"voiceId": "milena",
"numberE164": "+420601234567",
"provider": "engine"
},
"published": {
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, tady recepce kavárny Nula, jak vám mohu pomoct?",
"voiceId": "milena",
"numberE164": "+420601234567",
"provider": "engine"
},
"revision": 4,
"tested": {
"revision": 4,
"testedAt": 1756118920000
},
"history": [
{
"revision": 3,
"publishedAt": 1756118840000
},
{
"revision": 2,
"publishedAt": 1756112640000
}
],
"operation": null
}Chybové stavy
- 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 500
storage_failedUložení nebo načtení konceptu selhalo na naší straně - zkus to prosím znovu.
PUT/v1/agents/{id}/draft
Uloží koncept podle expectedRevision. Tělo posílej PŘESNĚ jako objekt, který jsi přečetl z GET, s jednou provedenou změnou - tělo je .strict(), takže i drobný neznámý klíč vrátí 400. Uložení NIKDY nemění běžícího agenta. Ukázka GET .../draft výš zobrazuje stav PO tomhle PUT (revize 3 -> 4): proto tenhle PUT posílá expectedRevision: 3 (revize, na které úprava stavěla) a GET výš už vrací revision: 4 (novou revizi po uložení).
Požadavek
curl -X PUT "https://volai.cz/v1/agents/ag_kx91fa2b/draft" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":3,"draft":{"name":"Recepční","language":"cs","systemPrompt":"Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...","firstMessage":"Dobrý den, kavárna Nula, co si dáte?","voiceId":"milena","numberE164":"+420601234567","provider":"engine"}}'Odpověď
{
"draft": {
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, kavárna Nula, co si dáte?",
"voiceId": "milena",
"numberE164": "+420601234567",
"provider": "engine"
},
"revision": 4
}Chybové stavy
- 400
validationNeplatný tvar těla - viz meze u konkrétního pole. - 400
invalid_draftproviderv konceptu neodpovídáprovideragenta - koncept se dá upravovat jen v mezích téhož poskytovatele. - 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 409
revision_conflictKoncept mezitím upravil (nebo PATCHem obešel) někdo jiný. Chyba nesecurrentRevision- načti aktuální stav přesGET .../drafta zkontroluj rozdíl, než uložení zopakuješ. - 409
publish_in_progressNa agentovi právě běží jiná publikace nebo dávková úloha - zkus to znovu za chvíli. - 409
operation_uncertainNa agentovi visí nejistá operace z předchozího pokusu - zkontroluj živého agenta a vyřeš ji přesGET/POST .../draft/operation, než zkusíš znovu. - 500
storage_failedUložení nebo načtení konceptu selhalo na naší straně - zkus to prosím znovu.
POST/v1/agents/{id}/draft/publish
Nasadí uložený koncept na živého agenta - jediný krok konceptu, který sahá na poskytovatele (ElevenLabs nebo motor volai) a telefonii. Bere Idempotency-Key (viz sekci Idempotence výš) - druhé volání se stejným klíčem do 24 hodin vrátí přesně tu samou uloženou odpověď, ať byla úspěšná, nebo operation_uncertain.
Chyby z nasazení (deploy) se propagují BEZE ZMĚNY - publikace dědí CELOU chybovou tabulku PATCH /v1/agents/{id} výš (in_progress, engine_unavailable, engine_not_configured, engine_readback_mismatch a validační kódy), plus vlastní tabulku konceptu výš.
Požadavek
curl -X POST "https://volai.cz/v1/agents/ag_kx91fa2b/draft/publish" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: REPLACE_WITH_UNIQUE_POST_V1_AGENTS_AG_KX91FA2B_DRAFT_PUBLISH_ID" \
-d '{"expectedRevision":4}'Před spuštěním nahraď REPLACE_WITH_UNIQUE… jedinečným ID této akce, například UUID, a ulož si ho. Při opakování stejného požadavku po timeoutu použij stejné ID. Pro jinou akci nebo změněné tělo použij nové ID, i když voláš jiný endpoint.
Odpověď
{
"revision": 5,
"published": {
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, kavárna Nula, co si dáte?",
"voiceId": "milena",
"numberE164": "+420601234567",
"provider": "engine"
}
}Chybové stavy
- 400
validationNeplatný tvar těla - viz meze u konkrétního pole. - 400
invalid_draftproviderv konceptu neodpovídáprovideragenta - koncept se dá upravovat jen v mezích téhož poskytovatele. - 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 409
revision_conflictKoncept mezitím upravil (nebo PATCHem obešel) někdo jiný. Chyba nesecurrentRevision- načti aktuální stav přesGET .../drafta zkontroluj rozdíl, než uložení zopakuješ. - 409
publish_in_progressNa agentovi právě běží jiná publikace nebo dávková úloha - zkus to znovu za chvíli. - 409
operation_uncertainNa agentovi visí nejistá operace z předchozího pokusu - zkontroluj živého agenta a vyřeš ji přesGET/POST .../draft/operation, než zkusíš znovu. - 409
idempotency_in_progressSouběžné volání se stejnýmIdempotency-Keyještě běží - zkus to prosím za chvíli znovu. - 500
storage_failedUložení nebo načtení konceptu selhalo na naší straně - zkus to prosím znovu. - 503
engine_not_configuredU agenta na vlastním motoru volai: motor je momentálně nenakonfigurovaný na naší straně, publikace se neuložila. Napiš prosím podpoře. - 502
engine_unavailableU agenta na vlastním motoru volai: motor teď neodpovídá, publikace se neuložila. Zkus to prosím znovu za chvíli. - 502
engine_readback_mismatchU agenta na vlastním motoru volai: motor uložil jinou konfiguraci, než jsme poslali, publikace se neuložila. Zkus to znovu. - 409
in_progressBuď na agentovi právě probíhá jiná změna (živý PATCH nebo jiná publikace), nebo předchozí změna proběhla, ale nešla bezpečně potvrdit - než publikaci zopakuješ, přečtiGET /v1/agents/{id}/draft/operationa rozhodni podleoperation.
POST/v1/agents/{id}/draft/rollback
Vrátí agenta na dřívější PUBLIKOVANOU revizi z historie (targetRevision, viz pole history u GET .../draft) a rovnou ji nasadí poskytovateli - je to publikace, ne jen přepsání konceptu. expectedRevision chrání proti souběžné úpravě stejně jako u PUT .../draft. Na rozdíl od .../draft/publish BEZ Idempotency-Key - opakování se stejným tělem je bezpečné samo o sobě.
Sdílí přesně stejné dva zdroje chyb jako publikace výš: vlastní chybovou tabulku konceptu (validation, invalid_draft, forbidden, agent_not_found, revision_conflict, publish_in_progress, operation_uncertain, storage_failed) a CELOU chybovou tabulku PATCH /v1/agents/{id} (nasazení sahá na poskytovatele stejně jako u PATCH/publikace).
Požadavek
curl -X POST "https://volai.cz/v1/agents/ag_kx91fa2b/draft/rollback" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":4,"targetRevision":2}'Odpověď
{
"revision": 5,
"published": {
"name": "Recepční",
"language": "cs",
"systemPrompt": "Jsi recepční kavárny Nula. Přijímáš objednávky na vyzvednutí...",
"firstMessage": "Dobrý den, kavárna Nula, co si dáte?",
"voiceId": "milena",
"numberE164": "+420601234567",
"provider": "engine"
}
}Chybové stavy
- 400
validationNeplatný tvar těla - viz meze u konkrétního pole. - 400
invalid_drafttargetRevision už není mezi uloženými historickými revizemi (historyuGET .../draftji nenese). - 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 409
revision_conflictKoncept mezitím upravil (nebo PATCHem obešel) někdo jiný. Chyba nesecurrentRevision- načti aktuální stav přesGET .../drafta zkontroluj rozdíl, než uložení zopakuješ. - 409
publish_in_progressNa agentovi právě běží jiná publikace nebo dávková úloha - zkus to znovu za chvíli. - 409
operation_uncertainNa agentovi visí nejistá operace z předchozího pokusu - zkontroluj živého agenta a vyřeš ji přesGET/POST .../draft/operation, než zkusíš znovu. - 500
storage_failedUložení nebo načtení konceptu selhalo na naší straně - zkus to prosím znovu. - 503
engine_not_configuredU agenta na vlastním motoru volai: motor je momentálně nenakonfigurovaný na naší straně, publikace se neuložila. Napiš prosím podpoře. - 502
engine_unavailableU agenta na vlastním motoru volai: motor teď neodpovídá, publikace se neuložila. Zkus to prosím znovu za chvíli. - 502
engine_readback_mismatchU agenta na vlastním motoru volai: motor uložil jinou konfiguraci, než jsme poslali, publikace se neuložila. Zkus to znovu. - 409
in_progressBuď na agentovi právě probíhá jiná změna (živý PATCH nebo jiná publikace), nebo předchozí změna proběhla, ale nešla bezpečně potvrdit - než publikaci zopakuješ, přečtiGET /v1/agents/{id}/draft/operationa rozhodni podleoperation.
GET/v1/agents/{id}/draft/operation
Přečte aktuální stav blokující operace (null, když agenta nic neblokuje) - stejný tvar jako operation u GET .../draft.
Požadavek
curl https://volai.cz/v1/agents/ag_kx91fa2b/draft/operation \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"operation": {
"id": "ado_4f2a91cd",
"kind": "publish",
"status": "uncertain",
"expectedRevision": 4,
"createdAt": 1756118900000,
"updatedAt": 1756118905000
}
}Chybové stavy
- 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 500
storage_failedUložení nebo načtení konceptu selhalo na naší straně - zkus to prosím znovu.
POST/v1/agents/{id}/draft/operation
Po ruční kontrole živého agenta bezpečně uzavře nejistou (uncertain) operaci - potvrdíš, že jsi stav zkontroloval, a server ověří poskytovatele (readback) a operaci uzavře.
Požadavek
curl -X POST https://volai.cz/v1/agents/ag_kx91fa2b/draft/operation \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"operationId":"ado_4f2a91cd","decision":"acknowledge_live_state"}'Odpověď
{
"reconciled": true,
"revision": 5
}Chybové stavy
- 400
validationoperationId chybí, nebo decision není"acknowledge_live_state". - 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 409
revision_conflictKoncept mezitím upravil (nebo PATCHem obešel) někdo jiný. Chyba nesecurrentRevision- načti aktuální stav přesGET .../drafta zkontroluj rozdíl, než uložení zopakuješ. - 409
operation_uncertainNa agentovi visí nejistá operace z předchozího pokusu - zkontroluj živého agenta a vyřeš ji přesGET/POST .../draft/operation, než zkusíš znovu. - 500
storage_failedUložení nebo načtení konceptu selhalo na naší straně - zkus to prosím znovu.
POST/v1/agents/{id}/simulate
Pošle textovou zprávu proti ULOŽENÉMU konceptu (ne živému agentovi) a nastaví marker tested. Zdarma (0 Kč, platí volai), NENÍ podmínkou publikace, limit 20 za hodinu na účet, běží na pevném modelu Anthropic (jméno se ven neposílá), BEZ nástrojů a BEZ hlasu (ASR/TTS) - je to kontrola formulace promptu, ne test skutečného hovoru.
messages (nepovinné) jsou předchozí tahy konverzace BEZ aktuální zprávy - { role: "user" | "assistant", content }. Meze: message 1 až 4000 znaků, nejvýš 8 zpráv historie, 2000 znaků na historickou zprávu, 8000 znaků historie celkem.
Požadavek
curl -X POST https://volai.cz/v1/agents/ag_kx91fa2b/simulate \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":4,"message":"Dobry den"}'Odpověď
{
"revision": 4,
"text": "Dobrý den, kavárna Nula, co si dáte?",
"usage": {
"inputTokens": 412,
"outputTokens": 58
},
"tested": {
"revision": 4,
"testedAt": 1756118920000
}
}Chybové stavy
- 400
validationNeplatný tvar těla - viz meze u konkrétního pole. - 403
forbiddenSdílený demo agent volai je jen pro čtení. - 404
agent_not_foundAgent neexistuje, byl smazaný, nebo nepatří tvému účtu. - 409
revision_conflictKoncept mezitím upravil (nebo PATCHem obešel) někdo jiný. Chyba nesecurrentRevision- načti aktuální stav přesGET .../drafta zkontroluj rozdíl, než uložení zopakuješ. - 429
rate_limitedVyčerpal jsi limit 20 simulací za hodinu na účet. - 502
simulation_failedModel Anthropic vrátil chybu nebo neplatnou odpověď - zkus to prosím znovu. - 503
simulation_not_configuredSimulace je na naší straně dočasně nenakonfigurovaná - napiš prosím podpoře. - 503
simulation_unavailableKvótu simulace se nepodařilo ověřit (dočasný výpadek Redisu) - zkus to prosím znovu. - 409
publish_in_progressSimulace proběhla v pořádku, ale zápis markerutestednarazil na právě běžící publikaci konceptu - zkus to znovu za chvíli. - 409
operation_uncertainSimulace proběhla v pořádku, ale zápis markerutestednarazil na nejistou operaci z předchozího pokusu - vyřeš ji přesGET/POST .../draft/operation, než to zkusíš znovu. - 500
storage_failedSimulace proběhla v pořádku, ale zápis markerutestedselhal na naší straně - zkus to prosím znovu.
Hlasy
Katalog hlasů pro voiceId u POST/PATCH /v1/agents. Platformu říká provider; prvotní volbu určuje useForOutboundTasks. U existujícího agenta na motoru přijme PATCH každý katalogový hlas KROMĚ hlasů ElevenLabs (katty, starší anet); katty a syrové ElevenLabs ID jsou platné jen na ElevenLabs (anet tam zůstává jen agentům, kteří ho už mají). POST má jednu výjimku: explicitní true nahradí známý hlas nepodporovaný motorem, včetně katty, jeho výchozím hlasem. Pokud motor zvolí výchozí nastavení při vynechaném poli, stejná hodnota vrátí 400; syrové ElevenLabs ID motor odmítne vždy. Filtr ?provider=engine vrátí hlasy motoru, ?provider=elevenlabs hlasy ElevenLabs. Neznámá hodnota vrátí 400 validation a vyjmenuje platné hodnoty. Stejný katalog v tabulce s popisem každého hlasu je na stránce Hlasový agent.
GET/v1/voices
Katalog hlasů dostupných pro voiceId u agentů.
Požadavek
curl https://volai.cz/v1/voices \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"voices": [
{
"id": "milena",
"name": "Milena",
"gender": "female",
"provider": "cartesia",
"tone": "calm, warm",
"description": "The default volai voice - calm and natural, a good fit for most agents.",
"languages": [
"cs"
],
"preview": {
"studio": "https://volai.cz/hlasy/milena-studio.mp3",
"phone": "https://volai.cz/hlasy/milena-telefon.mp3"
},
"default": true
},
{
"id": "jan",
"name": "Jan",
"gender": "male",
"provider": "cartesia",
"tone": "calm, matter-of-fact",
"description": "The male counterpart to Milena - matter-of-fact, easy-to-follow delivery.",
"languages": [
"cs"
],
"preview": {
"studio": "https://volai.cz/hlasy/jan-studio.mp3",
"phone": "https://volai.cz/hlasy/jan-telefon.mp3"
},
"default": false
},
{
"id": "tereza",
"name": "Tereza",
"gender": "female",
"provider": "cartesia",
"tone": "professional, structured",
"description": "The second female voice - professional, well-structured delivery.",
"languages": [
"cs"
],
"preview": {
"studio": "https://volai.cz/hlasy/tereza-studio.mp3",
"phone": "https://volai.cz/hlasy/tereza-telefon.mp3"
},
"default": false
},
{
"id": "marek",
"name": "Marek",
"gender": "male",
"provider": "cartesia",
"tone": "calm, resonant",
"description": "The second male voice - calm, resonant delivery for longer calls.",
"languages": [
"cs"
],
"preview": {
"studio": "https://volai.cz/hlasy/marek-studio.mp3",
"phone": "https://volai.cz/hlasy/marek-telefon.mp3"
},
"default": false
},
{
"id": "katarina",
"name": "Katarina",
"gender": "female",
"provider": "cartesia",
"tone": "calm, natural",
"description": "Slovak female voice - calm, natural delivery.",
"languages": [
"sk"
],
"preview": {
"studio": "https://volai.cz/hlasy/katarina-studio.mp3",
"phone": "https://volai.cz/hlasy/katarina-telefon.mp3"
},
"default": false
},
{
"id": "peter",
"name": "Peter",
"gender": "male",
"provider": "cartesia",
"tone": "matter-of-fact, clear",
"description": "Slovak male voice - matter-of-fact, easy-to-follow delivery.",
"languages": [
"sk"
],
"preview": {
"studio": "https://volai.cz/hlasy/peter-studio.mp3",
"phone": "https://volai.cz/hlasy/peter-telefon.mp3"
},
"default": false
},
{
"id": "skylar",
"name": "Skylar",
"gender": "female",
"provider": "cartesia",
"tone": "calm, friendly",
"description": "English female voice - calm, friendly delivery.",
"languages": [
"en"
],
"preview": {
"studio": "https://volai.cz/hlasy/skylar-studio.mp3",
"phone": "https://volai.cz/hlasy/skylar-telefon.mp3"
},
"default": false
},
{
"id": "daniel",
"name": "Daniel",
"gender": "male",
"provider": "cartesia",
"tone": "matter-of-fact, confident",
"description": "English male voice - matter-of-fact, confident delivery.",
"languages": [
"en"
],
"preview": {
"studio": "https://volai.cz/hlasy/daniel-studio.mp3",
"phone": "https://volai.cz/hlasy/daniel-telefon.mp3"
},
"default": false
},
{
"id": "alina",
"name": "Alina",
"gender": "female",
"provider": "cartesia",
"tone": "calm, warm",
"description": "German female voice - calm, warm delivery.",
"languages": [
"de"
],
"preview": {
"studio": "https://volai.cz/hlasy/alina-studio.mp3",
"phone": "https://volai.cz/hlasy/alina-telefon.mp3"
},
"default": false
},
{
"id": "lukas",
"name": "Lukas",
"gender": "male",
"provider": "cartesia",
"tone": "matter-of-fact, clear",
"description": "German male voice - matter-of-fact, easy-to-follow delivery.",
"languages": [
"de"
],
"preview": {
"studio": "https://volai.cz/hlasy/lukas-studio.mp3",
"phone": "https://volai.cz/hlasy/lukas-telefon.mp3"
},
"default": false
},
{
"id": "ewa",
"name": "Ewa",
"gender": "female",
"provider": "cartesia",
"tone": "calm, natural",
"description": "Polish female voice - calm, natural delivery.",
"languages": [
"pl"
],
"preview": {
"studio": "https://volai.cz/hlasy/ewa-studio.mp3",
"phone": "https://volai.cz/hlasy/ewa-telefon.mp3"
},
"default": false
},
{
"id": "kacper",
"name": "Kacper",
"gender": "male",
"provider": "cartesia",
"tone": "matter-of-fact, confident",
"description": "Polish male voice - matter-of-fact, confident delivery.",
"languages": [
"pl"
],
"preview": {
"studio": "https://volai.cz/hlasy/kacper-studio.mp3",
"phone": "https://volai.cz/hlasy/kacper-telefon.mp3"
},
"default": false
}
]
}Chybové stavy
- 400
validationprovider není jedna z hodnot: elevenlabs, engine.
Pole tone popisuje povahu hlasu (klidný, věcný); languages obsahuje kódy jazyků, ve kterých hlas mluví - cs: Milena, Jan, Tereza, Marek; sk: Katarina, Peter; en: Skylar, Daniel; de: Alina, Lukas; pl: Ewa, Kacper; preview nese URL studiové a telefonní ukázky; default značí doporučenou položku katalogu - v portálu nese jen štítek 'Výchozí' na kartě a sama o sobě nic nepředvybírá. Nový agent založený bez voiceId na ni nepřechází - zdědí výchozí hlas svého poskytovatele (u motoru Milenu, u ElevenLabs hlas šablony, viz sekci Agenti výš).
Nástroje agenta
Nástroj je adresa tvého API, kterou agent zavolá uprostřed hovoru (ověřit objednávku, zapsat rezervaci) a odpověď použije v řeči. Nástroj patří účtu, agentovi se přiřadí přes toolIds - samo vytvoření nástroje tedy žádného agenta nezmění.
Limity: nejvýš 10 nástrojů na účet, 10 parametrů a 5 hlaviček na nástroj, timeoutSecs 5 až 30 (výchozí 20). Adresa musí být https a veřejná - vnitřní sítě a loopback odmítáme (private_address), protože jinak by šlo naším serverem oťukávat cizí infrastrukturu.
GET/v1/tools
Seznam webhook nástrojů na účtu. Hodnoty hlaviček jsou vždy maskované.
Požadavek
curl https://volai.cz/v1/tools \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"tools": [
{
"id": "tl_5c2a91f4",
"name": "overit_objednavku",
"label": "Ověřit objednávku",
"description": "Zjistí stav objednávky podle čísla. Použij, když se volající ptá, kde je jeho objednávka.",
"url": "https://api.tvojeappka.cz/objednavky",
"method": "POST",
"headers": { "Authorization": "Bear***" },
"params": [
{
"name": "cislo_objednavky",
"type": "string",
"source": "llm",
"description": "Číslo objednávky, které volající nadiktoval.",
"required": true
},
{ "name": "telefon", "type": "string", "source": "caller_number" },
{ "name": "zdroj", "type": "string", "source": "constant", "constantValue": "telefon" }
],
"timeoutSecs": 20,
"createdAt": 1756111000000,
"updatedAt": 1756111000000
}
]
}POST/v1/tools
Vytvoří nástroj. label je čitelný název, jméno pro model se z něj odvodí samo (Ověřit objednávku -> overit_objednavku) a vrátí se v poli name. description je jediné, podle čeho se model rozhodne, KDY nástroj použít - piš ho jako pokyn („Použij, když se volající ptá, kde je jeho objednávka.“), 10 až 1000 znaků.
Požadavek
curl -X POST https://volai.cz/v1/tools \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{
"label": "Ověřit objednávku",
"description": "Zjistí stav objednávky podle čísla. Použij, když se volající ptá, kde je jeho objednávka.",
"url": "https://api.tvojeappka.cz/objednavky",
"method": "POST",
"headers": { "Authorization": "Bearer tvuj_klic" },
"params": [
{
"name": "cislo_objednavky",
"type": "string",
"source": "llm",
"description": "Číslo objednávky, které volající nadiktoval.",
"required": true
},
{ "name": "telefon", "type": "string", "source": "caller_number" },
{ "name": "zdroj", "type": "string", "source": "constant", "constantValue": "telefon" }
],
"timeoutSecs": 20
}'Odpověď
{
"tool": {
"id": "tl_5c2a91f4",
"name": "overit_objednavku",
"label": "Ověřit objednávku",
"description": "Zjistí stav objednávky podle čísla. Použij, když se volající ptá, kde je jeho objednávka.",
"url": "https://api.tvojeappka.cz/objednavky",
"method": "POST",
"headers": { "Authorization": "Bear***" },
"params": [
{
"name": "cislo_objednavky",
"type": "string",
"source": "llm",
"description": "Číslo objednávky, které volající nadiktoval.",
"required": true
},
{ "name": "telefon", "type": "string", "source": "caller_number" },
{ "name": "zdroj", "type": "string", "source": "constant", "constantValue": "telefon" }
],
"timeoutSecs": 20,
"createdAt": 1756111000000,
"updatedAt": 1756111000000
}
}Chybové stavy
- 400
tool_limitNa účtu už je 10 nástrojů. - 400
invalid_tool_namelabel musí mít 1 až 60 znaků, nebo by z názvu vzniklo rezervované jméno (end_call,transfer_to_human,switch_to_*). - 400
invalid_tool_urlurl není platná adresa, nebo není https. - 400
private_addressurl míří do vnitřní sítě nebo na loopback. - 400
invalid_tool_paramsParametr má neplatné jméno, typ, zdroj, nebo je jich víc než 10. - 400
invalid_tool_headersHlavička je zakázaná (host, content-length, x-conversation-id, x-caller-id), duplicitní, prázdná, nebo je jich víc než 5. - 400
validationdescription mimo 10 až 1000 znaků, timeoutSecs mimo 5 až 30, nebo method jiná než GET/POST. - 502
eleven_labs_errorNástroj se nepodařilo založit u hlasové platformy - lokálně jsme nic neuložili, zkus to znovu.
GET/v1/tools/{id}
Detail jednoho nástroje - stejná pole jako ve výpisu, plus agents: pole agentů, kteří ho mají zapnutý přes toolIds (jen id a name, celého agenta si dotáhneš přes GET /v1/agents/{id}).
Požadavek
curl https://volai.cz/v1/tools/tl_5c2a91f4 \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"tool": {
"id": "tl_5c2a91f4",
"name": "overit_objednavku",
"label": "Ověřit objednávku",
"description": "Zjistí stav objednávky podle čísla. Použij, když se volající ptá, kde je jeho objednávka.",
"url": "https://api.tvojeappka.cz/objednavky",
"method": "POST",
"headers": { "Authorization": "Bear***" },
"params": [
{
"name": "cislo_objednavky",
"type": "string",
"source": "llm",
"description": "Číslo objednávky, které volající nadiktoval.",
"required": true
},
{ "name": "telefon", "type": "string", "source": "caller_number" },
{ "name": "zdroj", "type": "string", "source": "constant", "constantValue": "telefon" }
],
"timeoutSecs": 20,
"createdAt": 1756111000000,
"updatedAt": 1756111000000,
"agents": [{ "id": "ag_kx91fa2b", "name": "Recepční" }]
}
}Chybové stavy
- 404
tool_not_foundNástroj neexistuje nebo nepatří tvému účtu.
PATCH/v1/tools/{id}
Upraví nástroj - všechna pole nepovinná, mění se jen ta zaslaná. Pozor na dvě věci: params i headers nahrazují celý dosavadní seznam, a změna label přepíše i jméno, kterým nástroj zná model - když se na něj odkazuješ v systemPrompt, uprav ho zároveň.
Hlavičky chodí ven jen maskované ("Bear***"). Když pošleš zpátky přesně tu maskovanou hodnotu, bereme to jako „nech původní“ - běžný postup „načti nástroj, změň jedno pole, pošli celý objekt zpět“ ti tedy přihlašovací údaje nezničí. Skutečnou změnu hodnoty pošli v plném znění.
Požadavek
curl -X PATCH https://volai.cz/v1/tools/tl_5c2a91f4 \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"timeoutSecs": 10}'Odpověď
{
"tool": {
"id": "tl_5c2a91f4",
"name": "overit_objednavku",
"label": "Ověřit objednávku",
"description": "Zjistí stav objednávky podle čísla. Použij, když se volající ptá, kde je jeho objednávka.",
"url": "https://api.tvojeappka.cz/objednavky",
"method": "POST",
"headers": { "Authorization": "Bear***" },
"params": [
{
"name": "cislo_objednavky",
"type": "string",
"source": "llm",
"description": "Číslo objednávky, které volající nadiktoval.",
"required": true
},
{ "name": "telefon", "type": "string", "source": "caller_number" },
{ "name": "zdroj", "type": "string", "source": "constant", "constantValue": "telefon" }
],
"timeoutSecs": 10,
"createdAt": 1756111000000,
"updatedAt": 1756111890000
}
}Chybové stavy
- 400
invalid_tool_urlurl není platná adresa, nebo není https. - 400
private_addressurl míří do vnitřní sítě nebo na loopback. - 400
invalid_tool_paramsParametr má neplatné jméno, typ nebo zdroj. - 400
invalid_tool_headersHlavička je zakázaná, duplicitní nebo prázdná. - 400
validationdescription (je-li poslaný) mimo 10 až 1000 znaků, timeoutSecs mimo 5 až 30, nebo method jiná než GET/POST. - 404
tool_not_foundNástroj neexistuje nebo nepatří tvému účtu. - 502
eleven_labs_mismatchZměna se u hlasové platformy neuložila přesně podle zadání - lokálně jsme nic nepřepsali.
DELETE/v1/tools/{id}
Smaže nástroj a vrátí agenty, kterým tím přestal fungovat (jen id a name; celého agenta si dotáhneš přes GET /v1/agents/{id}). Na rozdíl od uvolnění čísla je to vratná ztráta - stejný nástroj jde založit znovu, jen dostane nové id, které je pak potřeba agentům přiřadit.
Požadavek
curl -X DELETE https://volai.cz/v1/tools/tl_5c2a91f4 \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"deleted": true,
"agents": [
{ "id": "ag_kx91fa2b", "name": "Recepční" }
]
}Chybové stavy
- 404
tool_not_foundNástroj neexistuje nebo nepatří tvému účtu. - 502
eleven_labs_errorNástroj se nepodařilo smazat u hlasové platformy - zkus to prosím znovu.
POST/v1/tools/test
Odešle SKUTEČNÝ požadavek podle poslané definice a vrátí, co přišlo zpátky - nástroj se NEUKLÁDÁ (na rozdíl od POST /v1/tools, label/description jsou tu nepovinné). Hodí se na vyzkoušení adresy, než ji uložíš jako nástroj agenta. timeoutSecs se tu jen validuje (5 až 30) - zkouška má vždy pevných 10 sekund, ať u ní nečekáš celý runtime timeout; je to hodnota, kterou by nástroj použil při ostrém běhu po uložení. Sdílí rate limit s POST /v1/tools/{id}/test níž - dohromady nejvýš 10 pokusů za minutu na účet.
Požadavek
curl -X POST https://volai.cz/v1/tools/test \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"url": "https://api.yourapp.com/orders", "method": "GET", "params": [{"name": "order", "type": "string", "source": "llm", "description": "Order number."}]}'Odpověď
{
"status": 200,
"durationMs": 214,
"body": "{\"status\":\"shipped\"}",
"note": null
}Chybové stavy
- 400
validationmethod jiná než GET/POST, nebo timeoutSecs mimo 5 až 30. - 400
invalid_tool_urlurl není platná adresa, nebo síťová/DNS/TLS chyba při samotném odeslání požadavku (kamkoli v téhle fázi - i timeout - se sbalí do stejného kódu). - 400
private_addressurl míří do vnitřní sítě nebo na loopback (SSRF ochrana) - kontrola proběhne PŘED odesláním. - 400
invalid_tool_paramsParametr má neplatné jméno, typ, zdroj, nebo je jich víc než 10. - 400
invalid_tool_headersHlavička je zakázaná, duplicitní, prázdná, nebo je jich víc než 5. - 429
rate_limitedVyčerpal jsi 10 pokusů za minutu (společně sPOST /v1/tools/{id}/test) - zkus to prosím za chvíli.
POST/v1/tools/{id}/test
Zkouší JIŽ ULOŽENÝ nástroj podle id - tělo je vždy prázdné {}, adresu, metodu a SKUTEČNÉ (nemaskované) hlavičky bere endpoint z uloženého záznamu, ne z těla požadavku. private_address/invalid_tool_params/invalid_tool_headers tu nejdou vrátit (uložený záznam znovu neprochází kontrolou vstupu) - síťová chyba se pořád sbalí do invalid_tool_url.
Požadavek
curl -X POST https://volai.cz/v1/tools/tl_5c2a91f4/test \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{}'Odpověď
{
"status": 200,
"durationMs": 214,
"body": "{\"status\":\"shipped\"}",
"note": null
}Chybové stavy
- 400
validationTělo požadavku není prázdné - pošli{}, nebo úplně žádné tělo. - 400
invalid_tool_urlSíťová/DNS/TLS chyba (i timeout) při odeslání skutečného požadavku. - 404
tool_not_foundNástroj neexistuje nebo nepatří tvému účtu.
Parametry nástroje: pole source
Každý parametr má name, type (string, number, boolean) a source - odkud se vezme hodnota. U GET jdou parametry do query, u POST do JSON těla.
| source | Odkud je hodnota | Co k tomu vyplnit |
|---|---|---|
llm | Vytáhne ji z hovoru model. | description (co přesně tam má dát) a volitelně required. |
caller_number | Číslo volajícího v E.164, doplní se samo. | Nic. Model tohle pole vůbec nevidí. |
called_number | Tvoje volané číslo v E.164, doplní se samo. | Nic. Model tohle pole vůbec nevidí. |
constant | Pevná hodnota, kterou zadáš ty. | constantValue. |
Zkušební hovor
„Nech si zavolat od svého agenta" - reálný odchozí hovor přes makeAgentCall, jen s vlastním denním limitem 3 hovory na účet (napříč všemi agenty), aby zkušební volání nešlo zneužít jako obchvat běžného limitu hovorů.
POST/v1/agents/{id}/test-call
Zavolá ti zpátky z tvého vlastního agenta - stejná cena a stejná pravidla jako u POST /v1/calls, žádná sleva ani zvláštní sazba. Agent na vlastním hlasovém motoru volai zavolá i BEZ přiřazeného čísla - jen ze sdílené linky volai, takže volaný uvidí číslo volai, ne tvoje. Vlastní číslo agentovi přiřadíš přes PATCH /v1/numbers/{e164} (routing agent) nebo polem numberE164 u agenta (POST/PATCH /v1/agents), případně v portálu v sekci Čísla.
Požadavek
curl -X POST https://volai.cz/v1/agents/ag_kx91fa2b/test-call \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"to": "+420777123456"}'Odpověď
{
"id": "c_9d4e2b7f",
"status": "initiated"
}Chybové stavy
- 400
validationto chybí nebo přesahuje 32 znaků, nebo tělo není platné JSON. - 404
agent_not_foundagentId neexistuje nebo nepatří tvému účtu. - 404
agent_no_numberAgent nemá přiřazené telefonní číslo - tuhle chybu vrací jen agent na ElevenLabs; agent na vlastním motoru volai zavolá i bez čísla ze sdílené linky volai. - 403
agent_suspendedAgenta ručně pozastavil provozovatel volai - zkušební hovor teď nejde uskutečnit. Pozastavený celý účet vrací místo tohoaccount_suspended. - 402
insufficient_creditKredit nepokryje minimum pro zahájení hovoru. - 503
capacity_busyVšechny odchozí linky jsou právě obsazené, zkus to za minutu. - 429
rate_limitedVyčerpaný denní limit 3 zkušebních hovorů na účet - běžné volání přes POST /v1/calls tenhle limit nemá.
Relay - vlastní agent
Jednorázový pronájem SIP jména z relay poolu pro odchozí hovor tvého vlastního hlasového agenta (ElevenLabs i jiná platforma) - bez agentní přirážky 2,50 Kč/min, tu totiž platíš u své platformy sám. Kompletní návod s nastavením ElevenLabs je na stránce Vlastní agent.
POST/v1/relay
Vytvoří lease - to je cílové číslo, from tvoje vlastní volai číslo, ze kterého má hovor vypadat, že jde. Vrácené sipName je HOLÉ jméno pro ElevenLabs to_number (ne sipUri - ElevenLabs celé SIP URI odmítne). Odchozí trunk své platformy nastav na outboundTrunkAddress z GET /v1/numbers/{e164}/sip - jiná adresa znamená, že se hovor v síti nesměruje a platforma ohlásí timeout.
ttlSecs (nepovinné, výchozí 120) - kolik vteřin lease čeká na první hovor, než nevyužitý zanikne. Povolený rozsah je 15 až 300 vteřin - mimo něj vrátí 400 validation.
Požadavek
curl -X POST https://volai.cz/v1/relay \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"to": "+420777123456", "from": "+420601234567"}'Odpověď
{
"id": "rl_4f2a91cd",
"sipName": "volai_relay_2",
"sipUri": "sip:volai_relay_2@sip.volai.cz",
"expiresAt": 1756111760000,
"callId": "c_9d4e2b7f"
}Chybové stavy
- 400
invalid_numberto nebo from není platné telefonní číslo. - 400
validationttlSecs mimo povolený rozsah 15 až 300 vteřin. - 404
from_number_not_ownedfrom nepatří tvému účtu. - 400
on_dncto je na tvém seznamu nevolat. - 400
relay_lease_limitUž máš aktivní lease na tomhle čísle, nebo dvě na celém účtu. - 402
insufficient_creditKredit nepokryje minimum pro zahájení hovoru. - 409
destination_busyNa to už běží jiný hovor. - 503
capacity_busyRelay pool je právě plný, zkus to za chvíli - nic ti neúčtujeme.
GET/v1/relay
Výpis tvých relay spojení - pending čeká na první hovor, active znamená, že hovor právě běží.
Požadavek
curl https://volai.cz/v1/relay \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"leases": [
{
"id": "rl_4f2a91cd",
"sipName": "volai_relay_2",
"sipUri": "sip:volai_relay_2@sip.volai.cz",
"from": "+420601234567",
"to": "+420777123456",
"callId": "c_9d4e2b7f",
"status": "active",
"createdAt": 1756111640000,
"expiresAt": 1756111760000
}
]
}DELETE/v1/relay/{id}
Uvolní lease a vrátí slot do poolu, dokud čeká na první hovor (pending). Neukončí probíhající hovor - to dnes žádné API neumí (ani telefonní síť, ani ElevenLabs) - takový lease (active) doběhne sám, jen zabrání dalšímu použití stejného leasu.
Požadavek
curl -X DELETE https://volai.cz/v1/relay/rl_4f2a91cd \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"cancelled": true
}Chybové stavy
- 404
lease_not_foundLease neexistuje, vypršel, nebo nepatří tvému účtu. - 409
lease_already_activeLease už spotřeboval hovor, který právě běží - takový lease se nedá zrušit (doběhne sám). Platí jen pro DELETE /v1/relay/{id}, ne pro založení nového leasu.
Seznam nevolat (DNC)
Čísla, na která tvůj agent (vlastní i zabudovaný) nemá volat - ať přes POST /v1/calls, zkušební hovor nebo relay. DNC platí jen pro hovory - odeslání SMS na číslo v seznamu nijak neomezuje.
Kromě ručního seznamu volai destinaci automaticky (a dočasně) zablokuje samo - po 3 neúspěšných pokusech za 24 hodin (obsazeno, nezvednuto, odmítnuto) přestane na číslo volat na 30 dní. Blokaci jde zrušit v portálu (Nastavení) nebo přes POST /v1/dnc/{e164}/unblock - jinak sama odezní.
GET/v1/dnc
Ruční seznam (numbers) i automaticky blokované destinace (blocked) - blockedAt a expiresAt jsou unixové milisekundy. Automatická blokace, která začala před verzí 1.8.0, ve blocked nemusí být; když hovor vrátí destination_auto_blocked, zavolej odblokovací endpoint přímo s jeho číslem i bez řádku ve výpisu.
Požadavek
curl https://volai.cz/v1/dnc \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"numbers": ["+420777998877"],
"blocked": [
{
"e164": "+420777123456",
"blockedAt": 1757600000000,
"expiresAt": 1760192000000
}
]
}POST/v1/dnc
Přidá číslo na seznam nevolat.
Požadavek
curl -X POST https://volai.cz/v1/dnc \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"e164": "+420777998877"}'Odpověď
{
"added": true,
"e164": "+420777998877"
}Chybové stavy
- 400
validatione164 není platné telefonní číslo.
DELETE/v1/dnc/{e164}
Odebere číslo ze seznamu nevolat.
Požadavek
curl -X DELETE "https://volai.cz/v1/dnc/+420777998877" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"removed": true,
"e164": "+420777998877"
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo.
POST/v1/dnc/{e164}/unblock
Zruší automatickou blokaci destinace, pokud existuje - i blokaci z doby před verzí 1.8.0, která ve výpisu blocked chybí. Vrátí unblocked: false, ne 404, když blokace nebyla.
Požadavek
curl -X POST "https://volai.cz/v1/dnc/+420777998877/unblock" \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"unblocked": true,
"e164": "+420777998877"
}Chybové stavy
- 400
validatione164 v URL není platné telefonní číslo.
Webhook
GET/v1/webhook
Aktuální nastavení odchozích webhooků - bez podpisového secretu, ten se vrací jen z PUT.
Požadavek
curl https://volai.cz/v1/webhook \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"url": "https://tvoje-appka.cz/webhooks/volai",
"events": ["call.completed", "call.failed", "message.sent"],
"recentDeliveries": [
{
"id": "whd_9f2b7a1c4e",
"event": "call.completed",
"url": "https://tvoje-appka.cz/webhooks/volai",
"status": 200,
"attempts": 1,
"ok": true,
"durationMs": 184,
"createdAt": 1756111641000
}
]
}PUT/v1/webhook
Nastaví (nebo přepíše) cílovou URL a odebírané události. V odpovědi dostaneš i podpisový secret - ulož si ho hned, později ho GET už nevrátí. Prázdné pole events: [] znamená odebírat všechny události, ne žádnou - a to i ty, které přibudou později. Když chceš jen některé, vyjmenuj je. Naopak prázdné url: "" webhook zruší - volai pak nepošle nic a odpověď vrátí url: null. Postup ověření podpisu je na stránce Webhooky.
Požadavek
curl -X PUT "https://volai.cz/v1/webhook" \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-d '{"url":"https://tvoje-appka.cz/webhooks/volai","events":["call.completed","call.failed","message.sent"]}'Odpověď
{
"url": "https://tvoje-appka.cz/webhooks/volai",
"secret": "whsec_9f2b7a1c4e6d8f0a",
"events": ["call.completed", "call.failed", "message.sent"]
}Chybové stavy
- 400
validationurl chybí nebo přesahuje 2000 znaků, nebo events má víc než 20 položek, nebo je některá položka přes 100 znaků. - 400
invalid_urlURL musí začínat https:// (http:// je povolené jen pro localhost). - 400
invalid_eventsNěkterá z events není známá (call.completed, call.failed, call.missed, call.no_answer, message.sent, message.received).
DELETE/v1/webhook
Zruší webhook - stejný účinek jako PUT /v1/webhook s prázdným url, jen výslovně pojmenovaný. Nový webhook jde kdykoli nastavit znovu přes PUT. V MCP odpovídá nástroj remove_webhook; list_webhook_deliveries je MCP protějšek GET /v1/webhook/deliveries výš.
Požadavek
curl -X DELETE https://volai.cz/v1/webhook \
-H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"removed":true}POST/v1/webhook/test
Pošle jeden testovací pokus na nastavenou URL, BEZ OHLEDU na filtr events z PUT /v1/webhook - testuje se doručitelnost, ne odběr. Žádný retry, i neúspěch se zapíše do přehledu doručení. Nejvýš 10 za hodinu.
Požadavek
curl -X POST https://volai.cz/v1/webhook/test \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"delivered": true,
"status": 200,
"attempts": 1,
"durationMs": 184
}Chybové stavy
- 404
not_foundWebhook není nastavený - nejdřív ho nastav přesPUT /v1/webhook. - 429
rate_limitedVyčerpal jsi limit 10 testovacích událostí za hodinu.
GET/v1/webhook/deliveries
Posledních 50 doručení (úspěšných, neúspěšných i testovacích), nejnovější první - stejný tvar jako recentDeliveries u GET /v1/webhook.
Požadavek
curl https://volai.cz/v1/webhook/deliveries \
-H "Authorization: Bearer vk_TVUJ_KLIC"Odpověď
{
"deliveries": [
{
"id": "whd_9f2b7a1c4e",
"event": "webhook.test",
"url": "https://tvoje-appka.cz/webhooks/volai",
"status": 200,
"attempts": 1,
"ok": true,
"durationMs": 184,
"createdAt": 1756111641000
}
]
}Google & Apple Calendar
V portálu otevři Připojení a připoj účet. Google se připojuje souhlasem v prohlížeči (povolíš čtení kalendářů i práci s událostmi), Apple e-mailem Apple účtu a heslem pro konkrétní aplikaci (vyžaduje dvoufaktorové ověřování); iCloud kalendáře najde volai automaticky. REST a MCP pak používají běžný API klíč volai stejného účtu a přihlašovací údaje poskytovatele se klientům nevrací. Odkaz na připojení otevírej v prohlížeči s přihlášením do volai. GET /v1/integrations obsahuje připravenost konfigurace a odkazy pro připojení v prohlížeči; ready označuje konfiguraci serveru, nikoli ověřené spojení s účtem.
Rozhraní čte a upravuje existující události. Před změnou načti detail, ukaž uživateli původní hodnoty a návrh a po potvrzení pošli sourceRevision, patch a confirm: true. Revize je neprůhledný řetězec včetně případných uvozovek. Kalendářové chyby mají prefix calendar_: stale_revision (409) vyžaduje nové načtení a schválení, oauth_failed/unauthorized (409) nové připojení, provider_error (502) opakování později. Po nejistém zápisu nebo verification_failed (502) nejdřív načti událost a ověř výsledek.
GET/v1/integrations
Seznam vlastních připojení, připravenost konfigurace a odkazy pro připojení v prohlížeči.
Požadavek
curl "https://volai.cz/v1/integrations" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"integrations":[],"providers":{"google-calendar":{"ready":true,"connectUrl":"https://volai.cz/api/integrations/google-calendar/oauth/start"},"apple-calendar":{"ready":true,"connectUrl":"https://volai.cz/en/connections"},"fakturoid":{"ready":true,"connectUrl":"https://volai.cz/api/integrations/fakturoid/oauth/start"},"abra-flexi":{"ready":true,"connectUrl":"https://volai.cz/en/connections"}},"googleCalendar":{"ready":true,"connectUrl":"https://volai.cz/api/integrations/google-calendar/oauth/start"}}POST/v1/integrations
Připojí Apple Kalendář nebo ABRA FlexiBee přihlašovacími údaji v těle. Google Kalendář a Fakturoid mají jen OAuth flow v prohlížeči (odkaz connectUrl z GET /v1/integrations) - poslat jejich provider sem vrátí integration_unsupported. Bere Idempotency-Key; i bez ní je opakované volání se stejnými údaji fakticky idempotentní - existující záznam se najde podle poskytovatele a účtu, ke kterému údaje patří (u Apple podle přihlašovacího jména, u ABRA podle adresy serveru a firmy); label je jen popisek a při opakovaném volání se přepíše.
Přihlašovací údaj předávej jen tehdy, když ho uživatel sám uložil někam, odkud ho můžeš přečíst (proměnná prostředí nebo soubor, který pojmenoval). Nikdy si o něj neříkej v konverzaci a nikdy ho nevypisuj zpět.
Požadavek
curl -X POST https://volai.cz/v1/integrations \
-H "Authorization: Bearer $VOLAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"provider":"apple-calendar","username":"you@icloud.com","appPassword":"abcd-efgh-ijkl-mnop"}'Odpověď
{"integration":{"id":"int_7f3a91cd","provider":"apple-calendar","kind":"calendar","label":"apple-calendar","createdAt":1756111640000,"updatedAt":1756111640000}}Chybové stavy
- 409
idempotency_in_progressSouběžné volání se stejnýmIdempotency-Keyještě běží - zkus to prosím za chvíli znovu. - 400
validationNeplatný tvar těla - u Apple chybíusername/appPassword, u ABRAbaseUrl/company/username/password, nebo tělo obsahuje neznámé pole (schéma je.strict()). - 400
integration_unsupportedproviderjegoogle-calendarnebofakturoid- ty se připojují jen OAuth flow v prohlížeči. - 400
integration_invalid_providerAdresa serveru ABRA FlexiBee (baseUrl) není na seznamu domén povolených provozovatelem volai - napiš podpoře, ať doménu povolí. - 400
integration_invalid_calendarBuď Apple účet nemá žádný dostupný kalendář, který by šlo připojit, nebo poslaná hodnota calendarUrl není mezi kalendáři, které vrátilo vyhledávání kalendářů (discovery) na iCloudu. - 409
integration_unauthorizedPoskytovatel přihlašovací údaje odmítl (špatné jméno nebo heslo). - 409
integration_read_onlyApple CalDAV odmítl zápis (403) - účet má jen čtecí přístup ke kalendáři. - 409
integration_busyNa účtu právě běží jiná operace nad integracemi - zkus to za chvíli znovu. - 404
integration_not_foundIntegrace, kterou má tenhle požadavek aktualizovat, mezitím zmizela - zkus připojit znovu. - 502
integration_provider_errorChyba na straně poskytovatele - zkus to prosím za chvíli znovu. - 502
integration_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to znovu, a pokud to přetrvává, napiš podpoře. - 500
integration_storage_errorUložení přihlašovacích údajů selhalo na naší straně - zkus to prosím znovu.
DELETE/v1/integrations/{id}
Odpojí libovolnou integraci (Google, Apple, Fakturoid, ABRA) - nevratné, žádné potvrzení a žádný MCP nástroj, protože odpojení nejde vzít zpět. Připojit přes REST znovu jde jen Apple a ABRA (viz POST /v1/integrations výš) - Google a Fakturoid znovu přes OAuth v prohlížeči.
Požadavek
curl -X DELETE https://volai.cz/v1/integrations/int_7f3a91cd \
-H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"disconnected":true}Chybové stavy
- 404
integration_not_foundIntegrace neexistuje nebo nepatří tvému účtu. - 409
integration_busyNa integraci právě běží jiná operace (typicky obnova tokenu) - zkus to za chvíli znovu.
GET/v1/integrations/{id}/calendars
Kalendáře vlastního připojení. id získáš ze seznamu připojení.
Požadavek
curl "https://volai.cz/v1/integrations/int_CONNECTION/calendars" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"calendars":[{"id":"primary","label":"Work","timezone":"Europe/Prague","accessRole":"owner"}]}Chybové stavy
- 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 409
calendar_read_onlyKalendář je připojený jen pro čtení (Apple CalDAV odmítl zápis) - v Apple Kalendáři si zkontroluj oprávnění ke sdílenému kalendáři. - 409
calendar_busyNa tomhle připojení právě běží jiná operace (typicky obnova tokenu) - zkus to prosím za chvíli znovu. - 409
calendar_refresh_in_progressPřístup k účtu se právě obnovuje na pozadí - zkus to prosím za chvíli znovu. - 409
calendar_unauthorizedPřipojení ztratilo přístup u poskytovatele - připoj účet v portálu znovu. - 409
calendar_oauth_failedPřihlášení k účtu poskytovatele selhalo - připoj účet v portálu znovu. - 409
calendar_credentials_unavailableUložené přihlašovací údaje připojení se nepodařilo rozšifrovat - připoj účet v portálu znovu; pokud to přetrvává, napiš podpoře. - 409
calendar_invalid_credentialsUložené přihlašovací údaje poskytovatel odmítl - připoj účet v portálu znovu. - 503
calendar_not_configuredKalendářová integrace je na naší straně momentálně nenakonfigurovaná - napiš prosím podpoře. - 502
calendar_provider_errorChyba na straně poskytovatele (Google, Apple) - zkus to prosím za chvíli znovu. - 502
calendar_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to prosím znovu, a pokud to přetrvává, napiš podpoře.
POST/v1/integrations/{id}/availability
Vrátí volné termíny v připojeném kalendáři BEZ uloženého agenta - stejný výpočet jako check_availability v hovoru, jen bez pravidel agenta. windows chybí = 24 hodin každý den; když ho pošleš, vynechaný den v týdnu nemá žádné okno. to musí být po from a nejvýš 31 dní po něm. Odpověď nese jen start/end a timezone - žádné názvy ani popisy událostí.
Požadavek
curl -X POST "https://volai.cz/v1/integrations/int_CONNECTION/availability" -H "Authorization: Bearer $VOLAI_API_KEY" -H "Content-Type: application/json" -d '{"calendarId":"primary","from":"2026-09-22T00:00:00+02:00","to":"2026-09-23T00:00:00+02:00","slotMinutes":30,"windows":{"tue":[{"from":"09:00","to":"17:00"}]}}'Odpověď
{"slots":[{"start":"2026-09-22T09:00:00+02:00","end":"2026-09-22T09:30:00+02:00"}],"timezone":"Europe/Prague"}Chybové stavy
- 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 409
calendar_read_onlyKalendář je připojený jen pro čtení (Apple CalDAV odmítl zápis) - v Apple Kalendáři si zkontroluj oprávnění ke sdílenému kalendáři. - 409
calendar_busyNa tomhle připojení právě běží jiná operace (typicky obnova tokenu) - zkus to prosím za chvíli znovu. - 409
calendar_refresh_in_progressPřístup k účtu se právě obnovuje na pozadí - zkus to prosím za chvíli znovu. - 409
calendar_unauthorizedPřipojení ztratilo přístup u poskytovatele - připoj účet v portálu znovu. - 409
calendar_oauth_failedPřihlášení k účtu poskytovatele selhalo - připoj účet v portálu znovu. - 409
calendar_credentials_unavailableUložené přihlašovací údaje připojení se nepodařilo rozšifrovat - připoj účet v portálu znovu; pokud to přetrvává, napiš podpoře. - 409
calendar_invalid_credentialsUložené přihlašovací údaje poskytovatel odmítl - připoj účet v portálu znovu. - 503
calendar_not_configuredKalendářová integrace je na naší straně momentálně nenakonfigurovaná - napiš prosím podpoře. - 502
calendar_provider_errorChyba na straně poskytovatele (Google, Apple) - zkus to prosím za chvíli znovu. - 502
calendar_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to prosím znovu, a pokud to přetrvává, napiš podpoře. - 400
validationNeplatný tvar těla (calendarId, from, to, ...) - tělo je.strict(), neznámé pole ho odmítne; from/to musí mít RFC3339 formát s pásmem. - 400
calendar_invalid_calendarcalendarId neodpovídá žádnému kalendáři z GET .../calendars tohohle připojení. - 400
calendar_too_many_eventsPožadovaný rozsah obsahuje víc událostí, než jedno čtení zvládne přečíst - zkrať rozsah (dny místo týdnů) a zkus to znovu. - 400
calendar_invalid_rangeto musí být později než from a nejvýš 31 dní po něm. - 400
calendar_invalid_timezonetimezone není platná IANA zóna, například Europe/Prague. - 400
calendar_invalid_windowsOkno musí mít from dřív než to ve tvaru HH:MM, nejvýš 4 okna na den a okna ve stejném dni se nesmí překrývat. - 400
calendar_no_windowsŽádný den v týdnu nemá žádné okno dostupnosti - přidej aspoň jedno. - 400
calendar_invalid_rulesNěkteré číslo je mimo povolený rozsah, nebo je minNoticeMinutes delší než celý horizont hledání.
GET/v1/integrations/{id}/events
Povinné calendarId v query. Nejvýš 50 Google událostí nebo Apple událostí a opakovaných sérií, od současnosti. Volitelně search, timeMin, timeMax a pageToken. Časové hranice musí mít pásmo. Pro další stránku použij nextPageToken a stejné filtry včetně pevného timeMin. Apple recurring:true označuje celou sérii; start/end popisují původní výskyt a změna upraví základ série se zachováním jednotlivých výjimek. Neznámý parametr v query tenhle endpoint odmítne chybou 400 validation - na rozdíl od zbytku v1 se přebývající parametry neignorují.
Požadavek
curl "https://volai.cz/v1/integrations/int_CONNECTION/events?calendarId=primary" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"events":[{"calendarId":"primary","externalId":"event1","title":"Meeting","start":"2026-10-05T10:00:00+02:00","end":"2026-10-05T11:00:00+02:00","status":"confirmed","sourceRevision":"revision1"}]}Chybové stavy
- 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 409
calendar_read_onlyKalendář je připojený jen pro čtení (Apple CalDAV odmítl zápis) - v Apple Kalendáři si zkontroluj oprávnění ke sdílenému kalendáři. - 409
calendar_busyNa tomhle připojení právě běží jiná operace (typicky obnova tokenu) - zkus to prosím za chvíli znovu. - 409
calendar_refresh_in_progressPřístup k účtu se právě obnovuje na pozadí - zkus to prosím za chvíli znovu. - 409
calendar_unauthorizedPřipojení ztratilo přístup u poskytovatele - připoj účet v portálu znovu. - 409
calendar_oauth_failedPřihlášení k účtu poskytovatele selhalo - připoj účet v portálu znovu. - 409
calendar_credentials_unavailableUložené přihlašovací údaje připojení se nepodařilo rozšifrovat - připoj účet v portálu znovu; pokud to přetrvává, napiš podpoře. - 409
calendar_invalid_credentialsUložené přihlašovací údaje poskytovatel odmítl - připoj účet v portálu znovu. - 503
calendar_not_configuredKalendářová integrace je na naší straně momentálně nenakonfigurovaná - napiš prosím podpoře. - 502
calendar_provider_errorChyba na straně poskytovatele (Google, Apple) - zkus to prosím za chvíli znovu. - 502
calendar_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to prosím znovu, a pokud to přetrvává, napiš podpoře. - 400
validationNeplatný tvar query (např. timeMax není po timeMin, nebo neznámý parametr) - viz meze u jednotlivých parametrů výš. - 400
calendar_invalid_calendarcalendarId neodpovídá žádnému kalendáři z GET .../calendars tohohle připojení. - 400
calendar_invalid_queryNeplatný pageToken nebo Apple eventId. Použij externalId z čerstvého výpisu událostí a při stránkování zachovej stejné filtry. - 409
calendar_stale_revisionsourceRevision neodpovídá aktuální revizi události - někdo ji mezitím změnil. Načti ji znovu, ukaž uživateli nový stav a nech ho schválit nový návrh. U výpisu Apple událostí znamená totéž, že se seznam mezi stránkami změnil: zahoď pageToken a načti první stránku znovu.
POST/v1/integrations/{id}/events
Založí schůzku v připojeném kalendáři po výslovném schválení uživatele (confirm: true). Pošli přesně jedno z end nebo durationMinutes. idempotencyKey je nepovinný - stejná hodnota podruhé vrátí tutéž událost místo druhého zápisu. Těsně před zápisem se znovu ověří, že termín je stále volný; odpověď je čerstvě přečtená událost, stejný tvar jako GET .../events/{eventId}.
Požadavek
curl -X POST "https://volai.cz/v1/integrations/int_CONNECTION/events" -H "Authorization: Bearer $VOLAI_API_KEY" -H "Content-Type: application/json" -d '{"calendarId":"primary","start":"2026-09-22T09:00:00+02:00","durationMinutes":30,"title":"Meeting","confirm":true}'Odpověď
{
"event": {
"calendarId": "primary",
"externalId": "event1",
"title": "Meeting",
"start": "2026-10-05T10:00:00+02:00",
"end": "2026-10-05T11:00:00+02:00",
"timezone": "Europe/Prague",
"status": "confirmed",
"sourceRevision": "revision1",
"provider": "google-calendar",
"sourceUrl": "https://calendar.google.com/calendar/event?eid=ZXZlbnQx",
"fetchedAt": "2026-09-08T09:00:00.000Z"
}
}Chybové stavy
- 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 409
calendar_read_onlyKalendář je připojený jen pro čtení (Apple CalDAV odmítl zápis) - v Apple Kalendáři si zkontroluj oprávnění ke sdílenému kalendáři. - 409
calendar_busyNa tomhle připojení právě běží jiná operace (typicky obnova tokenu) - zkus to prosím za chvíli znovu. - 409
calendar_refresh_in_progressPřístup k účtu se právě obnovuje na pozadí - zkus to prosím za chvíli znovu. - 409
calendar_unauthorizedPřipojení ztratilo přístup u poskytovatele - připoj účet v portálu znovu. - 409
calendar_oauth_failedPřihlášení k účtu poskytovatele selhalo - připoj účet v portálu znovu. - 409
calendar_credentials_unavailableUložené přihlašovací údaje připojení se nepodařilo rozšifrovat - připoj účet v portálu znovu; pokud to přetrvává, napiš podpoře. - 409
calendar_invalid_credentialsUložené přihlašovací údaje poskytovatel odmítl - připoj účet v portálu znovu. - 503
calendar_not_configuredKalendářová integrace je na naší straně momentálně nenakonfigurovaná - napiš prosím podpoře. - 502
calendar_provider_errorChyba na straně poskytovatele (Google, Apple) - zkus to prosím za chvíli znovu. - 502
calendar_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to prosím znovu, a pokud to přetrvává, napiš podpoře. - 400
validationNeplatný tvar těla - chybí přesně jedno z end/durationMinutes, title je prázdný nebo příliš dlouhý, nebo tělo obsahuje neznámé pole (.strict()). - 400
calendar_invalid_calendarcalendarId neodpovídá žádnému kalendáři z GET .../calendars tohohle připojení. - 400
calendar_invalid_rangeto musí být později než from a nejvýš 31 dní po něm. - 400
calendar_confirmation_requiredconfirm musí být true - bez výslovného schválení uživatele se schůzka nezaloží. - 409
calendar_slot_takenPožadovaný termín teď není volný - načti dostupnost znovu (POST .../availability) a vyber jiný čas. - 503
calendar_unavailableDo kalendáře se teď nejde podívat ani zapsat - zkus to prosím za chvíli znovu.
GET/v1/integrations/{id}/events/{eventId}
Povinné calendarId v query. Čerstvý detail s sourceRevision a fetchedAt. ID v cestě i query URL-enkóduj. U Apple použij jako eventId přesnou hodnotu externalId z výpisu událostí. Jde o neprůhledný identifikátor záznamu CalDAV, ne o iCalendar UID; nesestavuj ho ani nedekóduj.
Požadavek
curl "https://volai.cz/v1/integrations/int_CONNECTION/events/EVENT_ID?calendarId=primary" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{
"event": {
"calendarId": "primary",
"externalId": "event1",
"title": "Meeting",
"start": "2026-10-05T10:00:00+02:00",
"end": "2026-10-05T11:00:00+02:00",
"timezone": "Europe/Prague",
"status": "confirmed",
"sourceRevision": "revision1",
"provider": "google-calendar",
"sourceUrl": "https://calendar.google.com/calendar/event?eid=ZXZlbnQx",
"fetchedAt": "2026-09-08T09:00:00.000Z"
}
}Chybové stavy
- 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 409
calendar_read_onlyKalendář je připojený jen pro čtení (Apple CalDAV odmítl zápis) - v Apple Kalendáři si zkontroluj oprávnění ke sdílenému kalendáři. - 409
calendar_busyNa tomhle připojení právě běží jiná operace (typicky obnova tokenu) - zkus to prosím za chvíli znovu. - 409
calendar_refresh_in_progressPřístup k účtu se právě obnovuje na pozadí - zkus to prosím za chvíli znovu. - 409
calendar_unauthorizedPřipojení ztratilo přístup u poskytovatele - připoj účet v portálu znovu. - 409
calendar_oauth_failedPřihlášení k účtu poskytovatele selhalo - připoj účet v portálu znovu. - 409
calendar_credentials_unavailableUložené přihlašovací údaje připojení se nepodařilo rozšifrovat - připoj účet v portálu znovu; pokud to přetrvává, napiš podpoře. - 409
calendar_invalid_credentialsUložené přihlašovací údaje poskytovatel odmítl - připoj účet v portálu znovu. - 503
calendar_not_configuredKalendářová integrace je na naší straně momentálně nenakonfigurovaná - napiš prosím podpoře. - 502
calendar_provider_errorChyba na straně poskytovatele (Google, Apple) - zkus to prosím za chvíli znovu. - 502
calendar_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to prosím znovu, a pokud to přetrvává, napiš podpoře. - 400
validationcalendarId v query je povinné a smí mít nejvýš 500 znaků. - 400
calendar_invalid_calendarcalendarId neodpovídá žádnému kalendáři z GET .../calendars tohohle připojení. - 400
calendar_invalid_queryNeplatný pageToken nebo Apple eventId. Použij externalId z čerstvého výpisu událostí a při stránkování zachovej stejné filtry.
PATCH/v1/integrations/{id}/events/{eventId}
Změna názvu (title), začátku (start) nebo konce (end). Časy RFC3339 s pásmem, nebo celodenní YYYY-MM-DD s výlučným koncem. Apple čas bez pásma lze poslat pouze při zachování události, která již pásmo nemá. Vyžaduje souhlas a aktuální revizi; vrací ověřený detail události.
Požadavek
curl -X PATCH "https://volai.cz/v1/integrations/int_CONNECTION/events/EVENT_ID" -H "Authorization: Bearer $VOLAI_API_KEY" -H "Content-Type: application/json" -d '{"calendarId":"primary","sourceRevision":"revision1","patch":{"title":"Updated meeting"},"confirm":true}'Odpověď
{
"event": {
"calendarId": "primary",
"externalId": "event1",
"title": "Updated meeting",
"start": "2026-10-05T10:00:00+02:00",
"end": "2026-10-05T11:00:00+02:00",
"timezone": "Europe/Prague",
"status": "confirmed",
"sourceRevision": "revision1",
"provider": "google-calendar",
"sourceUrl": "https://calendar.google.com/calendar/event?eid=ZXZlbnQx",
"fetchedAt": "2026-09-08T09:00:00.000Z"
}
}Chybové stavy
- 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 409
calendar_read_onlyKalendář je připojený jen pro čtení (Apple CalDAV odmítl zápis) - v Apple Kalendáři si zkontroluj oprávnění ke sdílenému kalendáři. - 409
calendar_busyNa tomhle připojení právě běží jiná operace (typicky obnova tokenu) - zkus to prosím za chvíli znovu. - 409
calendar_refresh_in_progressPřístup k účtu se právě obnovuje na pozadí - zkus to prosím za chvíli znovu. - 409
calendar_unauthorizedPřipojení ztratilo přístup u poskytovatele - připoj účet v portálu znovu. - 409
calendar_oauth_failedPřihlášení k účtu poskytovatele selhalo - připoj účet v portálu znovu. - 409
calendar_credentials_unavailableUložené přihlašovací údaje připojení se nepodařilo rozšifrovat - připoj účet v portálu znovu; pokud to přetrvává, napiš podpoře. - 409
calendar_invalid_credentialsUložené přihlašovací údaje poskytovatel odmítl - připoj účet v portálu znovu. - 503
calendar_not_configuredKalendářová integrace je na naší straně momentálně nenakonfigurovaná - napiš prosím podpoře. - 502
calendar_provider_errorChyba na straně poskytovatele (Google, Apple) - zkus to prosím za chvíli znovu. - 502
calendar_invalid_provider_responsePoskytovatel vrátil neočekávanou odpověď - zkus to prosím znovu, a pokud to přetrvává, napiš podpoře. - 400
validationNeplatný tvar těla (calendarId, sourceRevision, patch, confirm) - tělo je.strict(), neznámé pole ho odmítne. - 400
calendar_invalid_calendarcalendarId neodpovídá žádnému kalendáři z GET .../calendars tohohle připojení. - 400
calendar_invalid_queryNeplatný pageToken nebo Apple eventId. Použij externalId z čerstvého výpisu událostí a při stránkování zachovej stejné filtry. - 400
calendar_provider_mismatchPřipojení mezitím změnilo poskytovatele, takže návrh z předchozího čtení k němu nepatří - načti událost znovu a nech schválit nový návrh. - 400
calendar_invalid_patchpatch má neplatný tvar nebo neznámé pole - povolené jsou jen title, start a end; start/end musí mít pásmo (nebo být celodenní YYYY-MM-DD s pozdějším koncem). - 400
calendar_confirmation_requiredconfirm musí být true - bez potvrzení uživatele se událost nezmění. - 409
calendar_stale_revisionsourceRevision neodpovídá aktuální revizi události - někdo ji mezitím změnil. Načti ji znovu, ukaž uživateli nový stav a nech ho schválit nový návrh. U výpisu Apple událostí znamená totéž, že se seznam mezi stránkami změnil: zahoď pageToken a načti první stránku znovu. - 502
calendar_verification_failedZápis proběhl, ale zpětné čtení u poskytovatele se nepodařilo ověřit - načti událost znovu a zkontroluj výsledek.
POST/v1/integrations/{id}/events/{eventId}/propose
Připraví návrh změny názvu, začátku nebo konce události BEZ zápisu k poskytovateli (patch a sourceRevision jako u PATCH .../events/{eventId}, ale bez confirm) - čistá funkce nad uloženým typem integrace, nikdy nevolá poskytovatele. Ukaž návrh (proposal.patch) uživateli k výslovnému schválení a teprve pak pošli PATCH .../events/{eventId} se stejnými hodnotami a confirm: true.
Požadavek
curl -X POST "https://volai.cz/v1/integrations/int_CONNECTION/events/EVENT_ID/propose" -H "Authorization: Bearer $VOLAI_API_KEY" -H "Content-Type: application/json" -d '{"calendarId":"primary","sourceRevision":"revision1","patch":{"title":"Updated meeting"}}'Odpověď
{"proposal":{"calendarId":"primary","externalId":"EVENT_ID","sourceRevision":"revision1","patch":{"title":"Updated meeting"},"provider":"google-calendar","proposedAt":"2026-09-08T09:00:00.000Z","requiresExplicitConfirmation":true}}Chybové stavy
- 400
validationNeplatný tvar těla -calendarId/sourceRevisionchybí, nebopatchobsahuje jiné pole nežtitle/start/end. - 404
calendar_not_foundIntegrace ani kalendář s tímhle ID neexistuje, nebo nepatří tvému účtu. - 400
calendar_unsupportedPřipojení není kalendář (fakturace), tenhle endpoint pro něj neplatí. - 400
calendar_invalid_patchpatchmá neplatný tvar -start/endmusí mít pásmo (nebo být celodenníYYYY-MM-DDs pozdějším koncem).
Faktury z Fakturoidu a ABRA Flexi
Účet nejdřív připoj v Připojení. Fakturoid používá OAuth v prohlížeči; pokud máš přístup k fakturám více firem, vybereš jednu výslovně. ABRA Flexi potřebuje HTTPS server, identifikátor firmy a přihlašovací údaje API uživatele; doménu serveru musí povolit provozovatel volai. Přihlašovací údaje patří do portálu. Rozhraní čte vydané faktury, nevystavuje je ani neoznačuje jako zaplacené.
Chyby fakturačních endpointů mají prefix integration_ a nesou cause i action jako každá chyba API. Podle příčiny: account znamená připojit účet znovu v Připojení, bez toho nemá smysl opakovat; busy (409) zopakuj za pár sekund, tvoje data jsou v pořádku; service (400, 502 nebo 503) je u nás nebo u poskytovatele - zopakuj později a stav faktury zatím ber jako NEZNÁMÝ; request (400) oprav v dotazu. Neúspěšné načtení nikdy nenahrazuj dřívějším tvrzením o úhradě ani tvrzením volajícího.
GET/v1/integrations/{id}/invoices
Volitelný search (nejvýš 100 znaků) hledá přímo u poskytovatele. Vrací prvních 40 výsledků z Fakturoidu nebo 50 z ABRA Flexi. Pro nalezení starších faktur zpřesni dotaz; odpověď nemá stránkovací token.
Požadavek
curl "https://volai.cz/v1/integrations/int_CONNECTION/invoices?search=2026-0001" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"invoices":[{"externalId":"123","label":"2026-0001","status":"unpaid","amountDueMinor":1210000,"currency":"CZK","dueDate":"2026-09-30","sourceRevision":"v3"}]}Chybové stavy
- 400
validationParametr search je delší než 100 znaků, nebo dotaz obsahuje neznámý parametr (třeba limit) - kalendářové a fakturační endpointy neznámé parametry odmítají, jinde ve v1 se ignorují. - 404
integration_not_foundPřipojení s tímto id na účtu není; u detailu také když poskytovatel fakturu s tímto invoiceId nezná (u výpisu 404 od poskytovatele přijde jako provider_error). - 400
integration_unsupportedPřipojení není fakturační (např. kalendář) - faktury umí jen Fakturoid a ABRA Flexi. - 400
integration_invalid_providerServer ABRA Flexi uložený u připojení není v seznamu povolených hostitelů provozovatele. Napiš podpoře. - 409
integration_busyPřihlašovací údaje připojení se právě obnovují a záznam se mezitím změnil - zopakuj požadavek za pár sekund. - 409
integration_refresh_in_progressJiný požadavek právě obnovuje token připojení - zopakuj požadavek za pár sekund. - 409
integration_unauthorizedPoskytovatel odmítl uložené přihlašovací údaje (HTTP 401) - připoj účet znovu v Připojení. - 409
integration_oauth_failedObnovení tokenu Fakturoidu selhalo - připoj účet znovu v Připojení. - 409
integration_credentials_unavailableUložené přihlašovací údaje nejde dešifrovat - připoj účet znovu v Připojení. - 409
integration_invalid_credentialsUložené přihlašovací údaje nemají očekávaný tvar (chybí token, slug nebo uživatel API) - připoj účet znovu v Připojení. - 503
integration_not_configuredProvozovatel nemá nastavené klíče poskytovatele (např. Fakturoid OAuth) - nic neplatíš, napiš podpoře. - 502
integration_provider_errorPoskytovatel odpověděl chybou (včetně HTTP 403) nebo neodpověděl - zopakuj požadavek později; stav faktury zatím ber jako neznámý. - 502
integration_invalid_provider_responsePoskytovatel vrátil odpověď v nečekaném tvaru - zopakuj požadavek později; když to trvá, napiš podpoře. - 400
integration_invalid_queryParametr search obsahuje zpětná lomítka, řídicí znaky nebo míchané uvozovky, které ABRA Flexi ve vyhledávání nepřijme - zjednoduš dotaz.
GET/v1/integrations/{id}/invoices/{invoiceId}
Před tvrzením o úhradě načti čerstvý důkaz od poskytovatele. amountDueMinor je celé číslo v nejmenších jednotkách dané měny; null znamená, že zůstatek nebyl doložen. status může být unknown. Neznámý stav ani chybějící částka nejsou důkazem úhrady. Detail obsahuje provider, sourceUrl, fetchedAt a evidence: provider_response. invoiceId URL-enkóduj.
Požadavek
curl "https://volai.cz/v1/integrations/int_CONNECTION/invoices/123" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"invoice":{"externalId":"123","status":"unpaid","amountDueMinor":1210000,"currency":"CZK","dueDate":"2026-09-30","sourceRevision":"v3","provider":"fakturoid","fetchedAt":"2026-09-08T09:00:00.000Z","sourceUrl":"https://app.fakturoid.cz/api/v3/accounts/firma/invoices/123.json","evidence":"provider_response"}}Chybové stavy
- 400
validationinvoiceId v cestě chybí nebo přesahuje 500 znaků. - 404
integration_not_foundPřipojení s tímto id na účtu není; u detailu také když poskytovatel fakturu s tímto invoiceId nezná (u výpisu 404 od poskytovatele přijde jako provider_error). - 400
integration_unsupportedPřipojení není fakturační (např. kalendář) - faktury umí jen Fakturoid a ABRA Flexi. - 400
integration_invalid_providerServer ABRA Flexi uložený u připojení není v seznamu povolených hostitelů provozovatele. Napiš podpoře. - 409
integration_busyPřihlašovací údaje připojení se právě obnovují a záznam se mezitím změnil - zopakuj požadavek za pár sekund. - 409
integration_refresh_in_progressJiný požadavek právě obnovuje token připojení - zopakuj požadavek za pár sekund. - 409
integration_unauthorizedPoskytovatel odmítl uložené přihlašovací údaje (HTTP 401) - připoj účet znovu v Připojení. - 409
integration_oauth_failedObnovení tokenu Fakturoidu selhalo - připoj účet znovu v Připojení. - 409
integration_credentials_unavailableUložené přihlašovací údaje nejde dešifrovat - připoj účet znovu v Připojení. - 409
integration_invalid_credentialsUložené přihlašovací údaje nemají očekávaný tvar (chybí token, slug nebo uživatel API) - připoj účet znovu v Připojení. - 503
integration_not_configuredProvozovatel nemá nastavené klíče poskytovatele (např. Fakturoid OAuth) - nic neplatíš, napiš podpoře. - 502
integration_provider_errorPoskytovatel odpověděl chybou (včetně HTTP 403) nebo neodpověděl - zopakuj požadavek později; stav faktury zatím ber jako neznámý. - 502
integration_invalid_provider_responsePoskytovatel vrátil odpověď v nečekaném tvaru - zopakuj požadavek později; když to trvá, napiš podpoře.
Objednávky Na klíč (Done for you)
Na klíč postaví funkčního agenta z popisu obyčejným jazykem místo ruční konfigurace v portálu. POST /v1/setup-orders proběhne jako jeden tah rozhovoru: popiš agenta a poradce buď vrátí naceněnou nabídku (quoted), požádá o potvrzení vlastních položek nad prahem (awaiting_confirmation), nebo automatizované nastavení zamítne u případu, který na ně nesedí (declined). Cenu vždy počítá kód z pevného katalogu, nikdy ne model - poradce jen vybírá balíček, doplňky a vlastní položky. Zaplacení nabídky (POST .../checkout, Stripe Checkout session za zřízení plus první dobití kreditu) spustí stavbu; volai postaví agenta ručně a objednávka prochází paid -> building -> ready. Ve stavu ready zavolej na přidělené číslo a vyzkoušej ho, pošli zprávou požadavek na úpravu (revision), pak POST .../launch pro spuštění. GET .../{id} vždy nese nextStep - anglickou větu, co dělat dál pro aktuální stav (REST mluví vždy anglicky).
POST/v1/setup-orders
Jeden tah: popiš agenta, kterého potřebuješ, v brief (aspoň 20 znaků), a dostaneš zpátky nabídku nebo žádost o potvrzení vlastních položek. locale řídí jazyk rozhovoru s poradcem a případných e-mailů k téhle objednávce (výchozí en) - jazyk TÉHLE odpovědi to nemění, REST mluví vždy anglicky. contactPhone se připojí k briefu jako poznámka pro volai, nevaliduje se. Strop 5 nových objednávek na účet za den. Když tah poradce selže (advisor_unavailable, advisor_no_quote), objednávka už vznikla a započítala se do stropu - dohledej ji přes GET /v1/setup-orders a další pokus pošli přes POST .../messages, ne opakovaným voláním tohohle endpointu. Bez Idempotency-Key: každé volání zakládá NOVOU objednávku, jedinou pojistkou je strop 5/den - po timeoutu si nejdřív ověř stav přes GET /v1/setup-orders.
Požadavek
curl -X POST https://volai.cz/v1/setup-orders \
-H "Authorization: Bearer $VOLAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"brief":"Reception for a Prague fitness studio, Czech and English, takes bookings and answers pricing questions.","locale":"en"}'201 Created
{"order":{"id":"so_AbCdEf123456","status":"quoted","nextStep":"Start the checkout to pay the setup fee and begin the build.","locale":"en","source":"api","createdAt":1757980800000,"updatedAt":1757980810000,"revisionsUsed":0,"extraRevisionHal":49000,"extraRevisionsCharged":0,"revisionsIncluded":2,"quote":{"lines":[{"kind":"package","id":"provozovna","label":"Business","quantity":1,"unitHal":299000,"totalHal":299000},{"kind":"addon","id":"calendar","label":"Calendar booking","quantity":1,"unitHal":99000,"totalHal":99000}],"setupNetHal":398000,"needsConfirmation":false,"revisionsIncluded":2,"monthly":{"callsPerDay":20,"avgMinutes":3,"totalMonthlyHal":542500,"callMinutes":1800}},"selection":{"segment":"provozovna","packageId":"provozovna","addons":[{"id":"calendar","quantity":1}],"customItems":[],"industry":"fitness studio","agentLanguages":["cs","en"],"callsPerDay":20,"avgMinutes":3,"cannotDo":[],"assumptions":["Business hours 9am-6pm"]},"messages":[{"role":"user","content":"Reception for a Prague fitness studio...","at":1757980800000},{"role":"assistant","content":"Here is your quote for a location agent...","at":1757980810000}]}}Chybové stavy
- 400
validationTělo nesedí na schéma (briefchybí nebo má míň než 20 znaků,contactPhoneje moc dlouhý, nebolocalenenícs/en). - 422
advisor_no_quotePoradce se rozhodl položit otázku, ale jednorázový tah vyžaduje nabídku nebo zamítnutí - zkus to znovu nebo dopiš do briefu víc podrobností. - 503
advisor_unavailablePoradce je dočasně nedostupný (chybí API klíč, výpadek sítě, nebo model odmítl odpovědět) - zkus to za chvíli znovu. - 503
setup_orders_disabledNa klíč je dočasně vypnuté pro celý účet; už zaplacené objednávky pokračují normálně dál.
GET/v1/setup-orders
Objednávky Na klíč tohoto účtu, bez stránkování.
Požadavek
curl "https://volai.cz/v1/setup-orders" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"orders":[{"id":"so_AbCdEf123456","status":"quoted","nextStep":"Start the checkout to pay the setup fee and begin the build.","locale":"en","source":"api","createdAt":1757980800000,"updatedAt":1757980810000,"revisionsUsed":0,"extraRevisionHal":49000,"extraRevisionsCharged":0,"messages":[]}]}GET/v1/setup-orders/{id}
Detail objednávky včetně VŠECH zpráv v rozhovoru (i odpovědí majitele od volai) a pole nextStep.
Požadavek
curl "https://volai.cz/v1/setup-orders/so_AbCdEf123456" -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"order":{"id":"so_AbCdEf123456","status":"ready","nextStep":"Call the number, then send a message for changes or launch.","locale":"en","source":"api","createdAt":1757980800000,"updatedAt":1758153600000,"readyAt":1758153600000,"revisionsUsed":0,"extraRevisionHal":49000,"extraRevisionsCharged":0,"revisionsIncluded":2,"agentId":"ag_XyZ987","numberE164":"+420999123456","messages":[{"role":"user","content":"Reception for a Prague fitness studio...","at":1757980800000},{"role":"owner","content":"Your agent is ready - give it a call.","at":1758153600000}]}}Chybové stavy
- 404
setup_order_not_foundObjednávka s tímhleidna účtu neexistuje.
POST/v1/setup-orders/{id}/messages
Pošle zprávu poradci. Dokud je objednávka quoted, nová zpráva může spustit další tah poradce, který nabídku přepíše - pokud zrovna neběží otevřený checkout (checkout_open), který nabídku zmrazí, dokud ta Stripe session nevyprší nebo se nevyužije. V ostatních stavech (ready, paid, building, revision) se zpráva jen zapíše pro tým volai; poslání zprávy ve stavu ready přesune objednávku do revision. Kola úprav v ceně balíčku (order.quote.revisionsIncluded, už vyčerpaná order.revisionsUsed) jsou zdarma; po jejich vyčerpání se za další dokončené kolo strhne z kreditu 490 Kč bez DPH jako pohyb setup_revision.
Požadavek
curl -X POST https://volai.cz/v1/setup-orders/so_AbCdEf123456/messages \
-H "Authorization: Bearer $VOLAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message":"Can it also speak German?"}'Odpověď
{"order":{"id":"so_AbCdEf123456","status":"quoted","nextStep":"Start the checkout to pay the setup fee and begin the build.","locale":"en","source":"api","createdAt":1757980800000,"updatedAt":1757981200000,"revisionsUsed":0,"extraRevisionHal":49000,"extraRevisionsCharged":0,"messages":[{"role":"user","content":"Reception for a Prague fitness studio...","at":1757980800000},{"role":"assistant","content":"Here is your quote...","at":1757980810000},{"role":"user","content":"Can it also speak German?","at":1757981190000},{"role":"assistant","content":"Updated the quote to add German.","at":1757981200000}]}}Chybové stavy
- 400
validationmessagechybí, je prázdné, nebo přesahuje 2000 znaků. - 404
setup_order_not_foundObjednávka s tímhleidna účtu neexistuje. - 409
order_closedObjednávka jelaunchednebocancelled- další zprávy už nepřijímá. - 409
turn_in_progressNa tuhle objednávku právě běží jiný požadavek - počkej, až doběhne, a zkus to znovu. - 409
checkout_openPro nabídku téhle objednávky právě běží otevřený checkout - počkej, až vyprší nebo se dokončí, než pošleš zprávu, která by mohla změnit cenu. - 422
advisor_no_quotePoradce se rozhodl položit otázku, ale jednorázový tah vyžaduje nabídku nebo zamítnutí - zkus to znovu nebo dopiš do briefu víc podrobností. - 503
advisor_unavailablePoradce je dočasně nedostupný (chybí API klíč, výpadek sítě, nebo model odmítl odpovědět) - zkus to za chvíli znovu.
POST/v1/setup-orders/{id}/checkout
Vytvoří Stripe Checkout session na naceněné zřízení plus první dobití kreditu (creditCzk, jedna z podporovaných částek dobití účtu). Jen ze stavu quoted, a jen vlastník objednávky. Success i cancel přesměrování míří zpátky na stránku objednávky v jazyce ROZHOVORU (order.locale), ne nutně v jazyce tohohle požadavku.
Požadavek
curl -X POST https://volai.cz/v1/setup-orders/so_AbCdEf123456/checkout \
-H "Authorization: Bearer $VOLAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"creditCzk":500}'Odpověď
{"url":"https://checkout.stripe.com/c/pay/cs_test_...","sessionId":"cs_test_a1B2c3D4"}Chybové stavy
- 400
validationTělo nesedí na schéma (creditCzknení celé číslo). - 400
invalid_amountcreditCzknení jedna z podporovaných částek dobití účtu. - 400
billing_address_requiredÚčet ještě nemá uloženou kompletní fakturační adresu - doplň ji nejdřív (PUT /v1/account/billing). - 404
setup_order_not_foundObjednávka s tímhleidna účtu neexistuje. - 409
checkout_openPro nabídku téhle objednávky právě běží otevřený checkout - počkej, až vyprší nebo se dokončí, než pošleš zprávu, která by mohla změnit cenu. - 409
invalid_transitionObjednávka neníquoted, nebo jí chybí nabídka - checkout se otevírá jen z naceněné objednávky. - 409
quote_pending_confirmationNabídka ještě čeká, až volai potvrdí vlastní položky (awaiting_confirmation), teprve pak se checkout otevře. - 409
turn_in_progressNa tuhle objednávku právě běží jiný požadavek - počkej, až doběhne, a zkus to znovu. - 503
setup_orders_disabledNa klíč je dočasně vypnuté pro celý účet; už zaplacené objednávky pokračují normálně dál.
POST/v1/setup-orders/{id}/launch
Spustí hotového agenta (ready -> launched) - jediný přechod, který dělá zákazník sám; všechny ostatní (start stavby, ready, zrušení) dělá tým volai.
Požadavek
curl -X POST https://volai.cz/v1/setup-orders/so_AbCdEf123456/launch -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"order":{"id":"so_AbCdEf123456","status":"launched","nextStep":"Your agent is live.","locale":"en","source":"api","createdAt":1757980800000,"updatedAt":1758160000000,"readyAt":1758153600000,"launchedAt":1758160000000,"revisionsUsed":0,"extraRevisionHal":49000,"extraRevisionsCharged":0,"agentId":"ag_XyZ987","numberE164":"+420999123456","messages":[]}}Chybové stavy
- 404
setup_order_not_foundObjednávka s tímhleidna účtu neexistuje. - 409
invalid_transitionObjednávka neníready- zatím není co spouštět.
POST/v1/setup-orders/{id}/cancel
Zruší nezaplacenou objednávku (draft, quoted, awaiting_confirmation nebo declined -> cancelled). Zaplacenou objednávku tímhle endpointem zrušit nejde - kontaktuj volai.
Požadavek
curl -X POST https://volai.cz/v1/setup-orders/so_AbCdEf123456/cancel -H "Authorization: Bearer $VOLAI_API_KEY"Odpověď
{"order":{"id":"so_AbCdEf123456","status":"cancelled","nextStep":"This order was cancelled.","locale":"en","source":"api","createdAt":1757980800000,"updatedAt":1757981500000,"revisionsUsed":0,"extraRevisionHal":49000,"extraRevisionsCharged":0,"messages":[]}}Chybové stavy
- 404
setup_order_not_foundObjednávka s tímhleidna účtu neexistuje. - 409
invalid_transitionObjednávku nejde zrušit z jejího aktuálního stavu (už je zaplacená, nebo je už uzavřená).
Changelog
Strojově čitelný changelog veřejného rozhraní - REST v1 i MCP. Jeden dokument na jednu URL (žádné query parametry, filtruj si sám nad vráceným polem entries), proto ho jde bezpečně veřejně cachovat. Stejná data jako /en/changelog v portálu a MCP nástroj get_changelog. Kanonický zdroj pravdy je jeden soubor (content/changelog.json) - odsud se generují všechny pohledy.
GET/v1/changelog
Vrátí aktuální verzi rozhraní a VŠECHNY záznamy changelogu (nejnovější první), anglicky bez ohledu na jazyk účtu. version/technical jsou null, když záznam neměl (staré položky bez verze, nebo bez technického detailu). url je kanonická anglická cesta s kotvou na id.
Požadavek
curl https://volai.cz/v1/changelogOdpověď
{
"version": "1.34.2",
"entries": [
{
"id": "parita-vlna-a",
"date": "2026-09-08",
"version": "1.5.0",
"areas": ["api", "mcp"],
"audience": "developer",
"breaking": false,
"title": "Account, call annotations, tool test, draft rollback, numbers waitlist and more",
"body": "See /en/docs/api and /en/docs/mcp for the new endpoints and tools.",
"technical": null,
"url": "https://volai.cz/en/changelog#parita-vlna-a"
}
]
}Chybové stavy
- 429
rate_limitedVyčerpal jsi limit 30 požadavků za minutu z jedné IP adresy (bez API klíče se limituje podle IP, ne podle účtu).
Hlavička x-volai-version
Úplně KAŽDÁ odpověď v1 (úspěšná i chybová, včetně 401/429, binárních rout jako nahrávka hovoru a GET /openapi.json) nese hlavičku x-volai-version s aktuální verzí rozhraní. Liší-li se od poslední verze, kterou jsi viděl, zavolej GET /v1/changelog (nebo MCP get_changelog) a zjisti, co je nového - stejné doporučení dostává MCP klient přímo v SERVER_INSTRUCTIONS serveru.
x-volai-version: 1.34.2MCP protějšek je nástroj get_changelog (READ_ONLY) - stejná data, navíc si umí filtrovat podle since (datum nebo verze - jen novější záznamy), area a omezit počet limit přímo na serveru.
Související
MCP server
Připojení Claude Code, Codex CLI, Codex desktopu, Cursoru a dalších AI editorů.
Hlasový agent
Systémový prompt, nástroje, přepojení na člověka, nahrávky a zapsané údaje z hovoru.
Webhooky
Události, zapsané údaje v těle, ověření podpisu, opakování při chybě.
SIP
Vlastní softphone, SIP údaje, odchozí přes SIP klienta.
Vlastní agent
Napojení cizí platformy (ElevenLabs, Asterisk...) - bez agentní přirážky.