Livqeno Docs

Chat Quickstart

Install, authenticate, connect, and send your first message — on every supported SDK.

What you'll build: a conversation two users can send messages into, with one seeing the other's messages arrive live.

Prerequisites: a Livqeno project and a project API key (see API Keys) — conversations are created and chat tokens are minted with it, server-side, and never in a browser or app.

1. Install

npm install @ravenkash/chat

2. Create a conversation (once, from your backend)

import { Raven } from '@ravenkash/server';
const raven = new Raven({
  apiKey: process.env.RAVEN_API_KEY,
  baseUrl: process.env.RAVEN_API_URL, // https://api.ravenstack.online
});
 
const conversation = await raven.chat.createConversation({
  name: 'support-room-42',
  members: [{ userId: 'alice', role: 'ADMIN' }, { userId: 'bob' }],
});

3. Authenticate — mint a token per user

const token = await raven.chat.createToken({
  userId: 'alice',
  conversations: [conversation.publicId],
});

The mint response is a grant: it carries token, chatUrl and apiUrl together. Return it to the browser as-is from your own endpoint:

// app/api/chat/token/route.ts — your backend, holding RAVEN_API_KEY
export async function POST() {
  const grant = await raven.chat.createToken({ userId: session.userId });
  return Response.json(grant);          // token + chatUrl + apiUrl
}

Then the browser needs no Livqeno configuration of its own — no RAVEN_API_KEY, no gateway hostname, no API base URL:

const grant = await fetch('/api/chat/token', { method: 'POST' }).then((r) => r.json());
const chat = createChatClient(grant);   // forwarded whole, unmodified
await chat.connect();

That is the whole reason the addresses ride inside the grant: the same frontend code works against your laptop, hosted Livqeno, or your own cluster, and nothing in it knows which.

4. Connect from the client

import { createChatClient } from '@ravenkash/chat';
 
const chat = createChatClient({ token: token.token, apiUrl: token.apiUrl });
await chat.connect({ room: conversation.publicId });

5. Send a message

await chat.sendMessage({ text: 'Hello everyone!' });

6. Receive messages

chat.on('message', (message) => console.log(message.senderId, message.text));

You receive your own messages back too — render the same server-ordered row everyone else does, rather than an optimistic local copy.

7. Disconnect

await chat.disconnect();

What Livqeno handles vs. what you handle

Livqeno handles: the WebSocket connection, reconnection with backoff and catch-up, message ordering and durability, and idempotent retries.

You handle: minting tokens from your own authenticated backend session, and the UI around messages/typing/presence.

Common errors

ErrorWhyFix
chat:send scope missingToken was minted without it, or the role doesn't grant it.Check the member's role — see Members.
Message never arrives for other usersRejected server-side; a rejection never round-trips as a message event.Listen for error too, not just message — see Troubleshooting.
senderId in the request is ignoredA browser chat token can't set it.Expected — see Messages.
ORIGIN_NOT_ALLOWED, socket closed with code 4403The page's origin is not on this project's allow-list. The token was fine; the page holding it was not expected.Add the origin under Project Settings → Security → Allowed Origins. Retrying will not help. Loopback origins are allowed by default. See Browser security.
403 on a Chat REST call, code RAVEN_PERMISSION_DENIEDSame cause, on the REST surface rather than the socket.Same fix. Note this is a real 403 you can read, not an opaque browser CORS failure — that is deliberate.

Production notes

  • Never call raven.chat.createConversation()/createToken() (or any @ravenkash/server/raven-sdk method) from a browser or app.
  • Derive userId from your own authenticated session — a chat token minted for the wrong user lets them send as someone else.
  • clientMessageId is attached automatically if you don't supply one, so retries from the SDK itself are already safe. Supply your own only when you control the retry (a job queue, an offline outbox).