> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pyai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create agents via API

> Create an Omni agent profile, bind knowledge and tools, and open a session with session_label. Console Agents is the no-code path; this is the same object in code.

An **agent profile** stores persona, voice, greeting, and recording consent so you do not send a full `configure` frame on every call. Open Omni with `session_label={agent_id}`. Inline `configure` fields still win for that session.

You can skip this page and [launch an Agent in the console](/agents/getting-started) instead. Both write the same profile.

## Create the profile

Scope: `omni:session`.

```bash theme={null}
curl -X POST https://api.pyai.com/v1/agents \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Front desk",
    "persona_system_prompt": "You are the after-hours receptionist for North Clinic. Answer from the bound knowledge base. Transfer when the caller asks for a human.",
    "greeting": "Thanks for calling North Clinic. How can I help?",
    "voice_id": "stock_ava_en_us",
    "recordings_enabled": true,
    "consent_line": "This call may be recorded for quality and training."
  }'
```

The response includes `id` (`agent_...`). List and read the same objects at `GET /v1/agents` and `GET /v1/agents/{id}`.

## Bind a hosted knowledge base

Scope: `kb:manage` to create the base and documents, `omni:session` to bind.

```bash theme={null}
KB_ID="$(
  curl -sS -X POST https://api.pyai.com/v1/knowledgebases \
    -H "Authorization: Bearer $PYAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "Clinic site"}' \
    | python -c 'import json,sys; print(json.load(sys.stdin)["id"])'
)"

curl -X POST "https://api.pyai.com/v1/knowledgebases/$KB_ID/crawls" \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.example.com", "max_pages": 25}'

curl -X PUT "https://api.pyai.com/v1/agents/agent_.../knowledgebases" \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "[{\"kb_id\": \"$KB_ID\", \"weight\": 1}]"
```

Poll documents until `status` is `indexed` before you treat the site as ready. See [Knowledge bases](/guides/knowledge-bases). If you already run retrieval, keep `kb_endpoint` on the Omni `configure` frame instead.

Sandbox keys from `POST /v1/sandbox/keys` omit `kb:manage`. Create a console key when you need hosted KB writes.

## Bind tools

Register a server tool with `POST /v1/tools`, then `PUT /v1/agents/{id}/tools`. Hosted catalog tools bind by name (`datetime`, `web_search`, and the rest). Do not put `endpoint` or `webhook_url` on the Omni `configure` frame. That is rejected as `unsupported_tool_transport`.

Details: [Omni tools](/guides/omni-tools). Greeting and consent: [Agent greetings](/guides/agent-greeting).

## Open a session

```
wss://api.pyai.com/v1/omni?session_label=agent_...&format=pcm16&rate=24000
```

`session_label` is an opaque tag. When it matches an agent id, Omni loads that profile. The same label is echoed to a customer `kb_endpoint` if you use one.

Auth: `Sec-WebSocket-Protocol: pyai-key.$PYAI_API_KEY` in browsers, or `Authorization: Bearer` on the server. Frame contract: [Omni wire protocol](/realtime/omni-protocol).

## Website or phone

The hosted Call Now button is a console publish: [Add your Agent to a website](/guides/website-voice-widget). Phone numbers stay on [Twilio](/guides/twilio-voice-agent) or managed telephony in the console.

## Next

<CardGroup cols={2}>
  <Card title="Launch an Agent" href="/agents/getting-started">Same profile, console workflow.</Card>
  <Card title="Knowledge bases" href="/guides/knowledge-bases">Hosted files, URLs, and pasted text.</Card>
  <Card title="Omni overview" href="/guides/omni-overview">Connect without a stored profile.</Card>
  <Card title="API reference" href="/api-reference">`/v1/agents` schemas.</Card>
</CardGroup>
