Riferimento API / Operations agents

Operations agents

Gli endpoint del gruppo Operations agents dell'API Voiceland AI, con parametri, schemi ed esempi curl.

Ultimo aggiornamento:

Le descrizioni degli endpoint e dei campi restano in inglese, esattamente come le pubblica l'API. È una scelta voluta: qui legge ciò che vedrà anche nelle risposte.

GET /v1/ops-agents#

List operations agents.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Corpo della richiesta

application/json Schema: OpsAgentRequest

Campo Tipo Obbligatorio Descrizione
definition string (byte)
description string
enabled boolean
name string
note string
source string

Risposte

Codice Descrizione
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.

Esempio di richiesta

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"
}'

Esempio di risposta

{
  "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.

Corpo della richiesta

application/json

Risposte

Codice Descrizione
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.

Esempio di richiesta

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"
}'

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
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).

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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".

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
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.

Risposte

Codice Descrizione
200 An .xlsx workbook.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
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.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
month query string YYYY-MM.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
204 Deleted.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Corpo della richiesta

application/json Schema: OpsAgentRequest

Campo Tipo Obbligatorio Descrizione
definition string (byte)
description string
enabled boolean
name string
note string
source string

Risposte

Codice Descrizione
200 Success.
400 invalid_definition.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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"
}'

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Corpo della richiesta

application/json

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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"
}'

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Corpo della richiesta

application/json

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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"
}'

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
trigger path string Trigger type.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
trigger path string Trigger type.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
trigger path string Trigger type.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
rev path string Revision id from the history.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
rev path string The older revision.
other path string The newer revision, or current.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
rev path string Revision id.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Corpo della richiesta

application/json

Risposte

Codice Descrizione
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.

Esempio di richiesta

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"
}'

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
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).

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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".

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
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.

Risposte

Codice Descrizione
200 An .xlsx workbook.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
id path string Run id (opr-…).

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
id path string Run id.

Risposte

Codice Descrizione
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.

Esempio di richiesta

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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.
id path string Run id.
node path string The step's node id.

Risposte

Codice Descrizione
202 Retrying.
401 Missing or invalid API key.
409 cannot_retry.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
name path string Agent name.

Corpo della richiesta

application/json

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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
}'

Esempio di risposta

{
  "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.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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.

Parametri

Nome Posizione Tipo Obbligatorio Descrizione
integration query string yeastar, hubspot or generic.

Risposte

Codice Descrizione
200 Success.
401 Missing or invalid API key.
4XX Request error (validation, not-found, etc.).
5XX Server or upstream error.

Esempio di richiesta

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

Esempio di risposta

{
  "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"
    }
  ]
}

Schemi#

Error#

Error envelope returned for non-2xx responses.

Campo Tipo Obbligatorio Descrizione
error object

OpsAgentRequest#

Campo Tipo Obbligatorio Descrizione
definition string (byte)
description string
enabled boolean
name string
note string
source string

La console

Queste pagine sono di sola lettura. La chiamata di prova, le chiavi API e il riferimento API aggiornato si trovano nella console, dove il suo account è connesso.

Apri la console