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

# Types

> Public TypeScript types exported from `@vibefollow/sdk`.

The SDK exports a curated set of public types. Internals (HTTP client, retry config, etc.) are intentionally not exported — they're refactoring surface area, not contract.

## `VibeFollowOptions`

The constructor options object.

```ts theme={null}
interface VibeFollowOptions {
  /** API key &mdash; sk_live_… or sk_test_… */
  apiKey: string;
  /** Base URL. Defaults to 'https://api.vibefollow.com'. */
  baseUrl?: string;
  /** Per-request timeout in ms. Defaults to 10000 (10s). */
  timeoutMs?: number;
  /** Max retries on 429/5xx/network. Defaults to 2. */
  maxRetries?: number;
  /** Injectable fetch (testing, edge runtimes). Defaults to globalThis.fetch. */
  fetchImpl?: typeof fetch;
}
```

<Info>
  See [`VibeFollow` class](/sdk/class-vibefollow) for the per-field details.
</Info>

## `IdentifyTraits`

The traits bag passed to `vf.users.identify()`. Known fields are typed; everything else is permitted under the index signature.

```ts theme={null}
interface IdentifyTraits {
  email?: string;
  name?: string;
  plan?: string;
  signupDate?: string;
  company?: string;
  role?: string;
  [k: string]: unknown;
}
```

## `EventProperties`

The properties bag passed to `vf.events.track()` and lifecycle helpers.

```ts theme={null}
type EventProperties = Record<string, unknown>;
```

## Bulk types

Shared by [`users.identifyBulk()`](/sdk/resources/users#identifybulk-records) and [`events.bulk()`](/sdk/resources/events#bulk-records).

```ts theme={null}
interface BulkUserRecord {
  external_user_id: string;
  email?: string;
  timezone?: string;
  traits?: IdentifyTraits;
}

interface BulkEventRecord {
  external_user_id: string;
  name: string;
  timestamp?: string;
  properties?: EventProperties;
}

interface BulkIngestError {
  index: number;     // position in the input array
  code: string;      // e.g. "validation"
  message: string;
  field?: string;    // e.g. "email"
}

interface BulkIngestResponse {
  data: {
    accepted: number;
    rejected: number;
    errors: BulkIngestError[];
  };
  meta: { received: number };
}

/** Hard server-side cap; exported so you can size loops against it. */
const BULK_INGEST_MAX_RECORDS = 1000;
```

## `chunk(input, size)`

Generator that slices an array into ≤`size` slices. Use it to backfill more than `BULK_INGEST_MAX_RECORDS` records in one loop without materialising the source twice in memory.

```ts theme={null}
import { VibeFollow, chunk } from '@vibefollow/sdk';

const vf = new VibeFollow({ apiKey: process.env.VIBEFOLLOW_API_KEY! });

for (const slice of chunk(historicalEvents, 1000)) {
  await vf.events.bulk(slice);
}
```

<ParamField path="input" type="readonly T[]" required>
  Source array. Empty arrays yield no chunks (the loop body never runs).
</ParamField>

<ParamField path="size" type="number" required>
  Positive integer. Throws `RangeError` for `0`, negatives, or non-integers.
</ParamField>

**Returns:** `Generator<readonly T[]>`. Iterable; do not call `.next()` on it directly.

## `STANDARD_EVENT_NAMES` and `StandardEventName`

The canonical 10 lifecycle event names. The same list used by the typed helpers on `vf.users`.

```ts theme={null}
const STANDARD_EVENT_NAMES = [
  'user_signed_up',
  'trial_started',
  'feature_used',
  'onboarding_step',
  'subscription_changed',
  'subscription_cancelled',
  'payment_failed',
  'trial_expiring',
  'user_invited',
  'usage_threshold_reached',
] as const;

type StandardEventName = (typeof STANDARD_EVENT_NAMES)[number];
```

Useful for runtime validation:

```ts theme={null}
import { STANDARD_EVENT_NAMES } from '@vibefollow/sdk';
import type { StandardEventName } from '@vibefollow/sdk';

function isStandard(name: string): name is StandardEventName {
  return (STANDARD_EVENT_NAMES as readonly string[]).includes(name);
}
```

## `WebhookEvent` union

The return type of `vf.webhooks.constructEvent()`. A discriminated union over `type`.

```ts theme={null}
type WebhookEvent =
  | EmailOpenedEvent
  | EmailClickedEvent
  | EmailBouncedEvent
  | EmailRepliedEvent
  | EmailUnsubscribedEvent;
```

See the per-type payload spec in [Webhook event types](/webhooks/event-types). Every member shares the envelope:

```ts theme={null}
{
  type: 'email.opened' | 'email.clicked' | …;
  id: string;       // unique per delivery
  created: number;  // Unix seconds
  data: { … };      // type-specific
}
```

### Per-event types

<AccordionGroup>
  <Accordion title="EmailOpenedEvent" icon="envelope-open">
    ```ts theme={null}
    interface EmailOpenedEvent {
      type: 'email.opened';
      id: string;
      created: number;
      data: {
        draftId: string;
        projectId: string;
        externalUserId: string;
        messageId: string;
        openedAt: string;
      };
    }
    ```
  </Accordion>

  <Accordion title="EmailClickedEvent" icon="arrow-pointer">
    ```ts theme={null}
    interface EmailClickedEvent {
      type: 'email.clicked';
      id: string;
      created: number;
      data: {
        draftId: string;
        projectId: string;
        externalUserId: string;
        messageId: string;
        url: string;
        clickedAt: string;
      };
    }
    ```
  </Accordion>

  <Accordion title="EmailBouncedEvent" icon="triangle-exclamation">
    ```ts theme={null}
    interface EmailBouncedEvent {
      type: 'email.bounced';
      id: string;
      created: number;
      data: {
        draftId: string;
        projectId: string;
        externalUserId: string;
        messageId: string;
        bounceType: 'hard' | 'soft' | 'transient' | 'complaint' | 'unknown';
        reason?: string;
        bouncedAt: string;
      };
    }
    ```
  </Accordion>

  <Accordion title="EmailRepliedEvent" icon="reply">
    ```ts theme={null}
    interface EmailRepliedEvent {
      type: 'email.replied';
      id: string;
      created: number;
      data: {
        draftId: string;
        projectId: string;
        externalUserId: string;
        messageId: string;
        replyBody: string;
        tone: 'positive' | 'neutral' | 'negative' | 'unsubscribe_request';
        receivedAt: string;
      };
    }
    ```
  </Accordion>

  <Accordion title="EmailUnsubscribedEvent" icon="ban">
    ```ts theme={null}
    interface EmailUnsubscribedEvent {
      type: 'email.unsubscribed';
      id: string;
      created: number;
      data: {
        projectId: string;
        externalUserId: string;
        email: string;
        source: 'one_click' | 'reply_request' | 'manual';
        unsubscribedAt: string;
      };
    }
    ```
  </Accordion>
</AccordionGroup>

## `SDK_VERSION`

The current SDK version as a string. Flows into the `User-Agent` header on every request.

```ts theme={null}
import { SDK_VERSION } from '@vibefollow/sdk';
console.log(SDK_VERSION); // e.g. "1.0.0"
```
