> Doc v2.0 · Updated 2026-06-15 · AEvent MCP server "AEvent" · 43-tool consumer surface

# AEvent MCP Tools Reference

This is the complete reference for the AEvent consumer tool surface (43 tools) exposed by the AEvent MCP server (Laravel class `AEventServer`, reported version `0.0.1`, a framework placeholder). It is written for developers and AI agents that drive AEvent over the Model Context Protocol.

Every tool, parameter table, example call, and return shape in this document was verified read-only against the demo tenant `tenant_aevent` on 2026-06-15, or read directly from the live tool schemas. Write/mutating tools are shown with their call shape only and are explicitly marked "illustrative (not executed)". The authoritative schema catalog lives at `01-live-tool-catalog.md`; the real captured outputs live at `04-worked-examples.md`.

---

## How to read this reference

### Endpoint and transport

The AEvent MCP server is reached at:

```
https://app-api.aevent.com/mcp
```

Transport is streamable HTTP (Laravel `Mcp::web`). This is a real MCP server: point any MCP client (Claude, an Agents SDK runtime, etc.) at that URL and it will negotiate over MCP. The endpoint advertises the `mcp-protocol-version` header and sits behind Caddy and Cloudflare. The server identifies itself as `"AEvent"`.

### Authentication

Auth is a single HTTP header:

```
Authorization: Bearer <TOKEN>
```

The token is a Laravel Passport personal-access token carrying the ability `mcp:use`. An unauthenticated request returns HTTP 401 with header `www-authenticate: Bearer realm="mcp", error="invalid_token"`.

> Token provisioning. Generate your token inside the AEvent app at **Settings > Developer**: create a token, check the **`mcp:use`** scope, click Create, and copy it (you cannot read it again). Use it as `Authorization: Bearer <TOKEN>`.

### Account targeting (every call)

Almost every tool accepts two universal account-targeting params:

| Param | Type | Notes |
|-------|------|-------|
| `email` | string | Email address of the customer account to act on behalf of. (Exception: on `show-lead`, `email` means the REGISTRANT, see that tool.) |
| `tenant_id` | string | AEvent tenant ID for the account to act on behalf of. The worked examples use `tenant_id: "tenant_aevent"`. |

Provide one identifier for the target account. In the worked examples we pass `tenant_id`.

### The campaign ID (`wtl`)

Most campaign-scoped tools take `wtl`:

> `wtl` (a.k.a. `webinarTimeline`) is the campaign ID: a 15-character system-generated identifier like `cAJ3f3AjCeqy01F`. Never construct it from a campaign name. Always resolve it with `list-campaigns` first.

### The "required" caveat (important)

The live JSON schemas mark NOTHING as `required`. There is no `required` array on any tool. Functional requirements (for example, `wtl` on action builders, `url` on page setters) are enforced server-side and described in prose, not in the schema. In every parameter table below, the "Required" column states the SERVER-ENFORCED / functional requirement, not what the raw schema says (the raw schema says everything is optional).

### Shared action-builder params

The message/automation builders (`add-email`, `add-text-message`, `add-autochat`, `add-voice-mail`, `add-tag`, `remove-tag`, `add-to-list`, `add-additional-event`) share a standard quartet:

| Param | Type | Notes |
|-------|------|-------|
| `audience` | string | Audience ID or name to target. Leave blank for all registrants. Combine with `and` / `or`. Resolve IDs via `list-audiences`. |
| `eventID` | string | Which additional event to target; blank = main event. Combine with `and` / `or`. Resolve via `list-multi-events`. |
| `integrationID` | string | Which connected integration to use; blank = auto-match. Resolve via `list-campaign-integrations`. |
| `time` | string | Relative-time string, e.g. `"1 day 3 hours 30 minutes after"` or `"1 day before at 3:00pm"`, relative to the event. |

### Discover-before-act

The golden rule for agents: resolve real IDs before any write. In order:

1. `list-campaigns` -> `wtl`
2. `list-campaign-integrations` (or `list-integrations`) -> `integrationID`
3. `list-audiences` -> `audience` id
4. `list-multi-events` -> `eventID`
5. `list-videos` / `list-audio` / `list-images` / `list-nifty-images` -> file IDs

Then call the write tool. Never infer an ID from a name.

---

## Key concepts an agent must hold

- **Campaign** (a.k.a. `wtl` / `webinarTimeline`): the container. Holds settings, the timeline, registration, pages, integrations, audiences, and multi-events. ID like `cAJ3f3AjCeqy01F`.
- **Webinar**: a scheduled instance of a campaign (a dated occurrence). Has its own integer instance `id` (used by `show-event-info`), distinct from `wtl`.
- **Timeline**: the sequence of actions (emails, SMS/MMS, autochat, ringless voicemail, tags, list adds, webhooks) that live INSIDE a campaign. Built by the `add-*` tools.
- **Integrations**: connected services (Twilio, SendGrid/SMTP, GoHighLevel, ActiveCampaign, Zoom, GoToWebinar, calendars, webhooks, etc.).
- **Audiences**: segments. Every campaign has three defaults: `3` Registrants, `a1` Attendee, `a2` Non-Attendee. Campaigns may add custom behavioral segments (UUID-keyed).
- **Multi-Events**: additional events (Day 2, encore, post-event) fanned out from a source event/audience.
- **Format** (read from `general.webinarType`): `automatic` = like-live, `semi-automatic` = hybrid, `manual` = live. Always read the field, do not infer format from the campaign title.

---

# TOOL CATALOG

Tools are grouped by function. Within each group: purpose, parameter table, an example call (real demo IDs), and a real return shape where one was captured.

All example calls use `tenant_id: "tenant_aevent"`. Read tools below were executed read-only; write tools are marked "illustrative (not executed)".

---

## 1. Campaign Management

### list-campaigns

List or search campaigns. Returns campaign name keyed by `wtl`.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | no | Campaign name or partial. Omit to list all. |
| `email` / `tenant_id` | string | one of | Account target. |

Example call:

```json
{ "tool": "list-campaigns", "tenant_id": "tenant_aevent" }
```

Real return (trimmed):

```json
{
  "cAJ3f3AjCeqy01F": "Webinar Scaling Secrets",
  "4WN615HD1rDjDZI": "Multi-Event",
  "5Rb801EvIi0gHDu": "Zoom: AEvent Demo",
  "ebwNo4JbUyo4Ria": "GoToWebinar Example",
  "eNu623BZHtpbYIF": "AStream Example",
  "GyS14phh8RJ7V5U": "3 Day Challenge"
}
```

Canonical example campaigns (use in docs): like-live `Webinar Scaling Secrets` = `cAJ3f3AjCeqy01F`; full behavioral build = `0h84BA1Y5HY4Nmb`; multi-event `Multi-Event` = `4WN615HD1rDjDZI`; Zoom = `5Rb801EvIi0gHDu`; GoToWebinar = `ebwNo4JbUyo4Ria`; AStream = `eNu623BZHtpbYIF`.

### create-campaign

Create a campaign. Returns the new campaign (creates its own `wtl`, so no `wtl` input).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `name` | string | yes | Campaign name. |
| `integrationID` | string | yes | Integration to use with this campaign. |
| `options` | array | no | String modifiers (see below; not schema-enforced, value-validated server-side). |
| `email` / `tenant_id` | string | one of | Account target. |

`options` accepted values (description-only enum, supply correct values): `obvio`, `zoom`, `aevent`, `gotowebinar`, `youtube`, `oneTime`, `multiOption`, `multiSession`, `highDefinition`, `standardDefinition`, `hybrid`, `likeLive`, `live`.

Illustrative (not executed):

```json
{ "tool": "create-campaign", "tenant_id": "tenant_aevent",
  "name": "Demo Like-Live", "integrationID": "aevent",
  "options": ["aevent", "likeLive", "oneTime", "highDefinition"] }
```

### show-campaign

Dump campaign settings and timeline actions by section. For troubleshooting/read use.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `section` | string | no | One of `actions`, `general`, `registration`, `autoresponder`, `integration`, `page` (description-only enum). |
| `email` / `tenant_id` | string | one of | Account target. |

Example call:

```json
{ "tool": "show-campaign", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F", "section": "general" }
```

Real `general` (key fields):

```json
{
  "timelineID": "cAJ3f3AjCeqy01F",
  "campaign_name": "Webinar Scaling Secrets",
  "webinarType": "manual",
  "manualLength": "120",
  "webinarVideoLength": 7200,
  "replay": { "enabled": true, "replayDays": "3", "expireOnMid": 1 },
  "userGroup": [
    { "id": "3",  "name": "Registrants" },
    { "id": "a1", "name": "Attendee" },
    { "id": "a2", "name": "Non-Attendee" }
  ],
  "timelineName": "Webinar Scaling Secrets"
}
```

`section: "actions"` returns timeline actions bucketed by day-key (`"0"` = event day, `"+1"` = 1 day after, `"-1"` = event-day-minus). A real SMS action from the `"0"` bucket:

```json
{
  "id": "_gv0xk3fk2",
  "action": "twilio-textuser",
  "actionTitle": "Send SMS",
  "groupID": "3", "groupName": "Registrants",
  "isAfter": 1, "isExact": false, "minutes": "15",
  "integrationID": "PRuNUNR7aKViPuA", "integrationType": "TWILIO",
  "model": {
    "sms-text": "{{!subscriber-firstName!}}, if you're not on here, you're missing out... Join NOW: {{!subscriber-joinURL!}}",
    "phonenumber": "+17028205445"
  }
}
```

Timing read: `isAfter:1 / isExact:false / minutes:15` in day-key `"0"` = "15 minutes after" the start. This is what the `time` param on the `add-*` builders compiles into.

---

## 2. Webinar Scheduling

### schedule-webinar

Schedule a webinar instance for a campaign.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `integrationID` | string | yes | Connected delivery integration to use. |
| `timestamp` | integer | yes | Start time as a UNIX timestamp (seconds). |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "schedule-webinar", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "integrationID": "aevent", "timestamp": 1781020800 }
```

### list-upcoming-webinars

List upcoming scheduled webinar instances.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | no | Filter by campaign. |
| `page` | integer | no | 100 per page, default 1. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-upcoming-webinars", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

Real return on the demo tenant: `[]` (nothing scheduled). An empty array is the normal "nothing scheduled" response, not an error.

### list-past-webinars

List past webinar instances.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | no | Filter by campaign. |
| `page` | integer | no | 100 per page, default 1. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-past-webinars", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

Demo tenant returned `[]`.

### list-recurring

List recurring entries that regularly create webinars and keep the webinar dropdown filled.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | no | Filter by campaign. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-recurring", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

Demo tenant returned `[]`. Operational note: an AEvent "archive" deletes recurring entries and unarchive does not restore them, so an empty `list-recurring` on an otherwise-configured campaign can indicate a prior archive.

### show-event-info

Show event information (attendance rate, date, etc.) for a single webinar instance.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `id` | integer | yes | The webinar INSTANCE id (from `list-upcoming-webinars` / `list-past-webinars`), NOT the `wtl`. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed, no live instance existed on the demo tenant):

```json
{ "tool": "show-event-info", "tenant_id": "tenant_aevent", "id": 123456 }
```

---

## 3. Integrations

### list-integrations

List all account integrations. Returns the integration name + type + `connected` flag keyed by integrationID.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | no | Integration name or partial. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-integrations", "tenant_id": "tenant_aevent" }
```

Real return (trimmed):

```json
{
  "uJFLoMLeB9zy9dd": { "name": "ACTIVECAMPAIGN", "type": "ACTIVECAMPAIGN", "connected": true },
  "PRuNUNR7aKViPuA": { "name": "TWILIO", "type": "TWILIO", "connected": true },
  "sZ8ak220pmKL67q": { "name": "SendGrid - AEvent", "type": "SMTP", "connected": true },
  "RhKf6nD8Mfe8zmc": { "name": "GOHIGHLEVEL", "type": "GOHIGHLEVEL", "connected": true },
  "DkYzuZVenFShc2D": { "name": "ZOOM (DONT TOUCH PLZ)", "type": "ZOOM", "connected": true },
  "aevent":          { "name": "ASTREAM", "type": "AEVENT", "connected": true }
}
```

Writer notes: `connected: true` is SHALLOW. It does not validate the OAuth token or plan depth (a known trap). An account can hold multiple records of the same type (the demo tenant has three ZOOM and two GMAIL). Always resolve the exact `integrationID` per campaign via `list-campaign-integrations`, never by type alone.

### list-campaign-integrations

List integrations connected to a specific campaign. Returns integration name keyed by integrationID.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-campaign-integrations", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

Real return:

```json
{ "PRuNUNR7aKViPuA": "TWILIO", "uJFLoMLeB9zy9dd": "ACTIVECAMPAIGN" }
```

### test-integration

Test whether an integration is connected and working.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `integrationID` | string | yes | Integration to test. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "test-integration", "tenant_id": "tenant_aevent", "integrationID": "PRuNUNR7aKViPuA" }
```

Caveat: like `connected: true`, a "connected" result is a SHALLOW check. It does not validate token/plan depth.

---

## 4. Registration and Fields

### add-field

Add a single registration field to the campaign's form.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `name` | string | yes | The registration field name. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-field", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F", "name": "Company" }
```

### add-u-t-m

Add the standard UTM parameter set to the registration fields. The live tool name is `add-u-t-m`, displayed "Add U T M".

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-u-t-m", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

---

## 5. Messaging and Automation (timeline builders)

These tools add actions to the campaign timeline. Each shares the `audience` / `eventID` / `integrationID` / `time` quartet defined above. Use `show-merge-fields` first if the copy needs personalization.

### add-email

Add an email action (HTML body).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `subject` | string | yes | Email subject. |
| `message` | string | yes | Email body as HTML. |
| `audience` / `eventID` / `integrationID` / `time` | string | no | Action quartet. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-email", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "subject": "You're in, {{!subscriber-firstName!}}",
  "message": "<p>Your join link: {{!subscriber-joinURL!}}</p>",
  "audience": "3", "integrationID": "sZ8ak220pmKL67q",
  "time": "1 day before at 9:00am" }
```

Real stored shape for an email action (`smtp-sendMail`), for reference:

```json
{
  "action": "smtp-sendMail", "actionTitle": "Send Email",
  "groupID": ["3"], "groupName": "Registrants",
  "integrationID": "sZ8ak220pmKL67q", "integrationName": "SendGrid - AEvent", "integrationType": "SMTP",
  "isAfter": "1", "isExact": true, "hours": 8, "minutes": 0,
  "model": {
    "nameFrom": "Winter - AEvent", "emailFrom": "winter@aevent.com",
    "emailSubject": "Today. Here's what you'll walk away with.",
    "editorData": "<p>{{!subscriber-firstName!}}, it's today... {{!subscriber-joinURL!}}</p>"
  }
}
```

### add-text-message

Add a text message (SMS / MMS) action.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `message` | string | yes | The message text. |
| `fileID` | string | no | For MMS: a stored image/video file ID (from `list-images` / `list-videos`). |
| `niftyImage` | string | no | For an MMS with a NiftyImage: pass the file NAME (from `list-nifty-images`) instead of `fileID`. |
| `niftyFields` | array | no | Array of strings for the NiftyImage dynamic fields. |
| `audience` / `eventID` / `integrationID` / `time` | string | no | Action quartet. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-text-message", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "message": "{{!subscriber-firstName!}}, we go live in 15 min: {{!subscriber-joinURL!}}",
  "audience": "3", "integrationID": "PRuNUNR7aKViPuA",
  "time": "15 minutes before" }
```

Real stored shape (`twilio-textuser`): `model.phonenumber` may be a literal E.164 number OR the keyword `"service"` (use the account's service number).

### add-autochat

Add an autochat action (simulated live chat message posted in the webinar room).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `message` | string | yes | The chat message. |
| `audience` / `eventID` / `time` | string | no | Action params (no `integrationID`; autochat uses the internal ASTREAM `adminwebinar` engine). |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-autochat", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "message": "Quick note from the team: the timeline walkthrough is next.",
  "audience": "3", "time": "5 minutes after" }
```

### add-voice-mail

Add a ringless voicemail action. Get the audio `fileID` from `list-audio` first.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `fileID` | string | yes | Audio file ID (from `list-audio`). |
| `audience` / `eventID` / `integrationID` / `time` | string | no | Action quartet (use a ringless-voicemail integration, e.g. SLYBROADCAST). |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-voice-mail", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "fileID": "<audio-file-id-from-list-audio>",
  "audience": "a2", "integrationID": "bfkt18jAuoayAhg", "time": "1 hour before" }
```

### add-join-message

Add an on-join welcome message shown in chat after a registrant joins.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `message` | string | yes | Message shown in chat to the viewer. |
| `name` | string | yes | Name of the registrant "sending" the message. |
| `after` | integer | no | Seconds after join before the message is shown. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-join-message", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "message": "Welcome! Drop your #1 question in chat.", "name": "Support Team", "after": 30 }
```

### clear-join-messages

Delete ALL on-join welcome messages for the campaign. Destructive; deletes every join message.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "clear-join-messages", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

---

## 6. Tags and Lists (CRM sync actions)

### add-tag

Add an "Add Tag" action to the timeline.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `tag` | string | yes | Tag name to send. |
| `audience` / `eventID` / `integrationID` / `time` | string | no | Action quartet (use the CRM integration that owns the tag). |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-tag", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "tag": "aevent-attended", "audience": "a1",
  "integrationID": "RhKf6nD8Mfe8zmc", "time": "45 minutes after" }
```

Real stored shape (`gohighlevel-addTag`): note `groupID` can be a UUID for a custom behavioral segment (e.g. `attended-thru-cta`) rather than a default audience id.

### remove-tag

Add a "Remove Tag" action to the timeline.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `tag` | string | yes | Tag name to remove. |
| `audience` / `eventID` / `integrationID` / `time` | string | no | Action quartet. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "remove-tag", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "tag": "webinar-lead", "audience": "a1", "integrationID": "RhKf6nD8Mfe8zmc" }
```

### add-to-list

Add a "list" action (add to list, subscribe to campaign, add to workflow, sequence, or group).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `target` | string | yes | Name of the list / campaign / workflow / sequence / group to target. |
| `audience` / `eventID` / `integrationID` / `time` | string | no | Action quartet. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-to-list", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "target": "Attended Webinar", "audience": "a1", "integrationID": "uJFLoMLeB9zy9dd" }
```

---

## 7. Pages

### set-confirmation-page

Set the confirmation page URL for a campaign.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `url` | string | yes | Confirmation page link. |
| `email` / `tenant_id` | string | one of | Account target. |

### set-expired-page

Set the expired page URL for a campaign.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `url` | string | yes | Expired page link. |
| `email` / `tenant_id` | string | one of | Account target. |

### set-replay-page

Set the replay page URL for a campaign.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `url` | string | yes | Replay page link. SCHEMA BUG: the `url` description text says "expired page". It functionally sets the REPLAY page. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed) for all three:

```json
{ "tool": "set-confirmation-page", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F", "url": "https://go.aevent.com/webinar-confirmation" }
{ "tool": "set-expired-page",      "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F", "url": "https://go.aevent.com/expired" }
{ "tool": "set-replay-page",       "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F", "url": "https://go.aevent.com/scaling-secrets-replay" }
```

### set-replay-sequence

Set the replay availability window for a campaign.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `enabled` | boolean | yes | Is the replay sequence enabled? |
| `days` | integer | no | Days the replay is available. |
| `hours` | integer | no | Hours available. |
| `minutes` | integer | no | Minutes available. |
| `expiresMidnight` | boolean | no | Does the replay expire at midnight? |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "set-replay-sequence", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "enabled": true, "days": 3, "hours": 0, "minutes": 0, "expiresMidnight": true }
```

### check-page

Check whether a web page has any header-script issues (e.g. AEvent pixel/embed problems).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `url` | string | yes | The page to test. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "check-page", "tenant_id": "tenant_aevent", "url": "https://go.aevent.com/webinar-confirmation" }
```

---

## 8. Video and Content

### list-videos

List user video files. Returns file details keyed by video fileID.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | no | Video name or partial. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-videos", "tenant_id": "tenant_aevent" }
```

Real return (trimmed):

```json
{
  "cnE3B1gT4vP44os": { "name": "12TipsWebinar.mp4:::", "length": "00:30:07", "mimeType": "video/mp4", "status": "Encoded", "size": "0.08" },
  "cpCMVcDsWA8TqQlv": { "name": "AEvent_Demo_8.8.2025.mp4", "length": "00:35:00", "mimeType": "video/mp4", "status": "Encoded", "size": "0.23" }
}
```

`status: "Encoded"` means ready to attach. The fileID is what you pass to `switch-video.fileID`. The campaign's `webinarVideoLength` (e.g. 7200 = 2h) derives from the attached video and drives like-live scheduling/overlap math.

### switch-video

Switch the active video for a campaign (optionally for a single additional event).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `fileID` | string | yes | Desired video ID. SCHEMA BUG: the description says "use the list-files tool" (the actual tool is `list-videos`). |
| `eventID` | string | no | Change the video only for a specific additional event (from `list-multi-events`); omit for the main event. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "switch-video", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "fileID": "cpCMVcDsWA8TqQlv" }
```

### show-transcript

Show the video transcript for a campaign. Returns timestamped WebVTT.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "show-transcript", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

### list-audio

List user audio files (for ringless voicemail). Returns file details keyed by file ID.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | no | Audio name or partial. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-audio", "tenant_id": "tenant_aevent" }
```

### list-images

List user image files. Returns file details keyed by file ID. (Use a fileID with `add-text-message.fileID` for MMS.)

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | no | Image name or partial. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-images", "tenant_id": "tenant_aevent" }
```

### list-nifty-images

List user NiftyImage files (personalized images for MMS). Returns file details keyed by file NAME (not ID). Pass the name to `add-text-message.niftyImage`.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | no | Image name or partial. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-nifty-images", "tenant_id": "tenant_aevent" }
```

---

## 9. Multi-Events

### list-multi-events

List multi-events for a campaign. Returns additional-event name keyed by `eventID`.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-multi-events", "tenant_id": "tenant_aevent", "wtl": "4WN615HD1rDjDZI" }
```

Real return:

```json
{ "_9t1yi83zs": "Day1", "_kpe753x3h": "Day2", "_tgp1anwdd": "NonAttendeePost" }
```

These keys are `eventID`s (pass to `add-additional-event`, an action's `eventID`, or `switch-video.eventID`).

### add-additional-event

Add an additional event to the campaign (fans out from a source event/audience).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `name` | string | yes | The event name. |
| `audience` / `eventID` / `time` | string | no | Action params (`eventID` here selects the source event to fan out from). |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "add-additional-event", "tenant_id": "tenant_aevent", "wtl": "4WN615HD1rDjDZI",
  "name": "Day3", "audience": "3", "eventID": "_kpe753x3h", "time": "1 day before at 11:00am" }
```

Wiring note: in stored config the additional event is an `automa8-addEvent` action under `general.multiEvents`. `integrationType: "AUTOMA8"` ("AEvent Functions") is the internal engine that creates events; it is NOT a customer-connected integration.

---

## 10. Audiences

### list-audiences

List audiences for a campaign. Returns audience name keyed by its ID.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "list-audiences", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F" }
```

Real return:

```json
{ "3": "Registrants", "a1": "Attendee", "a2": "Non-Attendee" }
```

These three defaults exist on every campaign; the `id` is what you pass to an action's `audience`. Campaigns may add richer custom behavioral segments (UUID-keyed, e.g. `attended-thru-cta`); always resolve them per-campaign.

---

## 11. Forms

Most campaigns return an empty-state string because they use the default registration form, not the form builder. The form-builder JSON only exists once a campaign has been edited through the form builder. For default-form campaigns, the registration copy lives in `show-campaign?section=registration` (`registrationSubject` / `registrationBody` / `customForms`).

### view-form

Read a campaign's form-builder settings (HTML preview by default, or raw JSON).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `raw` | boolean | no | `true` returns the raw settings JSON instead of the HTML preview. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "view-form", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F", "raw": true }
```

Real return on the demo tenant (default-form campaign):

```
No form settings. The user may not be using the form builder for this campaign.
```

This is the literal expected response, NOT an error.

### edit-form

Write a campaign's form-builder settings. Pass either HTML or raw JSON.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `html` | string | one of html/json | The form HTML. |
| `json` | object | one of html/json | The raw form JSON, for when converting HTML does not work. |
| `email` / `tenant_id` | string | one of | Account target. |

Illustrative (not executed):

```json
{ "tool": "edit-form", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "html": "<form>...registration fields...</form>" }
```

---

## 12. Lead Management

### show-lead

Information about a single registrant: which integrations ran, and which webinar they signed up for.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `email` | string | yes | The REGISTRANT'S email address. WARNING: on this tool only, `email` means the registrant, NOT the operating account. This overload diverges from every other tool. |
| `wtl` | string | yes | Campaign ID. |
| `tenant_id` | string | yes | Account target (use this to target the account, since `email` is overloaded). |

```json
{ "tool": "show-lead", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "email": "registrant@example.com" }
```

Known bug: `show-lead` mis-routes `email` as the token key in some cases (the per-registrant integration run-state can fail to read). When it is down, flag it up front and lower confidence rather than theorizing root cause from logs/code alone.

---

## 13. Low-level: change-setting (JSON-Patch editor) ★

`change-setting` is the highest-value low-level tool: a single-operation JSON-Patch editor over a campaign's `general` settings node. Use it for a `general`-node field that has no purpose-built tool.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `wtl` | string | yes | Campaign ID. |
| `nodeID` | string | yes | The settings node. In practice **only the `general` node is writable**. The `registration`/`customForms` node is NOT patchable (every op returns `-32603`). For timeline actions, use the `add-*` tools (raw action edits diverge from the live action cache). |
| `op` | string | yes | JSON-Patch op. **Only `add`, `remove`, `replace` work** (verified). `move`/`copy` are unusable (the tool has no `from` parameter and the server rejects them); `test` is rejected as an invalid op. |
| `path` | string | yes | JSON-Pointer path within the node, e.g. `/timelineName`. |
| `value` | any | for add/replace | The patch value. No `type` constraint in the schema: it accepts any JSON type. |
| `email` / `tenant_id` | string | one of | Account target. |

Safe illustrative ops (not executed):

Rename the campaign:

```json
{ "tool": "change-setting", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "nodeID": "general", "op": "replace", "path": "/timelineName", "value": "Webinar Scaling Secrets (renamed)" }
```

Append to an array field (verified pattern: append with `/-`, replace a whole array with `/arrayField`, remove by index with `/arrayField/N`):

```json
{ "tool": "change-setting", "tenant_id": "tenant_aevent", "wtl": "cAJ3f3AjCeqy01F",
  "nodeID": "general", "op": "add", "path": "/userGroup/-", "value": { } }
```

Critical caveats:

- `change-setting` validates JSON type/structure AND value-domains/enums (the schema is generated from the frontend TypeScript interfaces). A bad value (e.g. an out-of-domain `webinarType`) is REJECTED with `-32603`, not persisted. Still supply known-correct values: `-32603` is a generic, opaque error, so getting the value right beats decoding the failure.
- It mutates the source-of-truth settings. The action CACHE is updated separately by the `add-*` tools, so editing actions via raw patch can diverge from what the `add-*` tools manage. Prefer the purpose-built `add-*` / `set-*` tools for actions; reserve `change-setting` for `general`-node fields with no dedicated tool.
- **Arrays:** append with `path:"/field/-"`, replace a whole array with `path:"/field"`, remove by index with `path:"/field/N"`. Appending to a field that is not already an array fails. A bare-root `replace` on `path:"/"` also fails.
- **Errors:** `-32603` ("Something went wrong while processing the request") is a generic catch-all for ANY failed patch (bad path, missing parent array, unwritable node, bare-root). It does not say which; re-check the `path` and that you are writing the `general` node. Unsupported ops fail distinctly with "The selected op is invalid."

---

## 14. Billing

### billing-details

Billing and plan information for the account. Account-level (no `wtl`).

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "billing-details", "tenant_id": "tenant_aevent" }
```

---

## 15. Docs

### search-documentation

Search the API documentation. Returns routes whose path contains the search string.

| Param | Type | Required | Notes |
|-------|------|----------|-------|
| `search` | string | yes | Only routes with this string in the path are returned. |
| `email` / `tenant_id` | string | one of | Account target. |

```json
{ "tool": "search-documentation", "tenant_id": "tenant_aevent", "search": "webinar" }
```

Note: `search-documentation` is present on the consumer proxy surface used for these tests. The public AEvent MCP server may expose additional discovery tools; if a `search-documentation` (or similar) appears on the public server but not the proxy, treat that as an expected surface difference and flag it.

---

# MERGE FIELDS

AEvent's canonical merge-token syntax is bang-on-both-sides: `{{!token!}}`. The authoritative list comes from `show-merge-fields` (account-level, no `wtl`).

```json
{ "tool": "show-merge-fields", "tenant_id": "tenant_aevent" }
```

## Most-used tokens (verified in real campaign copy)

| Token | Meaning |
|-------|---------|
| `{{!subscriber-firstName!}}` | First name |
| `{{!subscriber-lastName!}}` | Last name |
| `{{!subscriber-email!}}` | Email |
| `{{!subscriber-phone!}}` | Phone number |
| `{{!subscriber-joinURL!}}` | Join link |
| `{{!subscriber-replayURL!}}` | Replay link |
| `{{!replay-replayURL!}}` | Replay link (alternate; both resolve to the replay link) |
| `{{!subscriber-registrationDate!}}` | Registration date |
| `{{!subscriber-uuid!}}` | Registrant UID |

## Webinar time tokens (per timezone)

Account-timezone vs registrant-timezone variants exist for most time fields (registrant variants insert `-reg-`).

| Token | Meaning |
|-------|---------|
| `{{!webinar-esttime!}}` | Start in America/New_York (EST) |
| `{{!webinar-psttime!}}` | Start in America/Los_Angeles (PST) |
| `{{!webinar-csttime!}}` | Start in America/Chicago (CST) |
| `{{!webinar-msttime!}}` | Start in America/Denver (MST) |
| `{{!webinar-usertime!}}` | Start in the account timezone |
| `{{!webinar-gmttime!}}` / `{{!webinar-bsttime!}}` / `{{!webinar-cettime!}}` / `{{!webinar-aesttime!}}` / `{{!webinar-jsttime!}}` / `{{!webinar-isttime!}}` / `{{!webinar-msktime!}}` | Start in GMT / London / Paris / Sydney / Tokyo / Kolkata / Moscow |
| `{{!webinar-dayofweek!}}` | Day of week (account tz) |
| `{{!webinar-day!}}` / `{{!webinar-month!}}` / `{{!webinar-year!}}` | Date parts (account tz) |
| `{{!webinar-reg-dayofweek!}}` / `{{!webinar-reg-day!}}` / `{{!webinar-reg-month!}}` / `{{!webinar-reg-year!}}` | Date parts in the registrant's timezone |
| `{{!webinar-webinarTitle!}}` / `{{!webinar-webinarBody!}}` | Registration title / description (topic / agenda if Zoom) |
| `{{!webinar-startsIn!}}` | Seconds until start |

Replay-expiration tokens mirror the webinar set under the `{{!replay-...!}}` prefix (e.g. `{{!replay-esttime!}}`, `{{!replay-day!}}`, `{{!replay-expiresIn!}}`, `{{!replay-timeStamp!}}`).

## Calendar tokens (the exception: NO trailing bang)

```
{{!add_to_google_calendar}}      Link to add to Google Calendar
{{!add_to_apple_calendar}}       Link to add to other calendar types
```

These two are the ONLY tokens with no trailing bang. They were confirmed appearing verbatim in real campaign copy.

> ## Common pitfalls callout: plain single-brace tokens do not work
>
> These plain single-brace tokens are ALL WRONG and will render literally instead of personalizing:
>
> | WRONG | CORRECT |
> |-------|---------|
> | `{{first_name}}` | `{{!subscriber-firstName!}}` |
> | `{{webinar_link}}` | `{{!subscriber-joinURL!}}` |
> | `{{replay_link}}` | `{{!subscriber-replayURL!}}` (or `{{!replay-replayURL!}}`) |
> | `{{webinar_date}}` | `{{!webinar-day!}}` / `{{!webinar-month!}}` / `{{!webinar-year!}}` or a `{{!webinar-...time!}}` token |
>
> Rule: bang on both sides for everything EXCEPT the two `add_to_*_calendar` tokens. Always confirm with `show-merge-fields` before drafting AEvent-native copy.

---

# TOOL SUMMARY TABLE

| Tool | Category | Read/Write | Key params (server-required) |
|------|----------|-----------|------------------------------|
| `list-campaigns` | Campaign Mgmt | read | (search) |
| `create-campaign` | Campaign Mgmt | write | name, integrationID |
| `show-campaign` | Campaign Mgmt | read | wtl, (section) |
| `schedule-webinar` | Webinar Sched | write | wtl, integrationID, timestamp |
| `list-upcoming-webinars` | Webinar Sched | read | (wtl, page) |
| `list-past-webinars` | Webinar Sched | read | (wtl, page) |
| `list-recurring` | Webinar Sched | read | (wtl) |
| `show-event-info` | Webinar Sched | read | id (instance id) |
| `list-integrations` | Integrations | read | (search) |
| `list-campaign-integrations` | Integrations | read | wtl |
| `test-integration` | Integrations | read | integrationID |
| `add-field` | Registration | write | wtl, name |
| `add-u-t-m` | Registration | write | wtl |
| `add-email` | Messaging | write | wtl, subject, message |
| `add-text-message` | Messaging | write | wtl, message |
| `add-autochat` | Messaging | write | wtl, message |
| `add-voice-mail` | Messaging | write | wtl, fileID |
| `add-join-message` | Messaging | write | wtl, message, name |
| `clear-join-messages` | Messaging | write | wtl |
| `add-tag` | Tags & Lists | write | wtl, tag |
| `remove-tag` | Tags & Lists | write | wtl, tag |
| `add-to-list` | Tags & Lists | write | wtl, target |
| `set-confirmation-page` | Pages | write | wtl, url |
| `set-expired-page` | Pages | write | wtl, url |
| `set-replay-page` | Pages | write | wtl, url |
| `set-replay-sequence` | Pages | write | wtl, enabled |
| `check-page` | Pages | read | url |
| `list-videos` | Video & Content | read | (search) |
| `switch-video` | Video & Content | write | wtl, fileID |
| `show-transcript` | Video & Content | read | wtl |
| `list-audio` | Video & Content | read | (search) |
| `list-images` | Video & Content | read | (search) |
| `list-nifty-images` | Video & Content | read | (search) |
| `list-multi-events` | Multi-Events | read | wtl |
| `add-additional-event` | Multi-Events | write | wtl, name |
| `list-audiences` | Audiences | read | wtl |
| `view-form` | Forms | read | wtl, (raw) |
| `edit-form` | Forms | write | wtl, html OR json |
| `show-lead` | Lead Mgmt | read | email (REGISTRANT), wtl |
| `change-setting` | Low-level | write | wtl, nodeID, op, path, (value) |
| `billing-details` | Billing | read | (account) |
| `show-merge-fields` | Merge Fields | read | (account) |
| `search-documentation` | Docs | read | search |

Total: 43 consumer tools.

---

# APPENDIX: in-schema quirks and gotchas

- **No `required` arrays.** Every parameter is schema-optional; requirements are server-enforced. This doc states the functional requirements.
- **`set-replay-page.url` description bug.** Says "expired page"; functionally sets the replay page.
- **`switch-video.fileID` description bug.** References a nonexistent "list-files" tool; use `list-videos`.
- **`show-lead.email` overload.** Means the registrant, not the operating account (unlike all other tools). Target the account via `tenant_id`.
- **`change-setting` validates types AND enums/value-domains.** A bad value (wrong `webinarType`, etc.) is rejected with `-32603`, not silently saved. Still supply correct values (the error is generic).
- **Description-only enums.** `create-campaign.options` and `show-campaign.section` are not schema-enforced; supply correct values.
- **Empty arrays are normal.** `list-recurring` / `list-upcoming-webinars` / `list-past-webinars` return `[]` when nothing is scheduled; this is not an error.
- **`connected: true` and `test-integration` are shallow.** Neither validates the OAuth token or plan depth.
- **Multiple records per integration type.** Resolve the exact `integrationID` per campaign via `list-campaign-integrations`, never by type alone.

---

*Source of truth: live tool schemas (`01-live-tool-catalog.md`) + real read-only `tenant_aevent` captures (`04-worked-examples.md`), both 2026-06-15. Write tools shown as call shapes only; none executed against `tenant_aevent`.*
