Справочник API / Operations agents

Operations agents

Endpoints группы Operations agents в API Voiceland AI, с параметрами, схемами и примерами curl.

Последнее обновление:

Описания endpoints и полей показаны на английском языке, ровно так, как их публикует API. Это наш выбор: здесь вы читаете то же, что увидите в ответах.

GET /v1/ops-agents#

List operations agents.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "items": [
    {
      "created_at": "2026-09-19T08:00:00Z",
      "definition": {
        "edges": [
          {
            "from": "trigger",
            "to": "download"
          },
          {
            "from": "download",
            "to": "transcribe"
          },
          {
            "from": "transcribe",
            "to": "report"
          },
          {
            "from": "report",
            "to": "mail"
          },
          {
            "from": "report",
            "to": "hook"
          }
        ],
        "nodes": [
          {
            "id": "trigger",
            "label": "Call ended",
            "position": {
              "x": 80,
              "y": 160
            },
            "type": "trigger.pbx_call"
          },
          {
            "config": {
              "url": "{{trigger.recording_url}}"
            },
            "id": "download",
            "label": "Download recording",
            "position": {
              "x": 380,
              "y": 160
            },
            "type": "recording.download"
          },
          {
            "config": {
              "file": "{{download.file}}",
              "translate_to": [
                "en"
              ]
            },
            "id": "transcribe",
            "label": "Transcribe",
            "position": {
              "x": 680,
              "y": 160
            },
            "type": "transcribe"
          },
          {
            "config": {
              "questions": [
                {
                  "text": "Did the customer place an order?"
                },
                {
                  "text": "Was a complaint raised?"
                }
              ],
              "transcript": "{{transcribe.text}}"
            },
            "id": "report",
            "label": "Report",
            "position": {
              "x": 980,
              "y": 160
            },
            "type": "report.questions"
          },
          {
            "config": {
              "to": [
                "ops@example.com"
              ]
            },
            "id": "mail",
            "label": "Email the report",
            "position": {
              "x": 1280,
              "y": 100
            },
            "type": "email.report"
          },
          {
            "config": {
              "secret": "…",
              "url": "https://example.com/hooks/calls"
            },
            "id": "hook",
            "label": "Notify",
            "position": {
              "x": 1280,
              "y": 240
            },
            "type": "webhook.post"
          }
        ]
      },
      "description": "Transcribe every call and mail the report",
      "enabled": true,
      "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
      "kind": "operations",
      "last_run_at": "2026-09-19T09:45:31Z",
      "last_status": "ok",
      "name": "after-call-report",
      "runs": 12,
      "updated_at": "2026-09-19T08:30:00Z"
    }
  ]
}

POST /v1/ops-agents#

Create an operations agent. The name is shared with voice and chat agents and must be free. Without a definition the board starts with one manual trigger. definition is {nodes, edges}: a node has id, type (a module), label, config and position; an edge from, to and, leaving a condition, when: "true"|"false". Validated: known modules, required settings, at least one trigger, no cycle, a schedule trigger's cron and timezone (at most every 5 minutes). A board with a trigger.schedule node answers with schedule (cron, timezone, policies, runs_per_month) and next_run_at; it fires only while the agent is enabled.

Тело запроса

application/json Схема: OpsAgentRequest

Поле Тип Обязательно Описание
definition string (byte) Да
description string Да
enabled boolean
name string Да
note string
source string

Ответы

Код Описание
201 Created.
400 invalid_definition (the message names the node and the rule), invalid_agent_name.
401 Missing or invalid API key.
409 name_taken, already_exists.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "description": "Transcribe every call and mail the report",
  "enabled": true,
  "name": "after-call-report"
}'

Пример ответа

{
  "created_at": "2026-09-19T08:00:00Z",
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "description": "Transcribe every call and mail the report",
  "enabled": true,
  "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
  "kind": "operations",
  "last_run_at": "2026-09-19T09:45:31Z",
  "last_status": "ok",
  "name": "after-call-report",
  "runs": 12,
  "updated_at": "2026-09-19T08:30:00Z"
}

POST /v1/ops-agents/design#

Design a board with AI. Say what the workflow should do. The designer is given the module catalog, the connection schema, the rules and the template library, and answers with a board that has been parsed, validated and linted; a first draft with findings goes back to the model once with those findings. ok: true means the board is clean and ready to put on a canvas (it is NOT saved; save it with source: ai). ok: false carries the issues that remained. Pass current to ask for a change to an existing board.

Тело запроса

application/json

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
502 designer_unavailable: the model could not be reached.
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/design" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "language": "en",
  "request": "When a call ends, transcribe it and email a summary to sales@example.com"
}'

Пример ответа

{
  "assumptions": [
    "sales@example.com is the recipient"
  ],
  "attempts": 1,
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "explanation": "Downloads the recording, transcribes it, summarises it and emails the summary.",
  "issues": [],
  "ok": true
}

GET /v1/ops-agents/runs#

Run history across agents. Every agent's runs of the project, newest first, with the same window, totals and truncated flag as the per-agent list.

Параметры

Имя Место Тип Обязательно Описание
from query string Window start by run start time: RFC3339 or YYYY-MM-DD (00:00Z). Open when omitted.
to query string Window end: RFC3339 or YYYY-MM-DD (that day's last millisecond). Open when omitted.
limit query integer Max rows (default 50, max 500).

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/runs" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "from": "2026-09-01T00:00:00Z",
  "items": [
    {
      "active_ms": 39100,
      "agent": "after-call-report",
      "billed_seconds": 60,
      "cost_cents": 5,
      "data": {
        "download": {
          "bytes": 812345,
          "filename": "download-recording.wav"
        },
        "summarize": {
          "text": "The caller ordered two souvlaki for pickup."
        },
        "transcribe": {
          "language": "el",
          "text": "Καλημέρα, θα ήθελα δύο σουβλάκια…"
        },
        "trigger": {
          "caller_number": "+306972605774",
          "direction": "inbound"
        }
      },
      "duration_ms": 41200,
      "finished_at": "2026-09-19T09:46:12Z",
      "has_xlsx": true,
      "id": "opr-c3e5e22e41b010c0",
      "report": {
        "answers": [
          {
            "answer": "Yes, two souvlaki for pickup.",
            "matched": true,
            "question": "Did the customer place an order?"
          }
        ],
        "title": "Call report +306972605774"
      },
      "started_at": "2026-09-19T09:45:31Z",
      "status": "ok",
      "steps": [
        {
          "attempt": 1,
          "duration_ms": 1830,
          "finished_at": "2026-09-19T09:45:33Z",
          "input_bytes": 96,
          "input_preview": "{\"max_mb\":200,\"url\":\"https://example.com/api/v1.0/crm/recording?secret=…\"}",
          "label": "Download recording",
          "max_attempts": 24,
          "node_id": "download",
          "output_bytes": 118,
          "output_preview": "{\"bytes\":812345,\"content_type\":\"audio/wav\",\"file\":\"(file download-recording.wav)\",\"filename\":\"download-recording.wav\"}",
          "retry_interval_min": 60,
          "started_at": "2026-09-19T09:45:31Z",
          "status": "ok",
          "type": "recording.download"
        },
        {
          "attempt": 1,
          "attempts": [
            {
              "at": "2026-09-19T09:46:11Z",
              "attempt": 1,
              "duration_ms": 412,
              "error": "webhook: the endpoint answered 503: upstream maintenance",
              "remote_status": 503
            }
          ],
          "error": "webhook: the endpoint answered 503: upstream maintenance",
          "label": "Notify",
          "max_attempts": 24,
          "next_attempt_at": "2026-09-19T10:46:12Z",
          "node_id": "hook",
          "remote_body": "upstream maintenance",
          "remote_status": 503,
          "retry_interval_min": 60,
          "status": "retrying",
          "type": "webhook.post"
        }
      ],
      "trigger_summary": "inbound call +306972605774 → 401",
      "trigger_type": "trigger.pbx_call",
      "updated_at": "2026-09-19T09:46:12Z"
    }
  ],
  "to": "2026-09-30T23:59:59Z",
  "totals": {
    "billed_seconds": 60,
    "charged_cents": 0,
    "cost_cents": 5,
    "failed": 0,
    "ok": 1,
    "pool_seconds": 15,
    "runs": 1
  },
  "truncated": false
}

GET /v1/ops-agents/runs/export.xlsx#

Export runs across agents as a workbook. The runs of the window (up to 5000, newest first) as an .xlsx: a Runs sheet (started, agent, run, status, trigger, steps, active/automation/plan seconds, list value and charged EUR, source, error) and a Totals sheet. Content-Disposition: attachment; filename="ops-runs-all-<from>_<to>.xlsx".

Параметры

Имя Место Тип Обязательно Описание
from query string Window start by run start time: RFC3339 or YYYY-MM-DD (00:00Z). Open when omitted.
to query string Window end: RFC3339 or YYYY-MM-DD (that day's last millisecond). Open when omitted.

Ответы

Код Описание
200 An .xlsx workbook.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/runs/export.xlsx" \
  -H "Authorization: Bearer VL_API_KEY"

GET /v1/ops-agents/stats#

Run statistics. The window (default: the start of the current UTC month → now) folded per UTC day, zero-filled for every day of [from, to), and per agent (sorted by runs, with last_run_at), plus totals. Up to 5000 runs are counted; truncated says the window held more. Seconds and cents are the runs' own settled values.

Параметры

Имя Место Тип Обязательно Описание
from query string Window start by run start time: RFC3339 or YYYY-MM-DD (00:00Z). Open when omitted.
to query string Window end: RFC3339 or YYYY-MM-DD (that day's last millisecond). Open when omitted.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/stats" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "agents": [
    {
      "agent": "after-call-report",
      "billed_seconds": 540,
      "charged_cents": 0,
      "cost_cents": 45,
      "failed": 1,
      "last_run_at": "2026-09-22T16:02:11Z",
      "ok": 8,
      "pool_seconds": 135,
      "runs": 9
    }
  ],
  "days": [
    {
      "billed_seconds": 0,
      "charged_cents": 0,
      "cost_cents": 0,
      "date": "2026-09-01",
      "failed": 0,
      "ok": 0,
      "pool_seconds": 0,
      "runs": 0
    },
    {
      "billed_seconds": 540,
      "charged_cents": 0,
      "cost_cents": 45,
      "date": "2026-09-22",
      "failed": 1,
      "ok": 8,
      "pool_seconds": 135,
      "runs": 9
    }
  ],
  "from": "2026-09-01T00:00:00Z",
  "to": "2026-09-23T10:00:00Z",
  "total_runs": 14,
  "totals": {
    "billed_seconds": 900,
    "charged_cents": 0,
    "cost_cents": 75,
    "failed": 2,
    "ok": 12,
    "pool_seconds": 225,
    "runs": 14
  },
  "truncated": false
}

GET /v1/ops-agents/usage#

Monthly usage. Runs, billed seconds and cents for a month (default: the current one), plus the rate.

Параметры

Имя Место Тип Обязательно Описание
month query string YYYY-MM.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/usage" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "billed_seconds": 900,
  "charged_cents": 0,
  "cost_cents": 75,
  "month": "2026-09",
  "pool_seconds": 225,
  "questions": 8,
  "rate": {
    "cents_per_minute": 5,
    "currency": "EUR",
    "in_regime": true,
    "min_seconds": 30,
    "overage_cents_per_min": 20,
    "package_id": "growth",
    "percent": 25,
    "questions_included": 5,
    "seconds_per_extra_question": 60
  },
  "runs": 12
}

DELETE /v1/ops-agents/{name}#

Delete an operations agent. Runs are kept for their 90-day retention.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
204 Deleted.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X DELETE "https://api.voiceland.ai/v1/ops-agents/{name}" \
  -H "Authorization: Bearer VL_API_KEY"

GET /v1/ops-agents/{name}#

Get an operations agent.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "created_at": "2026-09-19T08:00:00Z",
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "description": "Transcribe every call and mail the report",
  "enabled": true,
  "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
  "kind": "operations",
  "last_run_at": "2026-09-19T09:45:31Z",
  "last_status": "ok",
  "name": "after-call-report",
  "runs": 12,
  "updated_at": "2026-09-19T08:30:00Z"
}

PUT /v1/ops-agents/{name}#

Save the board, description or enabled state. Fields absent from the body are kept. Disabling stops triggers from starting runs.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Тело запроса

application/json Схема: OpsAgentRequest

Поле Тип Обязательно Описание
definition string (byte) Да
description string Да
enabled boolean
name string Да
note string
source string

Ответы

Код Описание
200 Success.
400 invalid_definition.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X PUT "https://api.voiceland.ai/v1/ops-agents/{name}" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "description": "Transcribe every call and mail the report",
  "enabled": true,
  "name": "after-call-report"
}'

Пример ответа

{
  "created_at": "2026-09-19T08:00:00Z",
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "description": "Transcribe every call and mail the report",
  "enabled": true,
  "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
  "kind": "operations",
  "last_run_at": "2026-09-19T09:45:31Z",
  "last_status": "ok",
  "name": "after-call-report",
  "runs": 12,
  "updated_at": "2026-09-19T08:30:00Z"
}

POST /v1/ops-agents/{name}/apply-template#

Replace the board with a template. Templates are ready-made boards, grouped by integration, every one validated and run end to end in our tests. The previous board is kept as a revision. The answer carries the template's sample_payload, which a test run through its trigger exercises.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Тело запроса

application/json

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/apply-template" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "template": "yeastar-summary-email"
}'

Пример ответа

{
  "agent": {
    "created_at": "2026-09-19T08:00:00Z",
    "definition": {
      "edges": [
        {
          "from": "trigger",
          "to": "download"
        },
        {
          "from": "download",
          "to": "transcribe"
        },
        {
          "from": "transcribe",
          "to": "report"
        },
        {
          "from": "report",
          "to": "mail"
        },
        {
          "from": "report",
          "to": "hook"
        }
      ],
      "nodes": [
        {
          "id": "trigger",
          "label": "Call ended",
          "position": {
            "x": 80,
            "y": 160
          },
          "type": "trigger.pbx_call"
        },
        {
          "config": {
            "url": "{{trigger.recording_url}}"
          },
          "id": "download",
          "label": "Download recording",
          "position": {
            "x": 380,
            "y": 160
          },
          "type": "recording.download"
        },
        {
          "config": {
            "file": "{{download.file}}",
            "translate_to": [
              "en"
            ]
          },
          "id": "transcribe",
          "label": "Transcribe",
          "position": {
            "x": 680,
            "y": 160
          },
          "type": "transcribe"
        },
        {
          "config": {
            "questions": [
              {
                "text": "Did the customer place an order?"
              },
              {
                "text": "Was a complaint raised?"
              }
            ],
            "transcript": "{{transcribe.text}}"
          },
          "id": "report",
          "label": "Report",
          "position": {
            "x": 980,
            "y": 160
          },
          "type": "report.questions"
        },
        {
          "config": {
            "to": [
              "ops@example.com"
            ]
          },
          "id": "mail",
          "label": "Email the report",
          "position": {
            "x": 1280,
            "y": 100
          },
          "type": "email.report"
        },
        {
          "config": {
            "secret": "…",
            "url": "https://example.com/hooks/calls"
          },
          "id": "hook",
          "label": "Notify",
          "position": {
            "x": 1280,
            "y": 240
          },
          "type": "webhook.post"
        }
      ]
    },
    "description": "Transcribe every call and mail the report",
    "enabled": true,
    "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
    "kind": "operations",
    "last_run_at": "2026-09-19T09:45:31Z",
    "last_status": "ok",
    "name": "after-call-report",
    "runs": 12,
    "updated_at": "2026-09-19T08:30:00Z"
  },
  "revision": {
    "number": 2,
    "source": "template"
  },
  "template": {
    "id": "yeastar-summary-email",
    "integration": "yeastar",
    "sample_payload": {
      "caller_number": "+306972605774",
      "direction": "inbound"
    },
    "trigger": "trigger.pbx_call"
  }
}

GET /v1/ops-agents/{name}/export#

Export the board as JSON. An envelope (format: voiceland.ops-agent/v1) with the board, sent as a download. Import accepts exactly this.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/export" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "agent": "after-call-report",
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "exported_at": "2026-09-22T10:15:00Z",
  "format": "voiceland.ops-agent/v1"
}

DELETE /v1/ops-agents/{name}/hook-test#

Stop listening. Closes the window without capturing; the last sample, if any, stays readable.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X DELETE "https://api.voiceland.ai/v1/ops-agents/{name}/hook-test" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "armed": false,
  "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e"
}

GET /v1/ops-agents/{name}/hook-test#

Read the listening window. Whether the window is armed, and the captured request once one has arrived. Poll it after arming.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/hook-test" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "armed": false,
  "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
  "sample": {
    "body": {
      "call_id": "c-77",
      "direction": "inbound"
    },
    "headers": {
      "Content-Type": "application/json",
      "X-Event": "call.ended"
    },
    "method": "POST",
    "path": "/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
    "query": {
      "source": "pbx"
    },
    "received_at": "2026-09-22T10:07:41Z"
  }
}

POST /v1/ops-agents/{name}/hook-test#

Listen for a test webhook. Arms a ten-minute listening window on the agent's inbound webhook (hook_url). While it is open, the NEXT request to that address is captured and returned by GET instead of starting a run, so you can fire the real event from the other system and read exactly what it sent (method, path, query, a small set of safe headers, and the body as JSON when it parses). It works whether or not the agent is enabled, one request per press (the window closes on capture, so a second event cannot overwrite the one you are reading), the body is cut at 64 KB (truncated), and Authorization and cookies are never kept. Arming again clears the previous sample.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/hook-test" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "armed": true,
  "armed_until": "2026-09-22T10:15:00Z",
  "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e"
}

POST /v1/ops-agents/{name}/import#

Import a board from JSON. Send an exported envelope. The file is validated BEFORE anything changes: the format, the JSON, every module type, every edge, the cycle check, and the connection lint (a step no trigger reaches, a reference to a step that is not upstream, a URL fed to a file input). The answer says valid, lists errors by problem, and carries current, the normalised definition and the diff between them, so you can show the two side by side. With dry_run: true nothing is replaced; without it, a valid file becomes the board and a revision (source: import) records the previous one.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Тело запроса

application/json

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/import" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "agent": "after-call-report",
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "dry_run": true,
  "format": "voiceland.ops-agent/v1"
}'

Пример ответа

{
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "diff": {
    "same": false,
    "summary": "+1 step, +1 connection"
  },
  "errors": [],
  "valid": true
}

DELETE /v1/ops-agents/{name}/listen/{trigger}#

Stop listening on a trigger. Closes the window without capturing; the last sample, if any, stays readable.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
trigger path string Да Trigger type.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X DELETE "https://api.voiceland.ai/v1/ops-agents/{name}/listen/{trigger}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "armed": false,
  "trigger": "trigger.pbx_call"
}

GET /v1/ops-agents/{name}/listen/{trigger}#

Read a trigger's listening state and sample. Whether the window is open and the last captured sample: when it arrived, a summary, where it came from and the payload the run would have started with.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
trigger path string Да Trigger type.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/listen/{trigger}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "armed": false,
  "sample": {
    "payload": {
      "callee_number": "401",
      "caller_number": "+302101234567",
      "direction": "inbound",
      "duration_sec": 42
    },
    "received_at": "2026-05-09T10:31:12Z",
    "source": {
      "event_id": "evt_01",
      "integration": "yeastar_crm"
    },
    "summary": "inbound call +302101234567 → 401",
    "trigger": "trigger.pbx_call"
  },
  "trigger": "trigger.pbx_call"
}

POST /v1/ops-agents/{name}/listen/{trigger}#

Listen for a test event on a trigger. Opens a ten-minute window on one trigger: trigger.webhook, trigger.pbx_call (a finished PBX call) or trigger.agent (a call from another operations agent). The next such event is captured as a sample instead of starting a run, whether or not the agent is enabled. The window closes on the capture; read the sample with GET.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
trigger path string Да Trigger type.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/listen/{trigger}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "armed": true,
  "armed_until": "2026-05-09T10:40:00Z",
  "trigger": "trigger.pbx_call"
}

GET /v1/ops-agents/{name}/revisions#

Board history. Every save that changed the board, newest first, without the boards themselves: number, when, who, source (create, save, rollback, import, ai, template), a one-line summary of what changed against the previous revision, and the note the actor left. Kept a year.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/revisions" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "items": [
    {
      "actor": "maria@example.com",
      "created_at": "2026-09-22T10:15:00Z",
      "id": "00001790080000000000",
      "number": 3,
      "source": "save",
      "summary": "+1 step, +1 connection"
    }
  ]
}

GET /v1/ops-agents/{name}/revisions/{rev}#

One revision, with its board.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
rev path string Да Revision id from the history.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/revisions/{rev}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "definition": {
    "edges": [
      {
        "from": "trigger",
        "to": "download"
      },
      {
        "from": "download",
        "to": "transcribe"
      },
      {
        "from": "transcribe",
        "to": "report"
      },
      {
        "from": "report",
        "to": "mail"
      },
      {
        "from": "report",
        "to": "hook"
      }
    ],
    "nodes": [
      {
        "id": "trigger",
        "label": "Call ended",
        "position": {
          "x": 80,
          "y": 160
        },
        "type": "trigger.pbx_call"
      },
      {
        "config": {
          "url": "{{trigger.recording_url}}"
        },
        "id": "download",
        "label": "Download recording",
        "position": {
          "x": 380,
          "y": 160
        },
        "type": "recording.download"
      },
      {
        "config": {
          "file": "{{download.file}}",
          "translate_to": [
            "en"
          ]
        },
        "id": "transcribe",
        "label": "Transcribe",
        "position": {
          "x": 680,
          "y": 160
        },
        "type": "transcribe"
      },
      {
        "config": {
          "questions": [
            {
              "text": "Did the customer place an order?"
            },
            {
              "text": "Was a complaint raised?"
            }
          ],
          "transcript": "{{transcribe.text}}"
        },
        "id": "report",
        "label": "Report",
        "position": {
          "x": 980,
          "y": 160
        },
        "type": "report.questions"
      },
      {
        "config": {
          "to": [
            "ops@example.com"
          ]
        },
        "id": "mail",
        "label": "Email the report",
        "position": {
          "x": 1280,
          "y": 100
        },
        "type": "email.report"
      },
      {
        "config": {
          "secret": "…",
          "url": "https://example.com/hooks/calls"
        },
        "id": "hook",
        "label": "Notify",
        "position": {
          "x": 1280,
          "y": 240
        },
        "type": "webhook.post"
      }
    ]
  },
  "id": "00001790080000000000",
  "number": 3,
  "source": "save"
}

GET /v1/ops-agents/{name}/revisions/{rev}/diff/{other}#

Compare two revisions. Both boards whole, beside a structural diff: steps added, removed and changed (with each setting's before and after), connections added and removed, and steps merely moved. other may be current for the board as it is now.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
rev path string Да The older revision.
other path string Да The newer revision, or current.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/revisions/{rev}/diff/{other}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "diff": {
    "edges_added": [],
    "edges_removed": [],
    "nodes_added": [],
    "nodes_changed": [
      {
        "fields": [
          {
            "after": "bullets",
            "before": "brief",
            "key": "style"
          }
        ],
        "id": "summarize",
        "type": "summarize"
      }
    ],
    "nodes_removed": [],
    "same": false,
    "summary": "1 changed"
  },
  "from": {
    "id": "00001790070000000000",
    "label": "#2"
  },
  "to": {
    "id": "current",
    "label": "current"
  }
}

POST /v1/ops-agents/{name}/revisions/{rev}/rollback#

Restore a revision. The board becomes that revision again, and a NEW revision (source: rollback, note restored #n) records it, so the history only ever grows. 409 revision_invalid when the old board no longer validates against today's modules.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
rev path string Да Revision id.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/revisions/{rev}/rollback" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "agent": {
    "created_at": "2026-09-19T08:00:00Z",
    "definition": {
      "edges": [
        {
          "from": "trigger",
          "to": "download"
        },
        {
          "from": "download",
          "to": "transcribe"
        },
        {
          "from": "transcribe",
          "to": "report"
        },
        {
          "from": "report",
          "to": "mail"
        },
        {
          "from": "report",
          "to": "hook"
        }
      ],
      "nodes": [
        {
          "id": "trigger",
          "label": "Call ended",
          "position": {
            "x": 80,
            "y": 160
          },
          "type": "trigger.pbx_call"
        },
        {
          "config": {
            "url": "{{trigger.recording_url}}"
          },
          "id": "download",
          "label": "Download recording",
          "position": {
            "x": 380,
            "y": 160
          },
          "type": "recording.download"
        },
        {
          "config": {
            "file": "{{download.file}}",
            "translate_to": [
              "en"
            ]
          },
          "id": "transcribe",
          "label": "Transcribe",
          "position": {
            "x": 680,
            "y": 160
          },
          "type": "transcribe"
        },
        {
          "config": {
            "questions": [
              {
                "text": "Did the customer place an order?"
              },
              {
                "text": "Was a complaint raised?"
              }
            ],
            "transcript": "{{transcribe.text}}"
          },
          "id": "report",
          "label": "Report",
          "position": {
            "x": 980,
            "y": 160
          },
          "type": "report.questions"
        },
        {
          "config": {
            "to": [
              "ops@example.com"
            ]
          },
          "id": "mail",
          "label": "Email the report",
          "position": {
            "x": 1280,
            "y": 100
          },
          "type": "email.report"
        },
        {
          "config": {
            "secret": "…",
            "url": "https://example.com/hooks/calls"
          },
          "id": "hook",
          "label": "Notify",
          "position": {
            "x": 1280,
            "y": 240
          },
          "type": "webhook.post"
        }
      ]
    },
    "description": "Transcribe every call and mail the report",
    "enabled": true,
    "hook_url": "https://api.voiceland.ai/v1/ops/hooks/k3JqTz9wY1n8Qb2vXm5LpR0e",
    "kind": "operations",
    "last_run_at": "2026-09-19T09:45:31Z",
    "last_status": "ok",
    "name": "after-call-report",
    "runs": 12,
    "updated_at": "2026-09-19T08:30:00Z"
  },
  "restored": 2,
  "revision": {
    "note": "restored #2",
    "number": 5,
    "source": "rollback"
  }
}

POST /v1/ops-agents/{name}/run#

Start a run. Runs are asynchronous: the answer is the run row in state queued (or running on a single-node deployment); poll the detail. Any node of the service executes it under a lease; a node that stops hands the run to another one at its last checkpoint. payload is the trigger data; trigger (default trigger.manual) lets a test enter through trigger.pbx_call or trigger.webhook with sample data.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Тело запроса

application/json

Ответы

Код Описание
202 Started.
400 cannot_run (for example a board without that trigger), invalid_trigger.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/run" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "payload": {
    "callee_number": "401",
    "caller_number": "+306972605774",
    "direction": "inbound",
    "duration_sec": 42,
    "recording_url": "https://example.com/api/v1.0/crm/recording?secret=…"
  },
  "trigger": "trigger.pbx_call"
}'

Пример ответа

{
  "active_ms": 39100,
  "agent": "after-call-report",
  "billed_seconds": 60,
  "cost_cents": 5,
  "data": {
    "download": {
      "bytes": 812345,
      "filename": "download-recording.wav"
    },
    "summarize": {
      "text": "The caller ordered two souvlaki for pickup."
    },
    "transcribe": {
      "language": "el",
      "text": "Καλημέρα, θα ήθελα δύο σουβλάκια…"
    },
    "trigger": {
      "caller_number": "+306972605774",
      "direction": "inbound"
    }
  },
  "duration_ms": 41200,
  "finished_at": "2026-09-19T09:46:12Z",
  "has_xlsx": true,
  "id": "opr-c3e5e22e41b010c0",
  "report": {
    "answers": [
      {
        "answer": "Yes, two souvlaki for pickup.",
        "matched": true,
        "question": "Did the customer place an order?"
      }
    ],
    "title": "Call report +306972605774"
  },
  "started_at": "2026-09-19T09:45:31Z",
  "status": "ok",
  "steps": [
    {
      "attempt": 1,
      "duration_ms": 1830,
      "finished_at": "2026-09-19T09:45:33Z",
      "input_bytes": 96,
      "input_preview": "{\"max_mb\":200,\"url\":\"https://example.com/api/v1.0/crm/recording?secret=…\"}",
      "label": "Download recording",
      "max_attempts": 24,
      "node_id": "download",
      "output_bytes": 118,
      "output_preview": "{\"bytes\":812345,\"content_type\":\"audio/wav\",\"file\":\"(file download-recording.wav)\",\"filename\":\"download-recording.wav\"}",
      "retry_interval_min": 60,
      "started_at": "2026-09-19T09:45:31Z",
      "status": "ok",
      "type": "recording.download"
    },
    {
      "attempt": 1,
      "attempts": [
        {
          "at": "2026-09-19T09:46:11Z",
          "attempt": 1,
          "duration_ms": 412,
          "error": "webhook: the endpoint answered 503: upstream maintenance",
          "remote_status": 503
        }
      ],
      "error": "webhook: the endpoint answered 503: upstream maintenance",
      "label": "Notify",
      "max_attempts": 24,
      "next_attempt_at": "2026-09-19T10:46:12Z",
      "node_id": "hook",
      "remote_body": "upstream maintenance",
      "remote_status": 503,
      "retry_interval_min": 60,
      "status": "retrying",
      "type": "webhook.post"
    }
  ],
  "trigger_summary": "inbound call +306972605774 → 401",
  "trigger_type": "trigger.pbx_call",
  "updated_at": "2026-09-19T09:46:12Z"
}

GET /v1/ops-agents/{name}/runs#

Run history. Newest first, without step previews (the detail has them). from/to narrow the window by start time (RFC3339, or a plain YYYY-MM-DD day: from is that day's 00:00Z, to its last millisecond; either bound may be left open); 400 invalid_from, invalid_to, invalid_window (from must be before to). totals sums the rows returned (ok = finished clean, failed = error or partial); truncated says the window holds more rows than limit.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
from query string Window start by run start time: RFC3339 or YYYY-MM-DD (00:00Z). Open when omitted.
to query string Window end: RFC3339 or YYYY-MM-DD (that day's last millisecond). Open when omitted.
limit query integer Max rows (default 50, max 500).

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/runs" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "from": "2026-09-01T00:00:00Z",
  "items": [
    {
      "active_ms": 39100,
      "agent": "after-call-report",
      "billed_seconds": 60,
      "cost_cents": 5,
      "data": {
        "download": {
          "bytes": 812345,
          "filename": "download-recording.wav"
        },
        "summarize": {
          "text": "The caller ordered two souvlaki for pickup."
        },
        "transcribe": {
          "language": "el",
          "text": "Καλημέρα, θα ήθελα δύο σουβλάκια…"
        },
        "trigger": {
          "caller_number": "+306972605774",
          "direction": "inbound"
        }
      },
      "duration_ms": 41200,
      "finished_at": "2026-09-19T09:46:12Z",
      "has_xlsx": true,
      "id": "opr-c3e5e22e41b010c0",
      "report": {
        "answers": [
          {
            "answer": "Yes, two souvlaki for pickup.",
            "matched": true,
            "question": "Did the customer place an order?"
          }
        ],
        "title": "Call report +306972605774"
      },
      "started_at": "2026-09-19T09:45:31Z",
      "status": "ok",
      "steps": [
        {
          "attempt": 1,
          "duration_ms": 1830,
          "finished_at": "2026-09-19T09:45:33Z",
          "input_bytes": 96,
          "input_preview": "{\"max_mb\":200,\"url\":\"https://example.com/api/v1.0/crm/recording?secret=…\"}",
          "label": "Download recording",
          "max_attempts": 24,
          "node_id": "download",
          "output_bytes": 118,
          "output_preview": "{\"bytes\":812345,\"content_type\":\"audio/wav\",\"file\":\"(file download-recording.wav)\",\"filename\":\"download-recording.wav\"}",
          "retry_interval_min": 60,
          "started_at": "2026-09-19T09:45:31Z",
          "status": "ok",
          "type": "recording.download"
        },
        {
          "attempt": 1,
          "attempts": [
            {
              "at": "2026-09-19T09:46:11Z",
              "attempt": 1,
              "duration_ms": 412,
              "error": "webhook: the endpoint answered 503: upstream maintenance",
              "remote_status": 503
            }
          ],
          "error": "webhook: the endpoint answered 503: upstream maintenance",
          "label": "Notify",
          "max_attempts": 24,
          "next_attempt_at": "2026-09-19T10:46:12Z",
          "node_id": "hook",
          "remote_body": "upstream maintenance",
          "remote_status": 503,
          "retry_interval_min": 60,
          "status": "retrying",
          "type": "webhook.post"
        }
      ],
      "trigger_summary": "inbound call +306972605774 → 401",
      "trigger_type": "trigger.pbx_call",
      "updated_at": "2026-09-19T09:46:12Z"
    }
  ],
  "to": "2026-09-30T23:59:59Z",
  "totals": {
    "billed_seconds": 60,
    "charged_cents": 0,
    "cost_cents": 5,
    "failed": 0,
    "ok": 1,
    "pool_seconds": 15,
    "runs": 1
  },
  "truncated": false
}

GET /v1/ops-agents/{name}/runs/export.xlsx#

Export one agent's runs as a workbook. As the cross-agent export, for one agent: filename="ops-runs-<agent>-<from>_<to>.xlsx".

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
from query string Window start by run start time: RFC3339 or YYYY-MM-DD (00:00Z). Open when omitted.
to query string Window end: RFC3339 or YYYY-MM-DD (that day's last millisecond). Open when omitted.

Ответы

Код Описание
200 An .xlsx workbook.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/runs/export.xlsx" \
  -H "Authorization: Bearer VL_API_KEY"

GET /v1/ops-agents/{name}/runs/{id}#

Run detail. Every step with its start, duration, bytes received and produced, a redacted preview of both, its outcome (ok, error, skipped with the reason, retrying with next_attempt_at, pending), the attempt taken against the policy (attempt of max_attempts, every retry_interval_min), what a remote endpoint answered on failure (remote_status, remote_body) and the history of failed attempts. data is the full data map every step received (each node's output under its id), output the same capped, report the question report and has_xlsx whether a workbook exists. A run is queued while it waits for a worker, retrying while a step waits for its next attempt; active_ms is the worked time the bill is based on; deliveries counts the workers that picked it up (a run interrupted ten times is given up on). Webhook and dispatcher calls carry X-Voiceland-Idempotency-Key, the same value on every delivery of one attempt of one step.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
id path string Да Run id (opr-…).

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/runs/{id}" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "active_ms": 39100,
  "agent": "after-call-report",
  "billed_seconds": 60,
  "cost_cents": 5,
  "data": {
    "download": {
      "bytes": 812345,
      "filename": "download-recording.wav"
    },
    "summarize": {
      "text": "The caller ordered two souvlaki for pickup."
    },
    "transcribe": {
      "language": "el",
      "text": "Καλημέρα, θα ήθελα δύο σουβλάκια…"
    },
    "trigger": {
      "caller_number": "+306972605774",
      "direction": "inbound"
    }
  },
  "duration_ms": 41200,
  "finished_at": "2026-09-19T09:46:12Z",
  "has_xlsx": true,
  "id": "opr-c3e5e22e41b010c0",
  "report": {
    "answers": [
      {
        "answer": "Yes, two souvlaki for pickup.",
        "matched": true,
        "question": "Did the customer place an order?"
      }
    ],
    "title": "Call report +306972605774"
  },
  "started_at": "2026-09-19T09:45:31Z",
  "status": "ok",
  "steps": [
    {
      "attempt": 1,
      "duration_ms": 1830,
      "finished_at": "2026-09-19T09:45:33Z",
      "input_bytes": 96,
      "input_preview": "{\"max_mb\":200,\"url\":\"https://example.com/api/v1.0/crm/recording?secret=…\"}",
      "label": "Download recording",
      "max_attempts": 24,
      "node_id": "download",
      "output_bytes": 118,
      "output_preview": "{\"bytes\":812345,\"content_type\":\"audio/wav\",\"file\":\"(file download-recording.wav)\",\"filename\":\"download-recording.wav\"}",
      "retry_interval_min": 60,
      "started_at": "2026-09-19T09:45:31Z",
      "status": "ok",
      "type": "recording.download"
    },
    {
      "attempt": 1,
      "attempts": [
        {
          "at": "2026-09-19T09:46:11Z",
          "attempt": 1,
          "duration_ms": 412,
          "error": "webhook: the endpoint answered 503: upstream maintenance",
          "remote_status": 503
        }
      ],
      "error": "webhook: the endpoint answered 503: upstream maintenance",
      "label": "Notify",
      "max_attempts": 24,
      "next_attempt_at": "2026-09-19T10:46:12Z",
      "node_id": "hook",
      "remote_body": "upstream maintenance",
      "remote_status": 503,
      "retry_interval_min": 60,
      "status": "retrying",
      "type": "webhook.post"
    }
  ],
  "trigger_summary": "inbound call +306972605774 → 401",
  "trigger_type": "trigger.pbx_call",
  "updated_at": "2026-09-19T09:46:12Z"
}

GET /v1/ops-agents/{name}/runs/{id}/report.xlsx#

Download the run's Excel report.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
id path string Да Run id.

Ответы

Код Описание
200 The workbook.
401 Missing or invalid API key.
404 no_report: the run produced none.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-agents/{name}/runs/{id}/report.xlsx" \
  -H "Authorization: Bearer VL_API_KEY"

POST /v1/ops-agents/{name}/runs/{id}/steps/{node}/retry#

Retry a failed step now. Runs one error or retrying step again at once, then everything after it; the run is answered in state retrying and polled. A person's retry runs even when the policy's attempts are used up. 409 cannot_retry for a step that did not fail or a run still in progress.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.
id path string Да Run id.
node path string Да The step's node id.

Ответы

Код Описание
202 Retrying.
401 Missing or invalid API key.
409 cannot_retry.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/runs/{id}/steps/{node}/retry" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "active_ms": 39100,
  "agent": "after-call-report",
  "billed_seconds": 60,
  "cost_cents": 5,
  "data": {
    "download": {
      "bytes": 812345,
      "filename": "download-recording.wav"
    },
    "summarize": {
      "text": "The caller ordered two souvlaki for pickup."
    },
    "transcribe": {
      "language": "el",
      "text": "Καλημέρα, θα ήθελα δύο σουβλάκια…"
    },
    "trigger": {
      "caller_number": "+306972605774",
      "direction": "inbound"
    }
  },
  "duration_ms": 41200,
  "finished_at": "2026-09-19T09:46:12Z",
  "has_xlsx": true,
  "id": "opr-c3e5e22e41b010c0",
  "report": {
    "answers": [
      {
        "answer": "Yes, two souvlaki for pickup.",
        "matched": true,
        "question": "Did the customer place an order?"
      }
    ],
    "title": "Call report +306972605774"
  },
  "started_at": "2026-09-19T09:45:31Z",
  "status": "ok",
  "steps": [
    {
      "attempt": 1,
      "duration_ms": 1830,
      "finished_at": "2026-09-19T09:45:33Z",
      "input_bytes": 96,
      "input_preview": "{\"max_mb\":200,\"url\":\"https://example.com/api/v1.0/crm/recording?secret=…\"}",
      "label": "Download recording",
      "max_attempts": 24,
      "node_id": "download",
      "output_bytes": 118,
      "output_preview": "{\"bytes\":812345,\"content_type\":\"audio/wav\",\"file\":\"(file download-recording.wav)\",\"filename\":\"download-recording.wav\"}",
      "retry_interval_min": 60,
      "started_at": "2026-09-19T09:45:31Z",
      "status": "ok",
      "type": "recording.download"
    },
    {
      "attempt": 1,
      "attempts": [
        {
          "at": "2026-09-19T09:46:11Z",
          "attempt": 1,
          "duration_ms": 412,
          "error": "webhook: the endpoint answered 503: upstream maintenance",
          "remote_status": 503
        }
      ],
      "error": "webhook: the endpoint answered 503: upstream maintenance",
      "label": "Notify",
      "max_attempts": 24,
      "next_attempt_at": "2026-09-19T10:46:12Z",
      "node_id": "hook",
      "remote_body": "upstream maintenance",
      "remote_status": 503,
      "retry_interval_min": 60,
      "status": "retrying",
      "type": "webhook.post"
    }
  ],
  "trigger_summary": "inbound call +306972605774 → 401",
  "trigger_type": "trigger.pbx_call",
  "updated_at": "2026-09-19T09:46:12Z"
}

POST /v1/ops-agents/{name}/steps/test#

Preview or send one deliver step. Renders a send-email or webhook step against real data and shows exactly what would go out (method, URL, headers with credentials masked, body; or the message envelope). With send=true it is sent and the other side's answer is returned. Data comes from a past run (run_id: its steps' recorded outputs) and/or a sample trigger payload; definition may carry the unsaved board. Nothing is billed and no run is recorded.

Параметры

Имя Место Тип Обязательно Описание
name path string Да Agent name.

Тело запроса

application/json

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl -X POST "https://api.voiceland.ai/v1/ops-agents/{name}/steps/test" \
  -H "Authorization: Bearer VL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "node_id": "notify",
  "payload": {
    "caller_number": "+302101234567",
    "direction": "inbound"
  },
  "run_id": "run_01J9",
  "send": false
}'

Пример ответа

{
  "data_from": {
    "payload": true,
    "run_id": "run_01J9"
  },
  "node_id": "notify",
  "preview": {
    "body": {
      "caller": "+302101234567",
      "event": "ops.step"
    },
    "bytes": 52,
    "headers": {
      "Authorization": "•••",
      "Content-Type": "application/json",
      "X-Voiceland-Run": "test-3f9a1c2b"
    },
    "method": "POST",
    "timeout_s": 15,
    "url": "https://example.com/hooks/calls?source=voiceland"
  },
  "sent": false,
  "type": "webhook.post"
}

GET /v1/ops-modules#

Module catalog. Every module a board may use, with its settings (fields: type, default, options), what it produces (outputs), whether it is a trigger, its default retry policy (retry: attempts and interval_min; a node overrides it with a retry object in its config), and the run rate. Modules: the triggers (trigger.pbx_call, trigger.webhook, trigger.manual, trigger.agent, trigger.schedule with a preset or cron expression, timezone, overlap and catch-up policies, at most every 5 minutes), recording.download, transcribe, summarize, report.questions, email.report, webhook.post, dispatch (start several agents and/or post to several URLs at once), condition, agent.call.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-modules" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "items": [
    {
      "category": "media",
      "fields": [
        {
          "default": "{{trigger.recording_url}}",
          "key": "url",
          "label": "Recording URL",
          "required": true,
          "type": "string"
        }
      ],
      "icon": "mdi-download-circle-outline",
      "id": "recording.download",
      "name": "Download recording",
      "outputs": [
        {
          "description": "Temporary file (internal)",
          "key": "file"
        }
      ],
      "trigger": false
    }
  ],
  "rate": {
    "cents_per_minute": 5,
    "currency": "EUR",
    "in_regime": true,
    "min_seconds": 30,
    "overage_cents_per_min": 20,
    "package_id": "growth",
    "percent": 25,
    "questions_included": 5,
    "seconds_per_extra_question": 60
  }
}

GET /v1/ops-modules/schema#

The connection schema. What each module produces (with the kind of each output), what each data-bearing setting accepts and from where, which modules must be upstream of which, and the graph rules in words. Derived from the module catalog; this is what the AI designer and the import check are held to.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-modules/schema" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "modules": [
    {
      "consumes": [
        {
          "field": "file",
          "from": [
            "recording.download.file"
          ],
          "kinds": [
            "file"
          ],
          "required": true
        }
      ],
      "id": "transcribe",
      "needs": [
        "recording.download"
      ],
      "produces": [
        {
          "key": "text",
          "kind": "text"
        }
      ]
    }
  ],
  "rules": [
    "Every step must be reachable from a trigger through edges, or it never runs."
  ]
}

GET /v1/ops-modules/templates#

The template library. Ready-made boards by integration (?integration=yeastar|hubspot|generic), each with its trigger, a sample payload and the placeholders to fill in.

Параметры

Имя Место Тип Обязательно Описание
integration query string yeastar, hubspot or generic.

Ответы

Код Описание
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Пример запроса

curl "https://api.voiceland.ai/v1/ops-modules/templates" \
  -H "Authorization: Bearer VL_API_KEY"

Пример ответа

{
  "integrations": [
    "yeastar",
    "hubspot",
    "generic"
  ],
  "items": [
    {
      "id": "yeastar-summary-email",
      "integration": "yeastar",
      "name": "Email a summary of every call",
      "placeholders": [
        "mail.to"
      ],
      "trigger": "trigger.pbx_call"
    }
  ]
}

Схемы#

Error#

Error envelope returned for non-2xx responses.

Поле Тип Обязательно Описание
error object Да

OpsAgentRequest#

Поле Тип Обязательно Описание
definition string (byte) Да
description string Да
enabled boolean
name string Да
note string
source string

Консоль

Эти страницы доступны только для чтения. Тестовый звонок, ключи API и актуальный справочник API находятся в консоли, где выполнен вход в ваш аккаунт.

Открыть консоль