enough-match-43171
02/19/2026, 1:14 PMtall-airline-16756
02/19/2026, 1:14 PMtall-airline-16756
02/19/2026, 1:15 PMTokenSource.endpoint.
You can pass data by supplying the second options parameter to TokenSource.endpoint, the same way you would with fetch. Put your ID in body (stringified) and set the appropriate headers. Example:
const tokenSource = useMemo(() => {
return TokenSource.endpoint("/api/auth/livekit", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: "your-id-value" }),
});
}, []);
If the ID is dynamic (e.g., from props or state), include that variable:
const tokenSource = useMemo(() => {
return TokenSource.endpoint("/api/auth/livekit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id }),
});
}, [id]);
Server-side (example Next.js API route) — read the body and generate the token:
// pages/api/auth/livekit.ts
import { AccessToken } from "livekit-server-sdk";
export default async function handler(req, res) {
if (req.method !== "POST") return res.status(405).end();
const { id } = req.body;
const at = new AccessToken(process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET);
at.identity = `user-${id}`;
at.addGrant({ roomJoin: true, room: "my-room" });
const token = await at.toJwt();
res.json({ token });
}
Notes:
• Use method: "POST" so the body is sent.
• Always JSON.stringify the body and set Content-Type: application/json.
• If id changes, add it to the useMemo dependency array so the token source updates.
If you want, tell me where your id comes from (prop, route param, authenticated user) and I’ll show the exact code to wire it up.
Sources: server-sdk-js | livekit/livekit_composite | DeepWikienough-match-43171
02/19/2026, 1:16 PMtall-airline-16756
02/19/2026, 1:16 PM'body' does not exist in type 'EndpointOptions'.
Short answer: that error is correct. The object form of TokenSource does not accept a body field. Use context (sent as query params) or provide a custom async function (if you need to POST JSON in the body).
Two practical options:
1) Use context (object form — sends data as query parameters)
• Good when GET + query params are fine.
• Example:
const tokenSource = {
endpoint: "/api/auth/livekit",
apiKey: "your-api-key",
context: { id: "user-123" },
};
On the server you’ll read id from query params (e.g., req.query.id or req.nextUrl.searchParams).
2) Use a custom async function for full control (POST with JSON body)
• Use this when you must send a JSON body or custom headers.
• Example:
const tokenSource = async (roomName: string, participantName: string) => {
const res = await fetch("/api/auth/livekit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: "user-123", roomName, participantName }),
});
const data = await res.json();
return data.token;
};
Pass this function directly where a TokenSource is accepted.
If you’d like, tell me:
• Whether GET/query params are acceptable, or you specifically need POST+body.
• Where the id comes from (prop/state/route/user session).
I’ll give the exact code snippet wired into your component (including correct useMemo dependencies) based on your choice.enough-match-43171
02/19/2026, 1:20 PMtall-airline-16756
02/19/2026, 1:20 PMcontext to pass data; it will be serialized into query parameters on a GET request.
◦ Example:
const tokenSource = {
endpoint: "/api/auth/livekit",
apiKey: "your-api-key",
context: { id: "user-123" },
};
• Server: read from query params (e.g., req.query.id or req.nextUrl.searchParams).
• Function form (custom async function) — You can send whatever you need (POST, JSON body, headers). This gives you full control and avoids the TypeScript error.
◦ Example:
const tokenSource = async (roomName: string, participantName: string) => {
const res = await fetch("/api/auth/livekit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: "user-123", roomName, participantName }),
});
const data = await res.json();
return data.token;
};
• Server: read JSON body as usual.
Which to use?
• Use context if passing data via query string is acceptable and you want the simple object form.
• Use a custom function if you need to send a POST body, custom headers, or compute the payload dynamically.
If you tell me whether GET/query params are acceptable or you need POST+body (and where the id comes from—prop, state, route param, or user session), I’ll give the exact code snippet wired into your component (with useMemo and correct typings).