> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.meetstream.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.meetstream.ai/_mcp/server.

# Custom Attributes

> Attach custom key-value metadata to MeetStream bots: echoed in every webhook, filterable in List Bots, visible in the usage dashboard — the backbone of multi-tenant routing and attribution.

`custom_attributes` is a free-form string map you attach at `create_bot`. MeetStream never interprets it — it just **echoes it back everywhere**, which makes it the backbone of routing, attribution, and multi-tenant bookkeeping.

## Set at create time

```json
{
  "meeting_link": "https://meet.google.com/abc-defg-hij",
  "bot_name": "Notetaker",
  "custom_attributes": {
    "customer_id": "cus_8842",
    "environment": "production",
    "job_id": "meeting-sync-1234"
  }
}
```

CLI: `meetstream bot create <link> --attr customer_id=cus_8842 --attr environment=production`.

## Where it comes back

1. **Every webhook event.** Each delivery carries your `custom_attributes` verbatim — route events to the right tenant handler without any lookup table:

```json
{ "event": "bot.stopped", "bot_id": "...", "bot_status": "Stopped",
  "custom_attributes": { "customer_id": "cus_8842", "environment": "production" } }
```

2. **List Bots filtering.** Query your fleet by attribute with `custom_attr[...]` params (conditions combine with AND):

```bash
curl "https://api.meetstream.ai/api/v1/bots?custom_attr[customer_id]=cus_8842&custom_attr[environment]=production" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

3. **Status and detail endpoints** return them alongside the bot's state.

4. **The Usage dashboard** shows per-bot metadata in its cost breakdown — so per-customer usage attribution falls out for free. See [Usage & Retention](/guides/features/usage-and-retention).

## Patterns that work well

* **Multi-tenant routing**: `customer_id` on every bot; webhook handlers dispatch on it with zero database reads.
* **Idempotent job tracking**: put your queue's `job_id` in attributes, and pair with a [`deduplication_key`](/guides/features/deduplication-idempotency-keys) so retries never double-book the meeting.
* **Environment separation**: tag `environment: staging|production` and filter List Bots per environment — or go further and use separate [workspaces](/guides/get-started/workspaces) with separate keys.