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

# Event schema

> TrackEvent shape, the built-in event names, and the typed properties for each.

The full type-level reference for events sent via `wani.track()`. Usage recipes are in [Events](/sdk/tracking/events).

## `TrackEvent`

```ts theme={null}
import type { TrackInput } from "@waniwani/sdk";

type TrackEvent = {
  event: EventType;                     // required, one of the built-in names
  properties?: Record<string, unknown>; // typed per event name
  meta?: Record<string, unknown>;       // MCP request _meta
  metadata?: Record<string, unknown>;   // free-form metadata on the envelope
  sessionId?: string;                   // explicit override, usually omit
  traceId?: string;
  requestId?: string;
  correlationId?: string;
  externalUserId?: string;
  eventId?: string;                     // supply your own id (idempotency)
  timestamp?: string | Date;            // defaults to now
  source?: string;                      // defaults to "@waniwani/sdk"
};
```

<ResponseField name="event" type="EventType" required>
  The event name. Must be one of the built-in `EventType` values listed below.
</ResponseField>

<ResponseField name="properties" type="Record<string, unknown>">
  Event payload. For built-in events, the type is narrowed (for example, `quote.succeeded` expects `{ amount?: number; currency?: string }`).
</ResponseField>

<ResponseField name="meta" type="Record<string, unknown>">
  MCP request metadata, typically `extra._meta` inside a tool handler. This is where the SDK reads the session id from. See [Sessions](/sdk/tracking/sessions).
</ResponseField>

<ResponseField name="sessionId" type="string">
  Explicit session id override. Prefer passing `meta` instead.
</ResponseField>

<ResponseField name="externalUserId" type="string">
  External user identifier. Equivalent to calling `identify()` inline. See [Identify](/sdk/tracking/identify).
</ResponseField>

<ResponseField name="eventId" type="string">
  Client-generated id. If you omit it, the SDK generates `evt_<uuid>`. Supplying your own enables idempotent resends.
</ResponseField>

`track()` returns `{ eventId }` as soon as the envelope is enqueued, before the network request completes.

## `EventType` union

A closed union exported from `@waniwani/sdk`. Only these names are accepted by `track()`.

| Event name           | Typed properties              | Notes                                                                                                              |
| -------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `session.started`    | none                          | Emitted by the Waniwani backend when it sees a new session id. Do not send it yourself.                            |
| `page.viewed`        | `PageViewedProperties`        | Emitted automatically by the chat widget on init, attributed to an anonymous `visitorId`. Do not send it yourself. |
| `tool.called`        | `ToolCalledProperties`        | Emitted automatically by `withWaniwani(server)`. Do not send it yourself.                                          |
| `quote.requested`    | none                          | Top of a pricing funnel.                                                                                           |
| `quote.succeeded`    | `QuoteSucceededProperties`    | A quote was produced.                                                                                              |
| `quote.failed`       | none                          | A quote could not be produced.                                                                                     |
| `link.clicked`       | `LinkClickedProperties`       | An outbound link was followed.                                                                                     |
| `purchase.completed` | `PurchaseCompletedProperties` | A purchase finished.                                                                                               |
| `user.identified`    | none                          | Prefer `client.identify()` over sending this directly.                                                             |
| `price_shown`        | `PriceShownProperties`        | Revenue funnel step: one price was shown. Prefer `track.priceShown()`.                                             |
| `prices_compared`    | `PricesComparedProperties`    | Revenue funnel step: two or more options shown side by side. Prefer `track.pricesCompared()`.                      |
| `option_selected`    | `OptionSelectedProperties`    | Revenue funnel step: the user picked an option. Prefer `track.optionSelected()`.                                   |
| `lead_qualified`     | `LeadQualifiedProperties`     | The person met your qualification bar. Prefer `track.leadQualified()`.                                             |
| `converted`          | `ConvertedProperties`         | The user became paying, possibly later and off-platform. Prefer `track.converted()`.                               |

The five revenue events also have flat typed helpers on `track` (for example `wani.track.leadQualified({ ... })`). Each helper accepts its event's properties plus the shared tracking context (`sessionId`, `externalUserId`, `meta`, and so on). Placement guidance for each lives in [Instrumentation](/sdk/tracking/instrumentation).

## Typed property interfaces

```ts theme={null}
import type {
  ToolCalledProperties,
  QuoteSucceededProperties,
  LinkClickedProperties,
  PurchaseCompletedProperties,
  PriceShownProperties,
  PricesComparedProperties,
  OptionSelectedProperties,
  LeadQualifiedProperties,
  ConvertedProperties,
} from "@waniwani/sdk";

interface ToolCalledProperties {
  name?: string;
  type?: "pricing" | "product_info" | "availability" | "support" | "other";
  /** Retrieval traces for kb.search() calls made inside this tool handler. */
  kbSearch?: KbSearchTrace[];
}

interface QuoteSucceededProperties {
  amount?: number;
  currency?: string;
}

interface LinkClickedProperties {
  url?: string;
}

interface PurchaseCompletedProperties {
  amount?: number;
  currency?: string;
}

interface PriceShownProperties {
  amount: number;
  currency: string;
  itemId?: string;
  label?: string;
}

interface PricesComparedProperties {
  options: Array<{ id: string; amount: number; currency: string }>;
}

interface OptionSelectedProperties {
  id: string;
  amount: number;
  currency: string;
}

interface LeadQualifiedProperties {
  /** Your own lead id (e.g. the record id your CRM returns). The strongest dedup key. */
  externalId?: string;
  /** The lead's email, if known. */
  email?: string;
  /** The lead's name, if known. */
  name?: string;
  /** Acquisition source of the lead (e.g. "newsletter"). */
  source?: string;
}

interface ConvertedProperties {
  amount: number;
  currency: string;
  /** When the conversion actually happened, for backdated off-platform sales. */
  occurredAt?: string;
}
```

<Note>
  The SDK also defines `widget_render`, `widget_click`, `widget_link_click`, `widget_error`, `widget_scroll`, `widget_form_field`, and `widget_form_submit` event types. These are emitted automatically by the widget runtime (`useWaniwani()` in a browser widget) and are not intended to be sent from server code.
</Note>
