Skip to content

Concepts/Authentication

Authentication

Velo has two credentials and they are not interchangeable. A project API key controls the whole project and stays on your server. A room token admits one identity to one room and is the only thing a browser should ever hold.

The header

Every project endpoint reads a bearer token from the Authorization header. There is no query parameter and no cookie for the public API.

curl
curl https://api.usevelo.xyz/v1/rooms \
  -H "Authorization: Bearer $VELO_API_KEY"

The SDK builds the same header for you. It is the one place the key is read, and it warns loudly if it finds itself running in a browser.

typescriptserver
import { VeloClient } from "@usevelo/client";

const velo = new VeloClient({
  baseUrl: "https://api.usevelo.xyz",
  apiKey: process.env.VELO_API_KEY as string,
});

What a key looks like

A project API key is three parts joined by underscores: the literal vk_ prefix, the environment the project was created in, and 43 random base62 characters. The two below are zero-filled placeholders, so neither will ever authenticate anything.

text
vk_live_EXAMPLEKEY000000000000000000000000000000000
vk_test_EXAMPLEKEY000000000000000000000000000000000
vk_
Marks the string as a Velo project key wherever it turns up, including in a leak scan.
live | test
The project environment. A test project is a separate project with its own rooms, templates and usage.
first 12 characters
The key prefix. It is what the console lists, what revocation takes, and what shows up in audit trails. The rest is never stored.

Shown once

Velo stores a SHA-256 hash of the key and the 12-character prefix. The full key is returned exactly once, in the response that creates it. Listing keys afterwards returns prefixes and timestamps and nothing else, because there is nothing else left to return.

  • Copy the key into your secret store the moment it is created.
  • Lost a key: create a new one, move your services over, then revoke the old prefix.
  • Leaked a key: revoke the prefix first. Revocation takes effect on the next request.

A project API key can create rooms, mint a token for any identity, remove participants, start recordings and read usage. Treat it exactly like a database password. It belongs in an environment variable on a server, never in a repository and never in a bundle a browser downloads.

Keys and room tokens

Moderation endpoints accept either credential. A project API key acts for the project and is always allowed. A room token is checked against the role it was minted for, so a participant can only mute or remove someone if their role holds that permission.

Project API key
vk_.... Server side only. Authorises all 53 project endpoints.
Room token
A JWT minted by POST /v1/tokens. Scoped to one room, one identity and one role, with a ttl of at most 24 hours. Safe to send to a browser.

The shape that keeps them apart: the browser asks your backend for a token, your backend calls POST /v1/tokens with the key, and the browser receives the token and the connection url. See Your first room for that exchange end to end.

ttl_seconds defaults to 3600, one hour. It accepts 60 at the least and 86400 at the most, and a value outside that range is clamped rather than refused: ask for a week and you get a token good for a day, with no error to tell you so. Read expires_at off the response instead of assuming you got what you asked for. Mint a token for about as long as the call should last, and mint a fresh one if someone needs to rejoin, rather than issuing a long token to save a round trip.

When auth fails

A missing, malformed or unknown key all fail identically with 401 unauthorized: invalid api key, so nothing about the key space can be probed. A key that exists but has been revoked says so. Every error in the API uses this envelope.

json401 Unauthorized
{
  "error": {
    "code": "unauthorized",
    "message": "invalid api key"
  }
}
  • 401 unauthorized means the credential was not accepted.
  • 403 permission_denied means the credential was accepted but the acting role lacks the permission. The field key names the missing one.
  • 402 means a plan limit was reached, the project is suspended, or the plan does not include the feature you asked for. It is not an authentication failure. The code feature_not_in_plan is the last of those, and field names the feature: recording and live streaming are not on the free plan, so starting a recording or a broadcast, creating an ingress and writing a template destination are refused there. Listing, reading, stopping and deleting are not.

Edit this page on GitHub