VocalDocscontracts 1.65.0

Quick start: your first Agent

An Agent is the configuration of a voice assistant: the instructions it follows and the speech to text, language model and text to speech Providers it speaks with. In this quick start you create an Agent as an editable draft, publish a version of it, and read the version back. It takes six requests with curl and an API key; no SDK is involved.

On the Phase 0 host. Served. The six operations below were first released in 1.50.0 or earlier, and the api on the Phase 0 host serves every one of them. On 2026-10-24 UTC the runner passed the 28 steps of the four quick starts against the Phase 0 host, which has pinned contracts 1.60.0 since deploy #70, with a live key: 27 steps were answered and one was skipped, as its page allows. No run with a test key is recorded.

Before you start

You need an API key whose scopes include agents:read and agents:write. The environment of the key decides which Providers the Agent may name, as step 1 explains: a mock Provider runs for test keys only. Keys, scopes and the two environments are explained in Authentication and keys. Replace the placeholder origin with the base URL of your API and the placeholder key with your own.

export VOCAL_API=https://api.example.test
export VOCAL_API_KEY=vk_test_...

Every request carries the key as a bearer credential, and every answer carries X-Request-Id; quote it when you report a problem. A request body is JSON with snake_case fields.

1. Read the Provider catalog

An Agent names a Provider and a model for each stage of its pipeline. GET /v1/providers lists what each Provider offers.

curl "$VOCAL_API/v1/providers?limit=100" \
  -H "Authorization: Bearer $VOCAL_API_KEY"

Look for data, an array of descriptors. Each one has a provider, a stage (stt, llm or tts for this quick start), the models an Agent may name and enabled. A descriptor whose implementation is mock runs only for test keys. The answer also carries object, which is "list", and has_more; while has_more is true, repeat the request with cursor set to the answer's next_cursor. Choose one stt, one llm and one tts descriptor, and one model of each.

Not every descriptor will do. The api checks each reference when it creates the Agent and refuses the ones that break a rule with 422 validation_failed, one issue for each reference, naming its stage, provider, model and a reason:

  • The descriptor is enabled, its lifecycle is available or deprecated, and the model is one of its models that disabled_models does not list. A reserved descriptor has no adapter, and a preview one needs an opt-in of the Organization.
  • A descriptor whose implementation is mock runs for test keys only. With a live key the issue is provider_not_allowed with the reason mock_not_allowed.
  • A transcriber or voice whose descriptor declares streaming: false is refused with capability_mismatch and the reason streaming; so is one whose languages leave out the Agent's language. A descriptor that omits streaming is not refused. The mock transcriber and voice declare streaming: false.
  • The Compliance profile of the Organization must allow the data_regions of the descriptor, and the model must have a list price. The descriptor says neither, so the issue is the only sign: provider_not_allowed with the reason region_not_allowed or model_unpriced.

The runner takes the first descriptor that passes the rules above it can read. It prefers available to deprecated, and a descriptor that processes in us regions only to one that does not, since a new Organization's profile allows us alone.

2. Choose a voice

A voice belongs to a Provider of the tts stage. GET /v1/platform/inventory lists the voices of the Provider you chose.

curl "$VOCAL_API/v1/platform/inventory?kind=voice&provider=<tts_provider>&limit=100" \
  -H "Authorization: Bearer $VOCAL_API_KEY"

Look for object, which is "list", and data, an array of items whose kind is voice. The id of an item is the value an Agent names as its voice_id. When an item lists voice_models in its attributes, name one of those as the voice model; any other model is refused with capability_mismatch and the reason voice_model. Choose a voice whose languages include the Agent's language, as the runner does.

3. Create the Agent draft

POST /v1/agents creates the editable draft. It needs a name, an engine, a language, the instructions and the transcriber, model and voice you chose. Only the cascaded engine is built. Send an Idempotency-Key so that a retry replays the first answer.

curl -X POST "$VOCAL_API/v1/agents" \
  -H "Authorization: Bearer $VOCAL_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Quick start Agent",
    "engine": "cascaded",
    "language": "en",
    "instructions": "You are a friendly assistant for a furniture shop. Answer briefly and ask one question at a time.",
    "transcriber": { "provider": "<stt_provider>", "model": "<stt_model>" },
    "model": { "provider": "<llm_provider>", "model": "<llm_model>" },
    "voice": { "provider": "<tts_provider>", "model": "<tts_model>", "voice_id": "<voice_id>" }
  }'

The answer is 201. Look for object, which is "agent", id beginning agt_, revision, which is 1, latest_version and active_version, both null until you publish, and config. Keep the id and the revision.

A 422 whose issues name a stage, a provider and a reason means a choice from step 1 broke a rule above: read error.details, choose again and resend. Measured on 2026-10-24 UTC with a live key, the Phase 0 host answered 422 validation_failed to a mock model with the issue provider_not_allowed and the reason mock_not_allowed, to the mock transcriber and the mock voice with that issue and capability_mismatch with the reason streaming, and to the Amazon Polly voice with capability_mismatch and the reason streaming.

4. Publish a version

A Call runs a published version, never the draft. POST /v1/agents/{agent_id}/versions publishes the draft whose revision If-Match names, quoted as an ETag is. "activate": true makes the new version the one Calls run.

curl -X POST "$VOCAL_API/v1/agents/agt_.../versions" \
  -H "Authorization: Bearer $VOCAL_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'If-Match: "1"' \
  -H "Content-Type: application/json" \
  -d '{ "activate": true, "notes": "The first version, from the quick start." }'

The answer is 201. Look for object, which is "agent_version", agent_id, version, which is 1, active, which is true, status and config_sha256, the SHA-256 of the canonical configuration in lowercase hex. A stale revision answers 412 revision_mismatch, and a missing If-Match answers 428 precondition_required. Keep the version and the config_sha256.

5. Read the version

GET /v1/agents/{agent_id}/versions/{version} answers the published version. A version is immutable, so it answers what the publish answered.

curl "$VOCAL_API/v1/agents/agt_.../versions/1" \
  -H "Authorization: Bearer $VOCAL_API_KEY"

Look for object, agent_id, version, active and a config_sha256 equal to the one the publish answered.

6. Read the Agent

GET /v1/agents/{agent_id} answers the draft with the numbers of its published versions.

curl "$VOCAL_API/v1/agents/agt_..." \
  -H "Authorization: Bearer $VOCAL_API_KEY"

Look for object, id, revision, and latest_version and active_version, both 1 now. The Agent is ready for a Call: continue with Place a web Call.

Operations and releases

Every operation here is served by the Phase 0 host. The release is the one that first served the operation.

Run it

The repository that builds these pages holds a runner that sends these six requests in order, checks each answer's status and the fields named above, and prints one line per step. See HTTP quick starts for the command and for the record of its run.