Validate a flow graph
import MoreVoice from "@morevoice/sdk";
const mv = new MoreVoice(); // MOREVOICE_API_KEY from the environment
const flowValidation = await mv.flows.validate({ graph: { kind: "voice", nodes: [ { key: "start", transitions: [ { condition: { kind: "always", }, next: null, }, ], type: "start", }, ], },});console.log(flowValidation);from morevoice import MoreVoice
client = MoreVoice() # MOREVOICE_API_KEY from the environment
flow_validation = client.flows.validate({ "graph": { "kind": "voice", "nodes": [ { "key": "start", "transitions": [ { "condition": { "kind": "always", }, "next": None, }, ], "type": "start", }, ], },})print(flow_validation)curl -X POST https://api.morevoice.ai/v1/flows/validate \ -H "Authorization: Bearer $MOREVOICE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "graph": { "kind": "voice", "nodes": [ { "key": "start", "transitions": [ { "condition": { "kind": "always" }, "next": null } ], "type": "start" } ] }}'Checks a graph without saving it: the errors that would block publishing, plus warnings and tasks. A malformed graph answers 400.
Try it in the API playground with a test-mode key.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”The API version to use for this request. Defaults to the version the API key is pinned to.
Example
2026-11-01A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
Example
5f0c1e8a-7b2d-4c3e-9f1a-2b6d8e4c0a17Request Bodyrequired
Section titled “Request Bodyrequired”A graph to validate without saving it.
object
The graph to check (kind is required here).
object
Must be the flow’s kind (default: the flow’s).
A flow node to write (v1 node schema). Settings you leave out keep their stored values, or the type’s defaults for a new node.
object
Type ai_agent: A free conversation step with a goal: the AI talks until a transition matches.
object
The assistant’s tools usable in this step (by name).
Variables the AI gathers in this step.
object
Answer from these knowledge-base documents.
object
Type api: Call an HTTP API during the call; map the response to variables.
object
How the request authenticates. Reference credentials as {{secrets.NAME}} rather than in clear.
object
Api_key / hmac (required): the header name.
Basic (required).
Hmac (required): the signing secret.
Bearer (required).
Basic (required).
Api_key (required).
The body template ({{templates}} JSON-escaped when body_type is json).
object
object
Response fields → variables.
object
E.g. data.items[0].name
The URL ({{templates}} allowed).
Said while waiting.
Type decision: Branch by rules on variables (no AI).
object
Type dtmf_menu: A keypad menu.
object
Callers may say the option instead of pressing it.
A audio asset ID (aud_…).
object
Also the spoken choice.
Type end: End the call.
object
Makes the node reachable from anywhere in the call when its condition matches.
object
Return: back to where the caller was; stay: continue here; goto: follow this node’s transitions.
Intent, keyword or dtmf.
object
No_response (required): seconds of silence.
Intent (required): what the caller means.
Dtmf (required): keypad digits — 1, *, # or a range 1-3.
Intent: example phrasings.
Intent: the AI decides what the caller means · keyword · variable rules (no AI) · dtmf keys · always (right after the node) · no_response · outcome of an action · else (the fallback, last).
Keyword: any (default) or all of the phrases.
Variable (required): all or any of the rules.
Outcome (required): the result of an action or collect node.
Keyword (required): phrases the caller says; a trailing * matches a prefix.
No_response: in a row (default 1).
Higher wins when several global nodes match.
Where in the call the trigger listens.
object
Only / except: the nodes it applies to (or not).
Type hours: Branch on opening hours: open, closed or holiday.
object
Extra closed days, YYYY-MM-DD.
Closed on Israeli holidays (the holiday outcome).
Exceptional open days, YYYY-MM-DD.
Closed on Shabbat (Israel).
IANA time zone (default: the flow’s).
object
0 = Sunday … 6 = Saturday.
HH:MM
HH:MM
Type integration: Run a connected CRM or calendar action during the call (look the caller up, add a note, create a task): success, not found or error.
object
The action, e.g. crm.lookup_contact, crm.add_note, crm.create_task.
The action’s arguments by name ({{templates}} allowed).
object
The connected integration account (Settings › Integrations). Integration connections have no API object (and no public ID prefix) yet: the id is the dashboard’s.
Result fields → variables (e.g. contacts[0].name → customer_name).
object
E.g. data.items[0].name
Said while the action runs.
Type internal: a node of a type outside the v1 schema (SMS, e-mail, voicemail, callbacks, agent-script steps…). Read-only: when you write the draft, the stored node is kept; only its transitions’ next may change.
object
object
Type kb_answer: Answer from the knowledge base.
object
Empty: the whole knowledge base.
The node’s key: your stable identifier, unique in the graph.
Default: laid out automatically.
object
Type post_api: Call an HTTP API after the call.
object
How the request authenticates. Reference credentials as {{secrets.NAME}} rather than in clear.
object
Api_key / hmac (required): the header name.
Basic (required).
Hmac (required): the signing secret.
Bearer (required).
Basic (required).
Api_key (required).
The body template ({{templates}} JSON-escaped when body_type is json).
object
object
Response fields → variables.
object
E.g. data.items[0].name
The URL ({{templates}} allowed).
Said while waiting.
Type post_integration: Run a connected CRM action after the call (add a note, create a follow-up task).
object
The action, e.g. crm.lookup_contact, crm.add_note, crm.create_task.
The action’s arguments by name ({{templates}} allowed).
object
The connected integration account (Settings › Integrations). Integration connections have no API object (and no public ID prefix) yet: the id is the dashboard’s.
Result fields → variables (e.g. contacts[0].name → customer_name).
object
E.g. data.items[0].name
Type question: Ask for one detail, validate it and store it in a variable.
object
A audio asset ID (aud_…).
Read the answer back for confirmation.
Accept the answer on the keypad too.
object
object
The variable the answer is stored in.
Type say: Say an exact line, or one the AI rephrases.
object
An uploaded prompt played instead of speech.
Type set_variable: Set variables.
object
object
A literal or a {{template}}.
Type start: Where every call begins: the greeting.
object
Type transfer: Transfer the call to a queue, a number, another flow or a SIP address.
object
A assistant ID (asst_…).
A phone number, or a SIP URI for mode sip.
A flow ID (flow_…).
A queue ID (q_…).
Warm transfer: whisper an AI summary to the receiving side first.
The node’s outputs, in priority order. Default: the type’s standard outputs (a new node) or the stored ones.
A node output: when its condition matches, the call moves to next.
object
When a transition is taken: kind and that kind’s fields.
object
No_response (required): seconds of silence.
Intent (required): what the caller means.
Dtmf (required): keypad digits — 1, *, # or a range 1-3.
Intent: example phrasings.
Intent: the AI decides what the caller means · keyword · variable rules (no AI) · dtmf keys · always (right after the node) · no_response · outcome of an action · else (the fallback, last).
Keyword: any (default) or all of the phrases.
Variable (required): all or any of the rules.
Outcome (required): the result of an action or collect node.
Keyword (required): phrases the caller says; a trailing * matches a prefix.
No_response: in a row (default 1).
The transition’s key (an output port), unique in the node. Default: a new key.
The node type. Its settings are under the property of the same name (type: "say" → say: {…}).
Merged with the stored settings.
object
Persona and global instructions, combined with the assistant’s prompt.
object
Off: keypad only; keywords: spoken choices matched to the options; smart: keywords, then an AI routing check.
object
Inline: the reply decides the transition; classifier: a separate fast check.
Default: the stored variables.
object
A sample value for simulations and tests.
Redacted in logs, metrics and analytics.
Where its value comes from: the contact, a pre-call API, collected in the call, an API, set by a node, the system, or extracted after the call.
Example
{ "graph": { "kind": "voice", "nodes": [ { "key": "start", "transitions": [ { "condition": { "kind": "always" }, "next": null } ], "type": "start" } ] }}Responses
Section titled “Responses”OK
What would block publishing (errors) and what deserves a look (warnings, tasks).
object
object
A stable code, e.g. unreachable, dead_end, missing_else, undefined_var.
Errors block publishing; warnings and tasks do not.
No errors: it can be published.
Example
{ "issues": [ { "code": "dead_end", "field": null, "message": "This node has an output that leads nowhere.", "node_key": "ask_id", "severity": "error", "transition_key": "t_fail" } ], "object": "flow_validation", "valid": false}The request is invalid: a parameter is missing, malformed or unknown, or the version header is unknown.
Every /v1 error.
object
object
A stable, machine-readable code from the error-code catalogue.
Structured context, e.g. required_scope or the compliance verdict.
object
A link to the documentation of this code.
A human-readable explanation. Do not parse it.
The request parameter the error relates to, e.g. to or metadata[order_id].
The X-Request-Id of this request. Quote it when you contact support.
The category of the error.
Example
{ "error": { "code": "parameter_missing", "doc_url": "https://docs.morevoice.ai/api/errors#parameter-missing", "message": "Missing required parameter: to.", "param": "to", "request_id": "req_7Hk2LmN9pQ4rS6tV8wX0yZ", "type": "invalid_request_error" }}Headers
Section titled “Headers”The request’s ID (req_…). Quote it when you contact support.
No valid API key was sent.
Every /v1 error.
object
object
A stable, machine-readable code from the error-code catalogue.
Structured context, e.g. required_scope or the compliance verdict.
object
A link to the documentation of this code.
A human-readable explanation. Do not parse it.
The request parameter the error relates to, e.g. to or metadata[order_id].
The X-Request-Id of this request. Quote it when you contact support.
The category of the error.
Example
{ "error": { "code": "invalid_api_key", "doc_url": "https://docs.morevoice.ai/api/errors#invalid-api-key", "message": "Invalid API key.", "request_id": "req_7Hk2LmN9pQ4rS6tV8wX0yZ", "type": "authentication_error" }}Headers
Section titled “Headers”The request’s ID (req_…). Quote it when you contact support.
The key may not do this (a missing scope, a plan limit, or a compliance block).
Every /v1 error.
object
object
A stable, machine-readable code from the error-code catalogue.
Structured context, e.g. required_scope or the compliance verdict.
object
A link to the documentation of this code.
A human-readable explanation. Do not parse it.
The request parameter the error relates to, e.g. to or metadata[order_id].
The X-Request-Id of this request. Quote it when you contact support.
The category of the error.
Example
{ "error": { "code": "missing_scope", "doc_url": "https://docs.morevoice.ai/api/errors#missing-scope", "message": "This API key lacks the calls:write scope.", "request_id": "req_7Hk2LmN9pQ4rS6tV8wX0yZ", "type": "permission_error" }}Headers
Section titled “Headers”The request’s ID (req_…). Quote it when you contact support.
The request conflicts with the object’s state, or the Idempotency-Key was reused with other parameters.
Every /v1 error.
object
object
A stable, machine-readable code from the error-code catalogue.
Structured context, e.g. required_scope or the compliance verdict.
object
A link to the documentation of this code.
A human-readable explanation. Do not parse it.
The request parameter the error relates to, e.g. to or metadata[order_id].
The X-Request-Id of this request. Quote it when you contact support.
The category of the error.
Example
{ "error": { "code": "idempotency_mismatch", "doc_url": "https://docs.morevoice.ai/api/errors#idempotency-mismatch", "message": "This Idempotency-Key was already used with different parameters.", "request_id": "req_7Hk2LmN9pQ4rS6tV8wX0yZ", "type": "idempotency_error" }}Headers
Section titled “Headers”The request’s ID (req_…). Quote it when you contact support.
Too many requests, or no call capacity right now. Retry after the Retry-After delay.
Every /v1 error.
object
object
A stable, machine-readable code from the error-code catalogue.
Structured context, e.g. required_scope or the compliance verdict.
object
A link to the documentation of this code.
A human-readable explanation. Do not parse it.
The request parameter the error relates to, e.g. to or metadata[order_id].
The X-Request-Id of this request. Quote it when you contact support.
The category of the error.
Example
{ "error": { "code": "rate_limited", "doc_url": "https://docs.morevoice.ai/api/errors#rate-limited", "message": "Too many requests. Retry after 1 second.", "request_id": "req_7Hk2LmN9pQ4rS6tV8wX0yZ", "type": "rate_limit_error" }}Headers
Section titled “Headers”Seconds to wait before retrying.
The request’s ID (req_…). Quote it when you contact support.
Something went wrong on MoreVoice’s side. Retry with the same Idempotency-Key.
Every /v1 error.
object
object
A stable, machine-readable code from the error-code catalogue.
Structured context, e.g. required_scope or the compliance verdict.
object
A link to the documentation of this code.
A human-readable explanation. Do not parse it.
The request parameter the error relates to, e.g. to or metadata[order_id].
The X-Request-Id of this request. Quote it when you contact support.
The category of the error.
Example
{ "error": { "code": "internal_error", "doc_url": "https://docs.morevoice.ai/api/errors#internal-error", "message": "Something went wrong on MoreVoice's side.", "request_id": "req_7Hk2LmN9pQ4rS6tV8wX0yZ", "type": "api_error" }}Headers
Section titled “Headers”The request’s ID (req_…). Quote it when you contact support.