{
  "info": {
    "name": "TroveMeet media server API",
    "_postman_id": "8c0f5d8e-2f4c-4f43-9a66-3b0e1c9d7a10",
    "description": "Server API of the live-class media server. Set the collection variables (baseUrl, apiKey, apiSecret; get a key at /console), and every request is signed for you. The media server keeps no database: keep what you need from responses and webhooks.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Signs a short-lived admin token (HS256) with your API secret, so every",
          "// request carries Authorization: Bearer <token>. No other setup needed.",
          "const b64 = (wa) => CryptoJS.enc.Base64.stringify(wa).replace(/=+$/, '').replace(/\\+/g, '-').replace(/\\//g, '_');",
          "const enc = (o) => b64(CryptoJS.enc.Utf8.parse(JSON.stringify(o)));",
          "const now = Math.floor(Date.now() / 1000);",
          "const head = enc({ alg: 'HS256', typ: 'JWT' });",
          "const body = enc({ iss: pm.collectionVariables.get('apiKey'), admin: true, iat: now, exp: now + 300 });",
          "const sig = b64(CryptoJS.HmacSHA256(head + '.' + body, pm.collectionVariables.get('apiSecret')));",
          "pm.request.headers.upsert({ key: 'Authorization', value: 'Bearer ' + head + '.' + body + '.' + sig });"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://media.example.com"
    },
    {
      "key": "appUrl",
      "value": "https://meet.example.com"
    },
    {
      "key": "apiKey",
      "value": "tvk_your_key"
    },
    {
      "key": "apiSecret",
      "value": "your_secret"
    },
    {
      "key": "roomId",
      "value": "postman-demo"
    },
    {
      "key": "recordingId",
      "value": ""
    },
    {
      "key": "joinToken",
      "value": ""
    },
    {
      "key": "joinLink",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Join",
      "item": [
        {
          "name": "Make a join link (see console)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/health",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "health"
              ]
            },
            "description": "Pre-request script builds a host join token and join link for {{roomId}} and prints them in the Postman console. The request itself only checks the server is up.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Builds a join token and a join link for the user below and prints them",
                  "// (open the link in a browser to enter the class).",
                  "const b64 = (wa) => CryptoJS.enc.Base64.stringify(wa).replace(/=+$/, '').replace(/\\+/g, '-').replace(/\\//g, '_');",
                  "const enc = (o) => b64(CryptoJS.enc.Utf8.parse(JSON.stringify(o)));",
                  "const now = Math.floor(Date.now() / 1000);",
                  "const head = enc({ alg: 'HS256', typ: 'JWT' });",
                  "const body = enc({ iss: pm.collectionVariables.get('apiKey'), sub: 'postman-teacher', name: 'Postman Teacher', role: 'host', room: pm.collectionVariables.get('roomId'), iat: now, exp: now + 3600 });",
                  "const token = head + '.' + body + '.' + b64(CryptoJS.HmacSHA256(head + '.' + body, pm.collectionVariables.get('apiSecret')));",
                  "const link = pm.collectionVariables.get('appUrl') + '/join#token=' + token + '&url=' + encodeURIComponent(pm.collectionVariables.get('baseUrl')) + '&name=Postman%20Teacher';",
                  "pm.collectionVariables.set('joinToken', token);",
                  "pm.collectionVariables.set('joinLink', link);",
                  "console.log('Join link:', link);"
                ]
              }
            }
          ]
        },
        {
          "name": "Route a room (multi-node)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/route",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "route"
              ]
            },
            "description": "Which media server hosts (or will host) the room.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"region\": \"\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Rooms",
      "item": [
        {
          "name": "Create or update a room",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms"
              ]
            },
            "description": "Optional: settings can ride in join tokens instead (roomConfig).",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"id\": \"{{roomId}}\",\n  \"name\": \"Biology 101\",\n  \"waitingRoom\": true,\n  \"durationMinutes\": 60,\n  \"permissions\": {\n    \"chat\": true,\n    \"screenShare\": false,\n    \"canUnmute\": true\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List rooms",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms?active=true",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms"
              ],
              "query": [
                {
                  "key": "active",
                  "value": "true"
                }
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Get a room",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Update settings",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}"
              ]
            },
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"waitingRoom\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Participants and waiting room",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/participants",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "participants"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Mute a participant",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/participants/postman-student/mute",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "participants",
                "postman-student",
                "mute"
              ]
            },
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"microphone\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Remove a participant",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/participants/postman-student/remove",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "participants",
                "postman-student",
                "remove"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "End the class",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/end",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "end"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Delete a room",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}"
              ]
            },
            "description": ""
          }
        }
      ]
    },
    {
      "name": "Attendance and reports",
      "item": [
        {
          "name": "Attendance (JSON)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/attendance",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "attendance"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Attendance (CSV)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/attendance?format=csv",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "attendance"
              ],
              "query": [
                {
                  "key": "format",
                  "value": "csv"
                }
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Runs (each sitting of the class)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/runs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "runs"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Per-student analytics",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/analytics",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "analytics"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Class report",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/report",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "report"
              ]
            },
            "description": ""
          }
        }
      ]
    },
    {
      "name": "Recordings",
      "item": [
        {
          "name": "Start recording",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/recordings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "recordings"
              ]
            },
            "description": "Add \"upload\": {\"mediaUrl\": \"<presigned PUT>\", \"timelineUrl\": \"...\"} to have the files sent to your storage.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const j = pm.response.json(); if (j.id) pm.collectionVariables.set('recordingId', j.id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Stop recording",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/recordings/stop",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "recordings",
                "stop"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "List recordings of a room",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/rooms/{{roomId}}/recordings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "rooms",
                "{{roomId}}",
                "recordings"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Get a recording",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/recordings/{{recordingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "recordings",
                "{{recordingId}}"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Playback links (signed)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/recordings/{{recordingId}}/playback",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "recordings",
                "{{recordingId}}",
                "playback"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Delete a recording",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/recordings/{{recordingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "recordings",
                "{{recordingId}}"
              ]
            },
            "description": ""
          }
        }
      ]
    },
    {
      "name": "Cluster",
      "item": [
        {
          "name": "Health",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/health",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "health"
              ]
            },
            "description": "",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Nodes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/nodes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "nodes"
              ]
            },
            "description": ""
          }
        }
      ]
    }
  ]
}