Integrations

API reference

Control rooms programmatically with the REST API, or subscribe to live updates over WebSocket. API access is available on Yearly and Single Event plans.

Authentication

Create an API key from the dashboard under API Keys. Keys are shown once at creation and use the format ptp_….

Send the key on every REST request:

Authorization: Bearer ptp_your_api_key_here

API keys are scoped to your user account. Room access is limited to rooms in your organization. Keys are tied to the user who created them — any active organization membership for that user is used.

REST API

Base URL: https://stagetoolkit.com

GET/api/v1/rooms/[slug]

Read the current room configuration — timers, messages, and active timer selection.

Response

{
  "slug": "abc123",
  "activeTimerId": "timer-id-or-null",
  "timers": [
    {
      "id": "…",
      "title": "Opening",
      "speaker": "Host",
      "durationMs": 300000,
      "mode": "countdown",
      "sortOrder": 0,
      "…": "…"
    }
  ],
  "messages": [
    {
      "id": "…",
      "text": "Wrap in 2 minutes",
      "color": "yellow",
      "status": "queued",
      "sortOrder": 0,
      "durationMs": 10000,
      "flash": false
    }
  ]
}

Example

curl -s "https://stagetoolkit.com/api/v1/rooms/abc123" \
  -H "Authorization: Bearer ptp_your_api_key_here"
POST/api/v1/rooms/[slug]

Send a control action to the room. Returns { "ok": true } on success.

Request body

{
  "action": "start",
  "timerId": "optional-timer-id",
  "messageId": "optional-message-id"
}

Actions

ActionDescriptionExtra fields
startStart the active or specified timertimerId (optional)
pausePause the running timer
resetReset the active or specified timertimerId (optional)
timer.selectSelect which timer is activetimerId (required)
message.showPush a queued message to airmessageId (required)
prompter.playStart prompter scroll
prompter.pausePause prompter scroll

Example

curl -s -X POST "https://stagetoolkit.com/api/v1/rooms/abc123" \
  -H "Authorization: Bearer ptp_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"action":"start"}'
GET/api/rooms/[slug]/access-check?role=viewer

Check whether a shared link role requires a passcode before joining. No authentication required. Valid roles: viewer, agenda, qna, qna-screen.

{ "passcodeRequired": true }

WebSocket

Connect to the realtime server for live room state and bidirectional control. URL: wss://timer-app-realtime.fly.dev (set via NEXT_PUBLIC_WS_URL in production).

Join a room

Send room.join as the first message after connecting. Controller and moderator roles require the token from the room's share links.

{
  "type": "room.join",
  "payload": {
    "slug": "abc123",
    "role": "viewer",
    "token": "optional-share-token",
    "passcode": "optional-link-passcode"
  }
}

Server events

EventDescription
room.stateFull live room snapshot (timers, runtime, messages, script, settings, connections)
errorJoin or action failed — includes message and optional code
pongResponse to ping keepalive

Client events

After joining, send JSON messages with a type field. Available events depend on your connection role. Common examples:

EventRoleDescription
timer.startcontrollerStart timer — optional timerId in payload
timer.pausecontrollerPause the running timer
timer.resetcontrollerReset timer — optional timerId
timer.selectcontrollerSet active timer
timer.addTimecontrollerAdd milliseconds — payload.ms
timer.subtractTimecontrollerSubtract milliseconds — payload.ms
message.showcontroller, moderatorShow message — payload.messageId
message.createcontroller, moderatorCreate and queue a message
prompter.playcontrollerStart prompter scroll
prompter.pausecontrollerPause prompter scroll
question.createqna, askSubmit audience question
question.upvoteqna, askUpvote a question
settings.updatecontrollerUpdate room theme, chimes, Q&A settings, etc.
layout.setcontrollerSwitch viewer layout (timer, prompter, split)
room.resynccontrollerRestore live state after reconnect
pinganyKeepalive — server replies with pong

The server broadcasts room.state whenever something changes. Controllers receive the full state including runtime timer progress and connection list.

Connection roles

Use these values in room.join. Token requirements match the share links in the room control panel.

RoleAccessToken
controllerFull room control — timers, messages, prompter, settingsRequired
viewerRead-only output displayOptional passcode
moderatorMessages and Q&A moderationRequired
agendaRundown / agenda viewOptional passcode
qnaAudience Q&A lobby — submit and vote on questionsOptional passcode
qna-screenVenue screen for displayed questionsOptional passcode
askLegacy alias for audience Q&A (same as qna)Optional passcode

Errors

REST endpoints return JSON error bodies with an HTTP status code.

StatusMeaning
401Missing or invalid API key
403Plan does not include this feature — code: PLAN
404Room not found or not in your organization
400Invalid action or request body

Example plan error:

{
  "error": "API access requires Pro or Premium plan",
  "code": "PLAN",
  "action": "api.room.read"
}