# Build your first call Create a room on your server, then join it from React. ## Requirements - A running RelayRTC API, signaling service and media service. - A secret API key with `rooms:create` and `tokens:create`. - Node.js 22 or newer and a React application. - Camera and microphone permission. Use HTTPS in deployment; localhost works for development. [Install the SDKs](/installation) before following this page. ## Configure your server Keep these values on your backend. These URLs are for a local RelayRTC deployment. ```bash RELAYRTC_API_URL=http://localhost:8082/v1 RELAYRTC_SIGNALING_URL=ws://localhost:8081/v1/connect RELAYRTC_SECRET_KEY=your-secret-api-key ``` > **Keep secret keys on your server** > Never place a secret key in frontend code, a public environment variable or a participant token response. Authenticate your own users before issuing tokens. ## Create a room ```ts import { RelayServer } from '@relayrtc/node' const relay = new RelayServer({ apiUrl: process.env.RELAYRTC_API_URL!, apiKey: process.env.RELAYRTC_SECRET_KEY!, }) const room = await relay.rooms.create({ name: 'Team call', maxParticipants: 10, }) ``` Save `room.id` in your application. Everyone in the same call needs a token for that room. ## Issue participant tokens Create a token for each person, not one token shared by the whole room. ```ts const issued = await relay.tokens.create(room.id, { participantName: 'Alice', ttlSeconds: 3600, permissions: [ 'room:join', 'audio:publish', 'video:publish', 'screen:publish', 'messages:send', 'metadata:update', ], }) const joinResponse = { token: issued.token, expiresAt: issued.expiresAt, signalingUrl: process.env.RELAYRTC_SIGNALING_URL, } ``` Return `joinResponse` from your authenticated backend endpoint. Do not return the secret key. ## Connect from React In Next.js, put this component in a client module. ```tsx 'use client' import { RelayProvider, RelayRoom, useLocalMedia, useLocalParticipant, useRoom } from '@relayrtc/react' function Controls() { const local = useLocalParticipant() const { camera, microphone } = useLocalMedia() const { connectionState, error } = useRoom() return (
{connectionState}
{error &&{error.message}
}{media.error.message}
}{media.error.message}
}