REST · v1

API reference

Spin up video, voice, live-stream and broadcast sessions, then pull back structured AI notes and tasks — the same data your team sees in-app. JSON in, JSON out, over HTTPS.

Base URL

Every endpoint below is relative to a versioned base URL. Use the staging host while you build, then flip a single constant to go live.

Production

Live traffic, real minutes billed.

Staging

Sandbox for integration testing — never billed, sessions expire in ~5 minutes.

Use your same key from the dashboard on either host. Sessions created against staging are marked test, expire after ~5 minutes, and are excluded from your usage and cost.

Authentication

Pass your secret key as a bearer token on every request. Generate and rotate keys in the dashboard. Never ship a secret key in client-side code.

header
Authorization: Bearer vk_live_9f2a…

Quick start

Create your first session in one call. Copy, paste in your key, run.

cURL
curl https://api.vanillameet.com/v1/sessions \
  -H "Authorization: Bearer $VANILLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "medium": "video",
    "mode": "group",
    "capacity": 6,
    "recording": true
  }'
Node
const res = await fetch("https://api.vanillameet.com/v1/sessions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VANILLA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ medium: "video", mode: "group", capacity: 6 }),
});
const session = await res.json();
console.log(session.join_url);

Create a session

Returns a single shareable join link, capped by capacity. Attach any metadata and it comes back on every related webhook.

POST /v1/sessions
POST /v1/sessions
Authorization: Bearer <api_key>

{
  "medium": "video" | "voice" | "live_stream" | "broadcast",
  "mode": "1:1" | "group",
  "capacity": 6,
  "recording": false,
  "metadata": { "reference_id": "abc123" },
  "features": { "screen_share": false, "recording": false }
}

200 OK
{
  "session_id": "sess_9f2a…",
  "join_url": "https://vanillameet.com/j/9f2a",
  "expires_at": "2026-07-24T18:30:00Z"
}

Meeting features

Turn in-call actions on or off per meeting with an optional features object on POST /v1/sessions. Any key you omit stays enabled — pass false to hide that control for everyone in the call.

screen_sharePresent / share screen
chatIn-call text chat
recordingRecord the call
captionsLive captions
reactionsEmoji reactions
raise_handRaise hand
celebrateCelebrate 🎉
inviteInvite others mid-call
disable presenting + recording
{
  "medium": "video",
  "features": { "screen_share": false, "recording": false }
}

List sessions

Filter your session history by date range and medium. Results are paginated newest-first.

GET /v1/sessions
GET /v1/sessions?since=2026-07-01&until=2026-07-24&medium=video

200 OK
{
  "data": [
    { "session_id": "sess_9f2a…", "medium": "video", "minutes": 42, "ended_at": "2026-07-20T15:04:00Z" }
  ],
  "has_more": false
}

Get notes for a session

Structured AI notes and the per-participant task breakdown — the same content the host sees in-app. Available once session.notes_ready fires.

GET /v1/sessions/{id}/notes
GET /v1/sessions/{session_id}/notes

200 OK
{
  "session_id": "sess_9f2a…",
  "ready": true,
  "summary": "Kickoff for the Q3 launch…",
  "decisions": ["Ship the beta on the 14th"],
  "tasks": [
    { "text": "Draft the launch email", "owner": "Jane" }
  ]
}

ready is false with empty fields until the call ends and notes are generated (also signalled by the session.notes_ready webhook).

Errors

Errors return the right HTTP status with a stable machine-readable code and a human message.

401 Unauthorized
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key."
  }
}
400invalid_requestA field is missing or malformed.
401unauthorizedMissing or invalid API key.
403forbiddenKey lacks access to this resource.
404not_foundNo session with that id.
429rate_limitedToo many requests — back off and retry.
500server_errorSomething broke on our end. Safe to retry.

Rate limits

The default limit is 120 requests/minute per key. Every response carries your current budget in headers — read them and back off on 429.

response headers
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1721840400

Webhooks

Subscribe to lifecycle events to track usage or route tasks into your own system. Add endpoints in the dashboard; every delivery is signed so you can verify it came from us.

  • session.started
  • session.participant_joined
  • session.participant_left
  • session.ended
  • session.recording_ready
  • session.notes_ready
  • task.assigned
POST to your endpoint
{
  "event": "session.notes_ready",
  "session_id": "sess_9f2a…",
  "metadata": { "reference_id": "abc123" },
  "created_at": "2026-07-20T15:05:00Z"
}