> This page is for For Developers.

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

# Quickstart

> Give your users a real-time messaging chat on web and native iOS. Support many types of conversations. Whop handles the messages, realtime updates, media uploads and UI.

1

## Create an API key

Create an API key in the [Whop Developer Dashboard](https://whop.com/dashboard/developer) and save it on your server as `WHOP_API_KEY`.

This key will allow you to perform actions within the context of your company. Keep it on the server. Never put it in browser, mobile, or client-side code.

2

## Install packages

Install the SDK in your backend:

#### Next.js

```bash
pnpm add @whop/sdk
```

#### Express

```bash
pnpm add @whop/sdk
```

#### cURL

You can also check [the API reference](/developer/api/quickstart) if you prefer to make the requests yourself.

Install the elements packages in your frontend:

#### React

```bash
pnpm add @whop/embedded-components-react-js @whop/embedded-components-vanilla-js
```

#### HTML

```html
<script src="https://apollo.elements.whop.com/release/elements.js"></script>
```

#### iOS

Add this Swift package in Xcode:

```text
https://github.com/whopio/whopsdk-elements-swift
```

Chat supports photos, videos, and voice messages, so add these permissions to your app's `Info.plist`:

**`Info.plist`**

```xml Info.plist
<key>NSCameraUsageDescription</key>
<string>Allow camera access to take photos and videos in chat</string>
<key>NSMicrophoneUsageDescription</key>
<string>Allow microphone access to record voice messages in chat</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Allow photo library access to share photos and videos in chat</string>
```

3

## Get a user ID for your users

Enroll your own users as connected accounts before minting chat tokens. This creates a Whop account you can map back to your platform user.

#### Next.js

```typescript
import Whop from "@whop/sdk";

const client = new Whop({ apiKey: process.env.WHOP_API_KEY });

const company = await client.companies.create({
  email: "user@example.com",
  parent_company_id: "biz_XXXXXXXXXXXXX", // your platform's company ID
  title: "Jane Doe",
  metadata: {
    internal_user_id: "user_12345", // your platform's user ID
  },
});
```

#### Express

```typescript
import Whop from "@whop/sdk";

const client = new Whop({ apiKey: process.env.WHOP_API_KEY });

const company = await client.companies.create({
  email: "user@example.com",
  parent_company_id: "biz_XXXXXXXXXXXXX", // your platform's company ID
  title: "Jane Doe",
  metadata: {
    internal_user_id: "user_12345", // your platform's user ID
  },
});
```

#### cURL

```bash
curl -X POST https://api.whop.com/api/v1/companies \
  -H "Authorization: Bearer $WHOP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "parent_company_id": "biz_XXXXXXXXXXXXX",
    "title": "Jane Doe",
    "metadata": {
      "internal_user_id": "user_12345"
    }
  }'
```

Save the resulting Whop user ID (`owner_user.id` in the response) on your side and pass it as `user_id` when you create chat access tokens.

See [company-specific profiles](/developer/guides/chat/sync-users#2-set-a-company-specific-name-and-profile-picture) for more details on how to update users avatars and display names.

4

## Create a token endpoint on your server

Add an endpoint that calls `POST https://api.whop.com/api/v1/access_tokens` with your API key and returns the resulting token to the client.

#### Next.js

**`app/api/chat/token/route.ts`**

```typescript app/api/chat/token/route.ts
import { NextResponse } from "next/server";
import Whop from "@whop/sdk";

const client = new Whop({ apiKey: process.env.WHOP_API_KEY });

export async function POST() {
  // Derive these from your own auth / session in production.
  const user_id = "user_XXXXXXXXXXXX";
  const company_id = "biz_XXXXXXXXXXXXX";

  const { token } = await client.accessTokens.create({
    company_id,
    user_id,
    scoped_actions: [
      "chat:message:create",
      "chat:read",
      "dms:read",
      "dms:message:manage",
      "dms:channel:manage",
      "support_chat:read",
      "support_chat:message:create",
    ],
  });

  return NextResponse.json({ token });
}
```

#### Express

**`server.ts`**

```typescript server.ts
import express from "express";
import Whop from "@whop/sdk";

const app = express();
app.use(express.json());

const client = new Whop({ apiKey: process.env.WHOP_API_KEY });

app.post("/api/chat/token", async (_req, res) => {
  // Derive these from your own auth / session in production.
  const user_id = "user_XXXXXXXXXXXX";
  const company_id = "biz_XXXXXXXXXXXXX";

  const { token } = await client.accessTokens.create({
    company_id,
    user_id,
    scoped_actions: [
      "chat:message:create",
      "chat:read",
      "dms:read",
      "dms:message:manage",
      "dms:channel:manage",
      "support_chat:read",
      "support_chat:message:create",
    ],
  });

  res.json({ token });
});

app.listen(3000);
```

#### cURL

```bash
curl -X POST https://api.whop.com/api/v1/access_tokens \
  -H "Authorization: Bearer $WHOP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "biz_XXXXXXXXXXXXX",
    "user_id": "user_XXXXXXXXXXXX",
    "scoped_actions": [
      "chat:message:create",
      "chat:read",
      "dms:read",
      "dms:message:manage",
      "dms:channel:manage",
      "support_chat:read",
      "support_chat:message:create"
    ]
  }'
```

5

## Create or fetch a channel, DM, or support chat

All chat types use real-time messaging and can render in the Chat element. Pick the type based on your needs:

#### [Channels](/developer/guides/chat/channels)

A shared chat for public or large group conversations. Rooms with moderation, read-only options, and no fixed member cap.

#### [Direct messages](/developer/guides/chat/direct-messages)

A private conversation between users. They show in the DMs list and can include up to 50 members.

#### [Support chat](/developer/guides/chat/support-chats)

A one-on-one support conversation between a user and your company. Customers see them like DMs; admins manage them through a support inbox instead of the DMs list.

Before rendering chat, get the channel ID you want to open.

* [**Channels**](/developer/guides/chat/channels) IDs start with `chat_feed_`.
* [**DMs**](/developer/guides/chat/direct-messages) and [**support chats**](/developer/guides/chat/support-chats) IDs start with `feed_`.

6

## Render chat in your app

This will use the token endpoint you created to fetch a token and render the chat element. The SDK is responsible of managing the token and refreshing it when necessary.

#### React

```tsx
"use client";

import {
  ChatElement,
  ChatSession,
  Elements,
} from "@whop/embedded-components-react-js";
import { loadWhopElements } from "@whop/embedded-components-vanilla-js";

const elements = loadWhopElements();

async function getToken() {
  const res = await fetch("https://your-server.com/api/chat/token", { method: "POST" });
  const data = await res.json();
  return data.token;
}

export function Chat() {
  return (
    <Elements elements={elements}>
      <ChatSession token={getToken}>
        <ChatElement
          options={{ channelId: "chat_feed_XXXXXXXXXXXXXX" }}
          style={{ height: "100dvh", width: "100%" }}
        />
      </ChatSession>
    </Elements>
  );
}
```

#### HTML

```html
<div id="chat" style="height: 100vh"></div>

<script>
  const elements = new WhopElements();

  async function getToken() {
    const res = await fetch("https://your-server.com/api/chat/token", { method: "POST" });
    const data = await res.json();
    return data.token;
  }

  const session = elements.createChatSession({ token: getToken });
  const chat = session.createElement("chat-element", {
    channelId: "chat_feed_XXXXXXXXXXXXXX",
  });

  chat.mount("#chat");
</script>
```

#### iOS

```swift
import SwiftUI
import WhopElements

struct ContentView: View {
  var body: some View {
    WhopChatView(
      channelId: "chat_feed_XXXXXXXXXXXXXX",
      style: .imessage
    )
    // This should be done as soon as you know your user is authenticated so its
    // prepared and ready to use without delays.
    .task {
      await WhopSDK.configure(tokenProvider: WhopAPITokenProvider())
    }
  }
}

class WhopAPITokenProvider: WhopTokenProvider {
  func getToken() async -> WhopTokenResponse {
    let url = URL(string: "https://your-server.com/api/chat/token")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"

    do {
      let (data, _) = try await URLSession.shared.data(for: request)
      let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
      return WhopTokenResponse(accessToken: json["token"] as? String ?? "")
    } catch {
      return WhopTokenResponse(accessToken: "")
    }
  }
}
```

## Next steps

#### [Authentication](/developer/guides/chat/authentication)

Choose between company-scoped tokens and OAuth for embedded chat.

#### [Sync your users](/developer/guides/chat/sync-users)

Create or map Whop users before minting company-scoped chat tokens.

#### [Chat element](/developer/guides/chat/chat-element)

Learn the props, events, styles, and deeplinking options for the chat UI.

#### [DMs list element](/developer/guides/chat/dms-list-element)

Show a list of a user's direct message conversations.