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

# Give your voice agent a face: the agent's mascot

> Every agent has a mascot, an animated face drawn from a small spec. Change its look, generate one from a website, share it, or draw it in your own web or Flutter app.

Every agent has a mascot: an animated face people see while they talk to the
agent. It is the agent's `mascot` field. It is made with the agent and deleted
with it, and there is one per agent.

A new agent starts with the default mascot, a green squircle with two dark
eyes. Change it whenever you like.

```json theme={null}
{
  "id": "ag_01HXYZ",
  "name": "Molly",
  "mascot": {
    "spec": { "format": "wixzel.mascot", "version": 1, "name": "Molly", "color": "#a0d425", "...": "..." },
    "welcome_message": null,
    "status": "ready",
    "public_id": null,
    "sharing": { "link": false, "embed": false, "embed_origins": [], "...": "..." }
  }
}
```

In the console, it is the **Mascot** tab of the agent's page.

## Change the look

A mascot is one shape and two eyes, described by `spec`. Send the whole spec
you want; numbers out of range are clamped, and the response shows the spec as
saved.

```bash theme={null}
curl -X PATCH https://api.voice.wixzel.com/v1/agents/AGENT_ID/mascot \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "spec": {
      "color": "#1388ff",
      "shape": { "kind": "drop", "rotation": -8 },
      "eyes": { "style": "pill", "color": "#ffffff" }
    }
  }'
```

`welcome_message` in the same request sets what its speech bubble says before
a call. Without one it uses the agent's `opening_message`.

## Generate a look from a website

```bash theme={null}
curl https://api.voice.wixzel.com/v1/agents/AGENT_ID/mascot/generate \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "website_url": "https://example.com" }'
```

Send a `website_url`, a `description`, or both. Send neither for a random look.
It answers at once with `mascot.status: "building"`. Poll `GET /v1/agents/{id}`
until it is `ready` or `failed`, usually in under a minute. A failed build
keeps the look it had.

Only the look changes. The agent's prompt never does, and its knowledge base
stays as it is unless you send `"refresh_knowledge": true`. See
[Knowledge bases](/knowledge-bases.md#agents-made-from-a-website).

To make a whole agent from a website (name, prompt, opening line, language,
knowledge base and look), use `POST /v1/agents/generate` instead.

## Share it

Two ways for other people to talk to your agent through its mascot. Both are
off until you turn them on, and their calls are billed per second to your
credit.

| | What it is |
| - | - |
| **Share link** | A page anyone with the link can open and call from |
| **Website widget** | A mascot in the corner of your site, on the origins you list only |

```bash theme={null}
curl -X PATCH https://api.voice.wixzel.com/v1/agents/AGENT_ID/mascot \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sharing": {
      "link": true,
      "embed": true,
      "embed_origins": ["https://example.com", "https://www.example.com"]
    }
  }'
```

Turning either on needs `calls:write` as well as `agents:write`. The mascot then
has a `public_id`, like `m_4fT9qLx2Bv8K`. It is the id in the share link and in
the widget:

```html theme={null}
<script src="https://voice.wixzel.com/embed.js" data-mascot="m_4fT9qLx2Bv8K" async></script>
```

The widget can run [client tools](/tools.md#on-your-website-your-agents-mascot)
on your page.

`POST /v1/agents/{id}/mascot/rotate-public-id` gives it a new `public_id`. The
old link and embed code stop working at once.

### Caps

Public calls stay inside the numbers in `sharing`:

| Field | Default | What it limits |
| - | - | - |
| `max_call_seconds` | 300 | The longest public call |
| `daily_minutes` | 60 | Public minutes a day, everyone together, until midnight UTC |
| `calls_per_visitor_daily` | 3 | Calls one visitor may make a day |
| `max_concurrent_calls` | 2 | Public calls at the same time |

## Who can call

`sharing.caller_info` sets what a caller gives before a call through the share
link or the website widget. People calling from the Wixzel Voice app are
already signed in.

| `caller_info` | What the caller does first | What you get |
| - | - | - |
| `none` (default) | Nothing | Their approximate location and device |
| `contact` | Types a name and a phone number or email | That name and contact, not checked |
| `google` | Signs in with Google | Their Google name and email, checked by Google |

```bash theme={null}
curl -X PATCH https://api.voice.wixzel.com/v1/agents/AGENT_ID/mascot \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sharing": { "caller_info": "google" } }'
```

A Google sign-in only tells you who the caller is. It never creates a Wixzel
account for them. On your website, the widget opens the sign-in in a small
window on voice.wixzel.com, which hands the result back only to a site in
`embed_origins`.

Every web call also records:

* An approximate location: city, region and country, worked out from the
  caller's IP address. The address itself is kept only as a hash.
* The browser, operating system and device type, from the browser's
  User-Agent.
* The page the caller was on, for website widget calls.
* A random id the browser keeps, so one person's calls group together.

There is no fingerprinting. The share page and the widget tell callers that
their name (when asked), approximate location and device are shared with you.

You see all of this on each call (its `caller` field) and in
[Callers](/callers.md).

## Blocking callers

A blocked caller cannot call that agent again: not from its share link, its
website widget, the app or by phone. They are told "You can’t call this
assistant." Their earlier calls stay as they were.

In the console, open a call on the **Calls** page and choose **Block** on its
Caller card. The agent's **Mascot** tab lists who is blocked, with an
**Unblock** button for each.

With the API:

```bash theme={null}
curl -X PATCH https://api.voice.wixzel.com/v1/callers/CALLER_ID \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "blocked": true }'
```

Send `"blocked": false` to unblock. See [Callers](/callers.md).

## Draw it in your own app

The share link and the website widget are ready to use. To put the mascot in
your own page or app instead, draw it from the agent's `mascot.spec` with one
of these:

| | Package | Draws it with |
| - | - | - |
| **Web** | `wixzel-voice/mascot`, in `wixzel-voice` 0.10.0 or later on npm | `mountMascot` |
| **Flutter** | `wixzel_voice_flutter` on pub.dev | `AgentMascotView` |

Both use the same runtime as the share link, the widget and the Wixzel Voice
app, so the mascot looks and moves the same everywhere. Both can lip-sync it
to a [realtime session](/realtime.md): it listens while the user talks, thinks
while the agent prepares an answer, and moves its mouth in time with the
agent's audio.

```ts Web theme={null}
import { mountMascot } from 'wixzel-voice/mascot';

// `agent` and `session` come from your server
const face = mountMascot(document.getElementById('face')!, { agent, size: 240 });
const call = await face.connect(session, {
  onTranscript: ({ role, text }) => console.log(role, text),
});
```

```dart Flutter theme={null}
final mascot = MascotController();

// `agent` and `session` come from your server
Widget face(Agent agent) => AgentMascotView(agent: agent, controller: mascot);

MascotRealtimeLink talk(RealtimeSession session) =>
    MascotRealtimeLink(mascot, RealtimeConnection.forSession(session));
```

Keep your API key on your server. Fetch the agent and mint the realtime
session there, and send the page or app only the agent's JSON and the session.
In Flutter, your app records and plays the audio itself; the link only moves
the mascot. See [SDKs: Mascot widgets](/sdks.md#mascot-widgets) for install
steps and more of what each package does.

## Delete it

A mascot cannot be deleted on its own. Deleting the agent deletes its mascot,
and its share link and widget stop working.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.