batondocs← SiteSign in
Integrations/Custom WebRTC app

Custom WebRTC app

The canonical flow for any app built on raw RTCPeerConnection: your server mints an ephemeral token from the credentials API, and your client uses it. The API key never leaves your server.

1. Mint a token on your server

Expose a small endpoint that calls Baton with your project API key and returns just the ephemeral result to the browser.

server.js — POST /api/ice
app.post("/api/ice", async (req, res) => {
  // BATON_API_KEY lives only here, on the server
  const r = await fetch("https://api.usebaton.io/v1/credentials", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.BATON_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ ttl: 3600, region: "eu-central" })
  });
  const { iceServers } = await r.json();
  res.json({ iceServers });   // only the ephemeral token reaches the browser
});

2. Use the token on the client

client.js
const { iceServers } = await fetch("/api/ice").then(r => r.json());

const pc = new RTCPeerConnection({
  iceServers,
  iceTransportPolicy: "all"   // use "relay" to force-test the relay path
});
One model, everywhere

This is the same flow every integration uses: API key (server) → ephemeral token → client. Fetch a fresh token before the previous one's TTL expires; never embed the API key or any token in client or config files. See Authentication.