Quickstart

This guide gets a chat running in a Next.js (App Router) app. At the end two users can message each other in real time. The Integration guide then covers what production needs.

You need a Next.js app with a sign-in of its own. Below, yourAuth(req) stands for your existing session check; it returns the signed-in user's id in your system.

1. Create an API key

Sign up for the dashboard, open API keys and create a key. New keys start with the users:manage scope selected; keep it, because minting user tokens needs it. The full key is shown once, so copy it now. See API keys.

Put it in your backend's environment, never in browser code:

POOLSE_API_KEY=pk_live_…

2. Install the packages

npm install @poolse/sdk @poolse/react @poolse/react-ui

The current release is 3.1. Keep all @poolse/* packages on the same major version.

3. Mint user tokens on your backend

Create app/api/chat-token/route.ts:

import { NextResponse } from 'next/server';

const API = 'https://api.poolse.dev';
const KEY = process.env.POOLSE_API_KEY!;

export async function POST(req: Request) {
  const session = await yourAuth(req);
  if (!session) return new NextResponse('unauthorized', { status: 401 });

  // Create the poolse user for this person, or get the existing one.
  const userRes = await fetch(`${API}/v1/users`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ external_id: session.userId }),
  });
  if (!userRes.ok) return new NextResponse('poolse user upsert failed', { status: 502 });
  const user = await userRes.json(); // { id, external_id, … }

  // Mint a one-hour token for that user.
  const tokenRes = await fetch(`${API}/v1/users/${user.id}/tokens`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${KEY}` },
  });
  if (!tokenRes.ok) return new NextResponse('poolse token mint failed', { status: 502 });
  const { token } = await tokenRes.json(); // { token, token_type, expires_in, expires_at }

  return NextResponse.json({ token });
}
  • POST /v1/users is keyed on external_id, your own user id. The same external_id always gives the same poolse user, so calling it on every request is fine. Fields you leave out keep their stored values. See Users.
  • POST /v1/users/:user_id/tokens returns a new JWT that is valid for one hour. The SDK caches it and calls this route again shortly before it expires. Don't cache tokens on your server.

4. Render the chat

Create app/chat/page.tsx:

'use client';

import '@poolse/react-ui/styles.css';
import { PoolseProvider, type PoolseConfig } from '@poolse/react';
import { ConversationView } from '@poolse/react-ui';

const config: PoolseConfig = {
  getToken: async () => {
    const res = await fetch('/api/chat-token', { method: 'POST', credentials: 'include' });
    if (!res.ok) throw new Error(`chat-token failed: ${res.status}`);
    const { token } = await res.json();
    return token;
  },
};

export default function ChatPage() {
  return (
    <div style={{ height: '100vh', maxWidth: 720, margin: '0 auto' }}>
      <PoolseProvider config={config}>
        <ConversationView conversationId="PASTE-A-CONVERSATION-ID" />
      </PoolseProvider>
    </div>
  );
}

apiUrl defaults to https://api.poolse.dev, so you don't need to set it.

5. Create a conversation

ConversationView needs a conversation id. For a first test, create one from your terminal with the API key. This creates a user for you (alice), mints a token for her, and has her create a group with a second user (bob):

API=https://api.poolse.dev

ALICE=$(curl -s -X POST $API/v1/users \
  -H "Authorization: Bearer $POOLSE_API_KEY" -H "Content-Type: application/json" \
  -d '{"external_id":"alice"}' | jq -r .id)

JWT=$(curl -s -X POST $API/v1/users/$ALICE/tokens \
  -H "Authorization: Bearer $POOLSE_API_KEY" | jq -r .token)

curl -s -X POST $API/v1/conversations \
  -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"type":"group","name":"Hello world","member_external_ids":["bob"]}' | jq -r .id

Use your app's real user ids in place of alice and bob (the ids yourAuth returns), so that signing in to your app as them gets their tokens. bob is created as a poolse user automatically when he is added. Paste the printed id into conversationId.

6. Try it

Open /chat signed in as one member in one browser, and as the other member in a second browser (or a private window). Messages, typing and read ticks appear on the other side as they happen.

You can also post from the terminal and watch it appear:

curl -X POST $API/v1/conversations/$CONV_ID/messages \
  -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"body":"hello from curl"}'

Only members can read a conversation. A signed-in user who isn't a member sees an error in place of the messages.

What happened

RequestAuthWhen
POST /v1/usersAPI keyYour route, on each token request
POST /v1/users/:id/tokensAPI key (users:manage)Your route, on each token request
GET /v1/meJWTWhen ConversationView mounts
GET /v1/conversations/:id/messagesJWTLoading the newest messages
POST /v1/conversations/:id/messagesJWTSending
WebSocket /socket, channel conversation:<id>JWTLive messages, typing, read receipts

Next steps

Quickstart · poolse docs