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

# Create Agent

> Creates a new agent associated with the specified organization

## Request Body

### Required Fields

<ParamField body="name" type="string" required>
  Display name of the agent (1-255 characters)
</ParamField>

<ParamField body="organizationId" type="string" required>
  Organization ID to create the agent in (UUID format)
</ParamField>

### Agent Configuration

<ParamField body="description" type="string">
  Description of what the agent does
</ParamField>

<ParamField body="greetingMessage" type="string">
  Initial message the agent says when call starts. This is spoken immediately when a call connects.

  Example: `"Hello! Thank you for calling Acme Corp. How can I help you today?"`
</ParamField>

<ParamField body="outboundGreetingMessage" type="string">
  Greeting spoken when this agent places an [outbound call](/api-reference/outbound-calls/overview). Overridden by a per-call `greeting`; if empty, the agent auto-generates an opener from the call context (falling back to `greetingMessage`).

  Example: `"Hi, this is Ava calling from Acme Corp."`
</ParamField>

<ParamField body="systemPrompt" type="string">
  System prompt defining agent behavior and personality. This guides the AI's responses throughout the conversation.

  Example: `"You are a helpful customer support agent for Acme Corp. Be friendly, professional, and concise. If you don't know an answer, offer to transfer the call to a human agent."`
</ParamField>

<ParamField body="agentType" type="string" default="simple">
  Type of agent configuration.

  **Supported values:**

  * `simple` - Basic agent with standard configuration
  * `advanced` - Agent with additional features enabled
  * `custom` - Fully customizable agent configuration
  * `appointment_scheduler` - Agent optimized for scheduling appointments
  * `receptionist` - Receptionist agent for call routing and transfers
  * `message_taker` - Agent that takes messages and routes to directory extensions
</ParamField>

<ParamField body="status" type="string" default="active">
  Activation status of the agent. Defaults to `active` when omitted, so most callers can leave this out.

  **Supported values:**

  * `active` - Agent is live and can take calls
  * `inactive` - Agent is disabled and will not take calls
  * `cancelled` - Agent has been cancelled
  * `pending` - Agent is awaiting activation

  Any other value (for example `draft`) is rejected with a `400`. The same values can be changed later via [Update Agent](/api-reference/agents/update).
</ParamField>

### AI/Voice Model Configuration

<ParamField body="model" type="string" default="gpt-4.1">
  AI model used for the agent's language processing. See [List LLM Models](/api-reference/llm-models) for the full list with descriptions.

  **Supported values:**

  * `gpt-4.1` - OpenAI GPT-4.1 (default, recommended)
  * `gpt-4.1-mini` - OpenAI GPT-4.1 Mini (faster, more cost-effective)
  * `gpt-4o-mini` - OpenAI GPT-4o Mini
  * `grok-3-fast` - xAI Grok-3 Fast
  * `moonshotai/Kimi-K2.6` - Moonshot AI Kimi K2.6 (served via Telnyx)
  * `claude-sonnet-4-6` - Anthropic Claude Sonnet
</ParamField>

<ParamField body="voiceModel" type="string" default="gpt-4o-realtime-preview">
  Voice model for real-time speech processing
</ParamField>

<ParamField body="sttModel" type="string" default="deepgram">
  Speech-to-text model.

  **Supported values:**

  * `deepgram` - Deepgram STTv2 with flux-general-en model (recommended)
</ParamField>

<ParamField body="ttsModel" type="string" default="cartesia">
  Text-to-speech model.

  **Supported values:**

  * `cartesia` - Cartesia TTS (high quality, supports custom voices)
  * `minimax` - MiniMax TTS (multilingual support)
  * `inworld` - Inworld TTS (set `voiceSettings.voice_id` to a full Inworld voice string, e.g. `Inworld.TTS2.Ashley`)
</ParamField>

<ParamField body="voiceSettings" type="object">
  Voice configuration settings. Structure varies based on `ttsModel`.

  <Info>
    **Default when omitted:** For a **Cartesia** agent (the default `ttsModel`), omitting `voiceSettings` creates the agent with the standard voice `f786b574-daa5-4673-aa0c-cbe3e8534c02` (*Katie – Friendly Fixer*) on the **`sonic-3.5`** model. For a **MiniMax** agent, omitting `voiceSettings` leaves it unset.
  </Info>

  **For Cartesia (`ttsModel: "cartesia"`):**

  ```json theme={null}
  {
    "voice_id": "f786b574-daa5-4673-aa0c-cbe3e8534c02",
    "speed": 1.0
  }
  ```

  Cartesia voices also accept two optional fields:

  | Property   | Type   | Description                                                                                                                                                                                                                                                                            |
  | ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `model`    | string | Cartesia TTS model — one of `sonic-2`, `sonic-3`, or `sonic-3.5`. On a Cartesia voice, must be `sonic-3` or `sonic-3.5` to use custom `pronunciations` (Inworld supports them on any model; MiniMax supports them on English agents only), **and for any custom (cloned) `voice_id`**. |
  | `language` | string | Locale passed to Cartesia TTS (e.g. `es`). When set, must match the language registered for the selected `voice_id`.                                                                                                                                                                   |

  <Warning>
    A **custom (cloned)** `voice_id` requires `model` `sonic-3` or `sonic-3.5`; set `voiceSettings.model` to one of these or the request is rejected with `400`.
  </Warning>

  English Cartesia voices accept a `model` override (e.g. `sonic-3.5`, the default for new agents) but not a `language` override. Non-English voices (e.g. Spanish) require both a `model` and a matching `language`:

  ```json theme={null}
  {
    "voice_id": "d46e87a1-7c6d-4b18-9359-926f4a35ffdf",
    "model": "sonic-3",
    "language": "es",
    "speed": 1.0
  }
  ```

  **For MiniMax (`ttsModel: "minimax"`):**

  ```json theme={null}
  {
    "voice_id": "English_radiant_girl",
    "model": "speech-2.6-turbo",
    "speed": 1.0
  }
  ```

  **Advanced Voice Timing** (optional, applies to all TTS models):

  | Property                   | Type   | Default            | Description                                                                                                                                             |
  | -------------------------- | ------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `min_endpointing_delay`    | number | `0.1`              | Seconds to wait after the caller stops speaking before the agent responds. Lower values feel more responsive; higher values reduce false interruptions. |
  | `max_endpointing_delay`    | number | `2.0`              | Maximum seconds to wait when the caller pauses mid-sentence. Prevents the agent from cutting in during natural speech pauses.                           |
  | `vad_min_silence_duration` | number | *(system default)* | Minimum silence duration in seconds for Voice Activity Detection to consider speech ended. Omit to use the system default.                              |

  **Example with advanced timing:**

  ```json theme={null}
  {
    "voice_id": "f786b574-daa5-4673-aa0c-cbe3e8534c02",
    "speed": 1.0,
    "min_endpointing_delay": 0.1,
    "max_endpointing_delay": 5.0,
    "vad_min_silence_duration": 0.55
  }
  ```
</ParamField>

### Call Features

<ParamField body="transferEnabled" type="boolean" default="false">
  Whether SIP call transfer is enabled. When enabled, the agent can transfer calls to:

  * **SIP extensions**: Format `sip:extension@hostname`
  * **US phone numbers**: Automatically formatted to `tel:+1XXXXXXXXXX`
</ParamField>

<ParamField body="emailToolEnabled" type="boolean" default="false">
  Whether the agent can send emails during or after calls
</ParamField>

<ParamField body="emailToolInstructions" type="string">
  Instructions for the agent on how and when to use the email tool
</ParamField>

<ParamField body="callDetection" type="boolean" default="false">
  Whether to enable answering machine / voicemail detection
</ParamField>

<ParamField body="echoDetection" type="boolean" default="false">
  Whether to enable echo detection during calls
</ParamField>

<ParamField body="enableRecording" type="boolean" default="false">
  Enable call recording. Recordings are saved to cloud storage and accessible via the Call Logs API.
</ParamField>

<ParamField body="sendRecordingLinkWithSummary" type="boolean" default="false">
  Include a link to the call recording in the post-call summary notification. This is a sub-option of call recording — it requires `enableRecording: true`. Sending `true` without recording enabled returns a `400`. Note: the link is delivered via the call-summary email, so it is only actually sent when the agent also has an `email` recipient configured and a recording was produced; otherwise the flag is stored but has no effect.
</ParamField>

<ParamField body="transferRules" type="string">
  Rules and conditions for call transfers. Describes when and where the agent should transfer calls.

  Example: `"Transfer to +15551234567 if the caller asks for billing support. Transfer to +15559876543 for technical issues."`
</ParamField>

<ParamField body="email" type="array">
  Array of email addresses used for notifications and the email tool.

  Example: `["support@company.com", "admin@company.com"]`
</ParamField>

<ParamField body="emailServerId" type="string | null">
  UUID of the email server to use for this agent. Must belong to the same account. If omitted or `null`, the account's default email server is used.

  Use the [List Email Servers](/api-reference/email-servers/list) endpoint to retrieve available IDs.
</ParamField>

### Localization

<ParamField body="language" type="string" default="en-US">
  Agent language for speech recognition and responses.

  **Supported values:**

  * `en-US` - English (US)
  * `es-US` - Spanish (US)
  * `multi` - Multilingual (English, Spanish, French, German, Hindi, Russian, Portuguese, Japanese, Italian, Dutch)
</ParamField>

<ParamField body="timezone" type="string" default="America/New_York">
  Agent timezone in IANA format. Used for date/time operations and calendar scheduling.

  Example: `"America/New_York"`, `"Europe/London"`, `"Asia/Tokyo"`
</ParamField>

### Knowledge Base

<ParamField body="knowledgebaseLinks" type="array">
  Array of URLs the agent can reference for knowledge. The content at these URLs is ingested and made available to the agent during conversations.

  This is a legacy field and is **not** the RAG Knowledge Base — for vector search use `ragEnabled` and `knowledgeBaseId` below.

  Example: `["https://example.com/faq", "https://example.com/pricing"]`
</ParamField>

### RAG Knowledge Base

Attach an organization-level [Knowledge Base](/api-reference/knowledge-bases/overview) as part of the create request, so you do not need a follow-up Update Agent call.

<ParamField body="ragEnabled" type="boolean">
  Enable live vector search during calls. Requires `knowledgeBaseId` — an agent with no knowledge base does not retrieve regardless of this flag. Returns `403 forbidden` when Knowledge Base is not enabled for the target organization.
</ParamField>

<ParamField body="knowledgeBaseId" type="string | null">
  Knowledge base the agent searches. It must belong to the same organization the agent is being created in; a knowledge base from another organization is rejected.

  Use [List Knowledge Bases](/api-reference/knowledge-bases/list-create) to retrieve available IDs.
</ParamField>

<ParamField body="ragConfig" type="object">
  RAG retrieval configuration. Unknown keys are rejected.

  | Property             | Type               | Description                                                          |
  | -------------------- | ------------------ | -------------------------------------------------------------------- |
  | `top_k`              | integer (1-50)     | Number of chunks to retrieve per query.                              |
  | `rewrite_query`      | boolean            | Rewrite the caller's phrasing into a search query before retrieving. |
  | `max_context_tokens` | integer (1-200000) | Cap on retrieved context injected into the prompt.                   |
  | `fallback_message`   | string             | What the agent says when retrieval returns nothing useful.           |
</ParamField>

<RequestExample>
  ```bash Create an agent with a knowledge base theme={null}
  curl -X POST https://api.telzino.com/v1/agents \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Support Agent",
      "organizationId": "987fcdeb-51a2-3bc4-d567-890123456789",
      "ragEnabled": true,
      "knowledgeBaseId": "11111111-1111-1111-1111-111111111111",
      "ragConfig": { "top_k": 5, "rewrite_query": true }
    }'
  ```
</RequestExample>

Omitting these fields leaves the defaults in place: `rag_enabled` is `false`, `knowledge_base_id` is `null`, and `rag_config` is `{ "top_k": 5, "rewrite_query": false }`.

### Business (Google Place)

<ParamField body="googlePlaceId" type="string">
  Google Place ID linking the agent to a [Google Business Profile listing](/integrations/google-business). The platform fetches the listing's details (hours, location, phone, website, services, ratings) shortly after creation, and the agent uses them as verified facts when answering callers.

  Example: `"ChIJVS6XxJPFU4gRoE8c8ql2lCQ"`
</ParamField>

### Warm Transfer

<ParamField body="warmTransferEnabled" type="boolean">
  Enable warm transfer routing for this agent.
</ParamField>

<ParamField body="warmTransferRules" type="string">
  Plain-language rules for when and where to warm transfer. Example: `"If the caller asks for billing, confirm first and warm transfer to pbx:1234."`
</ParamField>

<ParamField body="warmTransferMohUrl" type="string">
  Public URL of the hold-music file played during warm transfer. The easiest way to set this is [Upload Hold Music](/api-reference/agents/upload-moh), which saves the URL for you. Leave empty for built-in hold music.
</ParamField>

<ParamField body="warmTransferPassThroughCallerNumber" type="boolean">
  Whether the original caller's number is passed to the transfer destination. Defaults to `true`.
</ParamField>

### Pronunciations

<ParamField body="pronunciations" type="array">
  Custom pronunciation rules for specific words and names, using IPA (International Phonetic Alphabet) format. The agent's TTS engine will use these rules to pronounce words correctly.

  <Note>
    Custom pronunciations are supported on **Inworld** voices, **Cartesia** voices using the **`sonic-3`** or **`sonic-3.5`** model, and **MiniMax** voices on **English** agents only. They are not supported on Cartesia `sonic-2`, nor on MiniMax when `language` is `es-US` or `fr-FR` — MiniMax accepts pronunciation phonemes for English only and mis-renders Spanish and French. Set `ttsModel` to `minimax` or `inworld`, or to `cartesia` with `voiceSettings.model` set to `sonic-3` or `sonic-3.5`; otherwise a non-empty `pronunciations` array is rejected with `400`. Send an empty array `[]` to clear rules on any voice.

    You store each pronunciation once and it works on any supported voice, provided it was generated with **Apply** — the phonemes must be IPA in Cartesia's `<<…>>` form. Hand-typed free-text `phonemes` work on Cartesia only and are **silently ignored** on MiniMax and Inworld, and rules generated for a Spanish or French voice are ignored on MiniMax. Multi-word entries such as `New York` work on Cartesia but are ignored on MiniMax and Inworld, whose syntax covers a single word each.

    Each entry also accepts an optional **`lang`** (`en` | `es` | `fr`) recording which language the phonemes were written for. It decides whether MiniMax can speak the row — MiniMax accepts English phonemes only. Omit it and the agent's `language` is used as the fallback.
  </Note>

  Each entry is an object with:

  * `word` — The word or name (1–100 characters)
  * `phonetic` *(optional)* — A plain-English respelling of how the word should sound (e.g., `jay-kob-sen`). Used by the dashboard's "Apply" helper to generate the IPA `phonemes`; not used directly by the agent.
  * `phonemes` — The IPA phoneme string (e.g., `<<ˈ|dʒ|eɪ|k|ə|b|s|ə|n>>`)
  * `lang` *(optional)* — `en` | `es` | `fr`. Which language the phonemes were written for, recorded when they are generated. Decides whether MiniMax can speak the row (MiniMax accepts English phonemes only); omit it and the agent's `language` is used as the fallback.

  **Example:**

  ```json theme={null}
  [
    { "word": "Telzino", "phonemes": "<<t|ɛ|l|ˈz|iː|n|oʊ>>" },
    { "word": "Jacobsen", "phonetic": "jay-kob-sen", "phonemes": "<<ˈ|dʒ|eɪ|k|ə|b|s|ə|n>>" }
  ]
  ```
</ParamField>

### Advanced Configuration

<ParamField body="config" type="object">
  General configuration object for additional settings.

  **Example:**

  ```json theme={null}
  {
    "enable_recording": true,
    "user_timezone": "America/New_York",
    "inactivity_timeout": 15
  }
  ```

  | Property                   | Type    | Description                                                                                                                                                                                                                       |
  | -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `enable_recording`         | boolean | Enable call recording (saved to S3)                                                                                                                                                                                               |
  | `user_timezone`            | string  | IANA timezone for calendar operations (e.g., `America/New_York`)                                                                                                                                                                  |
  | `inactivity_timeout`       | number  | Seconds before "Are you still there?" prompt (default: 15)                                                                                                                                                                        |
  | `ambient_type`             | string  | Type of ambient background audio                                                                                                                                                                                                  |
  | `ambient_volume`           | number  | Volume level for ambient audio                                                                                                                                                                                                    |
  | `thinking_sounds_enabled`  | boolean | Enable thinking/processing sounds during pauses                                                                                                                                                                                   |
  | `thinking_volume`          | number  | Volume level for thinking sounds                                                                                                                                                                                                  |
  | `thinking_clip_id`         | string  | Sound clip to play while the agent is thinking. `KEYBOARD_TYPING` (default) or `KEYBOARD_TYPING2`                                                                                                                                 |
  | `background_audio_enabled` | boolean | Enable background audio during calls                                                                                                                                                                                              |
  | `confirm_transfers`        | boolean | When `true`, the agent confirms a transfer is answered before connecting the caller — via a press-1 keypress, or via BLF presence for registered SIP extensions. Defaults to `false`. Only applies when call transfer is enabled. |
  | `summary_context`          | string  | Additional instructions for the AI-generated call summary. Use this to tell the summary what to focus on or what data to extract (e.g., `"Focus on customer complaints. Extract any mentioned order numbers."`).                  |
</ParamField>

<ParamField body="extensions" type="object">
  Extensions configuration for webhooks and MCP servers.

  **Structure:**

  ```json theme={null}
  {
    "tools": [
      {
        "type": "webhook",
        "name": "Create_Support_Ticket",
        "friendlyName": "Create Ticket",
        "description": "Creates a support ticket when the customer reports an issue",
        "condition": "after_call",
        "method": "POST",
        "url": "https://api.helpdesk.com/v2/tickets",
        "headers": [
          { "key": "Authorization", "value": "Bearer YOUR_API_TOKEN" },
          { "key": "Content-Type", "value": "application/json" }
        ],
        "parameters": [
          { "key": "subject", "value": "" },
          { "key": "description", "value": "" },
          { "key": "customer_email", "value": "unknown@example.com" },
          { "key": "priority", "value": "normal" }
        ]
      }
    ],
    "mcp_servers": [
      {
        "url": "https://mcp.acme.com/mcp",
        "name": "Acme CRM MCP"
      }
    ]
  }
  ```

  **Webhook fields:**

  | Field          | Type   | Required | Description                                                            |
  | -------------- | ------ | -------- | ---------------------------------------------------------------------- |
  | `type`         | string | Yes      | Must be `"webhook"`                                                    |
  | `name`         | string | Yes      | Unique identifier (e.g., `Create_Ticket`)                              |
  | `friendlyName` | string | Yes      | Human-readable display name                                            |
  | `description`  | string | Yes      | What the webhook does - helps AI understand when to use it             |
  | `condition`    | string | Yes      | When to trigger: `before_call`, `during_call`, or `after_call`         |
  | `method`       | string | Yes      | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`                |
  | `url`          | string | Yes      | Endpoint URL to call                                                   |
  | `headers`      | array  | No       | Array of `{key, value}` objects for HTTP headers                       |
  | `parameters`   | array  | No       | Array of `{key, value}` objects - AI extracts values from conversation |

  **Webhook conditions:**

  * `before_call` - Execute before the agent answers (pre-fetch caller info)
  * `during_call` - Execute while call is active (create tickets, real-time lookups)
  * `after_call` - Execute after call ends (log to CRM, send summaries)

  <Info>
    **Parameters:** Leave the `value` empty for fields you want the AI to extract from the conversation. Provide default values for fallbacks.
  </Info>
</ParamField>

#### MCP Servers Request Body

Each entry in the `mcp_servers` array inside `extensions` is validated at write time. The request shape is different from the stored shape returned by GET.

Validated request fields for each `mcp_servers` entry:

| Field                    | Type   | Required | Description                                                                                                                                  |
| ------------------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                   | string | Yes      | Friendly label for the connection (displayed in the Portal)                                                                                  |
| `url`                    | string | Yes      | MCP endpoint URL. Use your streamable HTTP endpoint when `transport_type` is `"http"`, or your SSE endpoint when `transport_type` is `"sse"` |
| `transport_type`         | string | No       | `"sse"` (default) or `"http"`                                                                                                                |
| `auth_headers`           | array  | No       | Array of `{key, value}` objects sent as HTTP headers to the MCP server                                                                       |
| `initialization_options` | object | No       | Optional MCP initialization options stored with the connection                                                                               |

After saving, the platform transforms each entry to the stored MCPConnection format: `name` → `connection_name`, `url` → `mcp_endpoint_url`, `auth_headers` array → header object, and assigns a generated `id`. See [Get Agent — Stored MCP Connection Shape](/api-reference/agents/get#stored-mcp-connection-shape) for the full list of stored fields.

<Warning>
  The [Get Agent](/api-reference/agents/get) response returns the stored shape with snake\_case keys: `id`, `connection_name`, `mcp_endpoint_url`, `transport_type` (lowercase `sse` or `http`), and optional `tools` entries with `name` and `description` only. Do not paste a GET `mcp_servers` array into a create or update body without transforming it to match the request fields above.

  The schema is **strict** — any unrecognized field in an `mcp_servers` entry (for example, fields from the stored GET shape such as `connection_name`, `mcp_endpoint_url`, or `id`) will be rejected with a `400` error. Only `url`, `name`, `transport_type`, `auth_headers`, and `initialization_options` are accepted.
</Warning>

<Note>
  **MCP servers are auto-tested on save.** When you include `extensions.mcp_servers`, the API tests each server (opening the transport and listing tools). Reachable servers are stored with a `fingerprint` and discovered `tools`, and appear with a green **Connected** badge in the Portal (agent → **Integrations** → **MCP**). Servers that are unreachable at save time are still stored, but without a `fingerprint` — they appear with a yellow **Not tested** badge, and the response includes a non-fatal `warnings` array:

  ```json theme={null}
  { "data": { "...": "..." }, "warnings": [{ "connection_name": "Acme CRM MCP", "message": "Connection failed" }] }
  ```

  To validate a configuration before creating an agent, use [Test MCP Connection](/api-reference/mcp/test-connection).
</Note>

<Note>
  The `integrations` field cannot be set on create. After creating the agent, configure integrations (ModMed, Google/Outlook Calendar, Twilio, NetSapiens) via the Dashboard or with the [`integrations` field on Update Agent](/api-reference/agents/update#integrations). Integration secrets are write-only — they never appear in API responses, including this endpoint's response. MCP servers can be configured in the Dashboard under agent Integrations, or via `extensions.mcp_servers` on this endpoint and on [Update Agent](/api-reference/agents/update).
</Note>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.telzino.com/v1/agents \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Customer Support Agent",
      "organizationId": "123e4567-e89b-12d3-a456-426614174000",
      "description": "Handles customer inquiries and support requests",
      "greetingMessage": "Hello! Thank you for calling Acme Corp. How can I help you today?",
      "systemPrompt": "You are a helpful customer support agent for Acme Corp. Be friendly and professional. If the customer needs to speak with a human, use the transfer_call function.",
      "agentType": "simple",
      "model": "gpt-4.1",
      "ttsModel": "cartesia",
      "voiceSettings": {"voice_id": "f786b574-daa5-4673-aa0c-cbe3e8534c02", "speed": 1.0},
      "transferEnabled": true,
      "transferRules": "Transfer to +15551234567 if the caller asks for billing support",
      "language": "en-US",
      "timezone": "America/New_York",
      "enableRecording": true,
      "knowledgebaseLinks": ["https://example.com/faq", "https://example.com/pricing"],
      "email": ["support@acmecorp.com"]
    }'
  ```

  ```bash With extensions (webhook + MCP) theme={null}
  curl -X POST https://api.telzino.com/v1/agents \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Support Agent with Integrations",
      "organizationId": "123e4567-e89b-12d3-a456-426614174000",
      "systemPrompt": "You are a helpful customer support agent. After every call, create a ticket using the Create_Ticket tool.",
      "model": "gpt-4.1",
      "ttsModel": "cartesia",
      "voiceSettings": {"voice_id": "f786b574-daa5-4673-aa0c-cbe3e8534c02"},
      "language": "en-US",
      "timezone": "America/New_York",
      "extensions": {
        "tools": [
          {
            "type": "webhook",
            "name": "Create_Ticket",
            "friendlyName": "Create Support Ticket",
            "description": "Creates a support ticket in Freshdesk after every call",
            "condition": "after_call",
            "method": "POST",
            "url": "https://yourcompany.freshdesk.com/api/v2/tickets",
            "headers": [
              { "key": "Authorization", "value": "Basic YOUR_FRESHDESK_API_KEY" },
              { "key": "Content-Type", "value": "application/json" }
            ],
            "parameters": [
              { "key": "subject", "value": "" },
              { "key": "description", "value": "" },
              { "key": "customer_email", "value": "" },
              { "key": "priority", "value": "2" }
            ]
          }
        ],
        "mcp_servers": [
          {
            "name": "Acme CRM",
            "url": "https://mcp.acmecrm.com/sse",
            "transport_type": "sse",
            "auth_headers": [
              { "key": "Authorization", "value": "Bearer YOUR_CRM_TOKEN" }
            ]
          }
        ]
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.telzino.com/v1/agents', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'Customer Support Agent',
      organizationId: '123e4567-e89b-12d3-a456-426614174000',
      description: 'Handles customer inquiries',
      greetingMessage: 'Hello! How can I help you today?',
      systemPrompt: 'You are a helpful customer support agent...',
      agentType: 'simple',
      model: 'gpt-4.1',
      ttsModel: 'cartesia',
      voiceSettings: { voice_id: 'f786b574-daa5-4673-aa0c-cbe3e8534c02', speed: 1.0 },
      transferEnabled: true,
      transferRules: 'Transfer to +15551234567 if the caller asks for billing support',
      language: 'en-US',
      timezone: 'America/New_York',
      enableRecording: true,
      knowledgebaseLinks: ['https://example.com/faq', 'https://example.com/pricing'],
      email: ['support@acmecorp.com']
    })
  });

  const { data } = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.telzino.com/v1/agents',
      headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
      json={
          'name': 'Customer Support Agent',
          'organizationId': '123e4567-e89b-12d3-a456-426614174000',
          'description': 'Handles customer inquiries',
          'greetingMessage': 'Hello! How can I help you today?',
          'systemPrompt': 'You are a helpful customer support agent...',
          'agentType': 'simple',
          'model': 'gpt-4.1',
          'ttsModel': 'cartesia',
          'voiceSettings': {'voice_id': 'f786b574-daa5-4673-aa0c-cbe3e8534c02', 'speed': 1.0},
          'transferEnabled': True,
          'transferRules': 'Transfer to +15551234567 if the caller asks for billing support',
          'language': 'en-US',
          'timezone': 'America/New_York',
          'enableRecording': True,
          'knowledgebaseLinks': ['https://example.com/faq', 'https://example.com/pricing'],
          'email': ['support@acmecorp.com']
      }
  )

  agent = response.json()['data']
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "data": {
      "id": "abc12345-e89b-12d3-a456-426614174000",
      "organization_id": "123e4567-e89b-12d3-a456-426614174000",
      "name": "Customer Support Agent",
      "description": "Handles customer inquiries",
      "greeting_message": "Hello! How can I help you today?",
      "system_prompt": "You are a helpful customer support agent...",
      "agent_type": "simple",
      "model": "gpt-4.1",
      "voice_model": "gpt-4o-realtime-preview",
      "stt_model": "deepgram",
      "tts_model": "cartesia",
      "voice_settings": {"voice_id": "f786b574-daa5-4673-aa0c-cbe3e8534c02", "speed": 1.0},
      "config": {},
      "extensions": {},
      "integrations": {},
      "transfer_enabled": true,
      "transfer_rules": "Transfer to +15551234567 if the caller asks for billing support",
      "language": "en-US",
      "timezone": "America/New_York",
      "enable_recording": true,
      "echo_detection": false,
      "call_detection": false,
      "knowledgebase_links": ["https://example.com/faq", "https://example.com/pricing"],
      "email": ["support@acmecorp.com"],
      "email_tool_enabled": false,
      "email_server_id": null,
      "pronunciations": [],
      "status": "active",
      "is_active": true,
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-01-15T10:30:00Z"
    }
  }
  ```

  ```json 400 theme={null}
  {
    "error": "Invalid request data",
    "details": [
      {"path": ["name"], "message": "Name is required"}
    ]
  }
  ```

  ```json 403 theme={null}
  {
    "error": "forbidden",
    "error_description": "No access to this organization"
  }
  ```
</ResponseExample>

## Built-in Agent Functions

When created, every agent automatically has access to these functions that the AI can call during conversations:

| Function                        | Description                                                                            |
| ------------------------------- | -------------------------------------------------------------------------------------- |
| `transfer_call(phone_number)`   | Transfer call to a SIP extension or US phone number (requires `transferEnabled: true`) |
| `end_call()`                    | End the current call gracefully                                                        |
| `get_date_details(date_string)` | Parse and get details about a date/time                                                |

<Note>
  Additional functions are added based on enabled integrations (Google Calendar, Outlook, ModMed), configured webhook tools in `extensions.tools`, and MCP servers in `extensions.mcp_servers`.
</Note>

## Feature Administration gating

When [Feature Administration](/admin-guide/dashboard/feature-administration) is enabled, agent creation is validated against the feature gates of the target organization — including locks inherited from its reseller or partner. The API returns `403 forbidden` when the request:

* sets `warmTransferEnabled: true` while **Warm Transfer** is locked;
* selects a cloned voice in `voiceSettings.voice_id` while **Custom Voices** is locked;
* sets a non-empty `googlePlaceId` while **Business Listing (Google Places)** is locked;
* includes the `ns_send_sms` or `ns_check_sms_replies` tool in `extensions.tools` while **SMS Messaging** is locked.

  <Warning>
    If you are seeding `extensions.tools` by copying them from an existing agent, do not paste a `GET` response verbatim. `tools[].type` accepts only the values in its enum (`webhook`, `tool`, `notification`, `function`, `transfer_agent`, `end_of_call_action`), which exclude the internal type a `GET` returns for UCaaS tools such as these. Such a request is rejected with `400` by schema validation before any gate runs — a pre-existing limitation of this endpoint, unrelated to Feature Administration.
  </Warning>

Omitting a field, or sending it as `null`, is never blocked — so you can always create an agent without the locked capability.
