RTC HTTP API: rooms, admission, media, and controls
This page describes public calling conventions; use the contract bundled with the target version for exact fields. A business backend manages rooms and issues one-use tickets with an authorized Authorization: Bearer ak_pat_... token. A meeting SDK consumes the ticket and uses a device-bound X-AK-RTC-Token on /api/v2/rtc/session/.... Browsers and apps must not hold the platform management token. Post-meeting archives use a separate archive ticket.
sequenceDiagram
participant Backend as Business backend
participant API as AKStream.Next
participant SDK as Meeting SDK
Backend->>API: POST /rtc/rooms (ak_pat_)
Backend->>API: POST /rooms/{roomId}/access-tickets
Backend-->>SDK: roomId + one-use accessTicket
SDK->>API: POST /session/rooms/{roomId}/join
API-->>SDK: participantToken + deviceSessionId + capabilities
SDK->>API: X-AK-RTC-Token + independent publication/subscription
Backend: rooms and one-use identity
| Endpoint | Input and purpose | Result/next step | Grant and edge case |
|---|---|---|---|
GET /api/v2/rtc/capabilities |
Discover this server's SFU feature contract | Capability result | Check deployed version; a planned capability is not physical-device acceptance. |
GET /api/v2/rtc/rooms / GET /api/v2/rtc/rooms/{roomId} |
Search rooms and read detail | Policy, status, membership | Access-scoped; closed rooms reject new devices. |
POST /api/v2/rtc/rooms |
CreateRtcRoomRequest: name, type, media node, participant limits, access, waiting, recording/board/chat switches |
Room result with roomId |
rtc.manage. Optional UUID idempotencyKey should be reused for the same creator/request retry. enableRecording=true does not start recording. |
POST /api/v2/rtc/rooms/{roomId}/access-tickets |
subjectIssuer, subjectId, displayName, role, capabilities, expiresInMinutes, bypassWaitingRoom |
One-use accessTicket, room, expiry |
rtc.manage. Your backend owns the subject; AKStream.Next need not create that user's password. Plain ticket is returned once. |
PUT /api/v2/rtc/rooms/{roomId}/capacity |
Room member/publisher limits | Updated policy | Room limits cannot bypass license quota; current occupancy is checked. |
POST /api/v2/rtc/rooms/{roomId}/close |
Administrative end | Closed state and member leave | rtc.manage; device sessions and media are released, not merely hidden from UI. |
Room fields: roomType supports meeting/chatroom/screen/whiteboard; accessMode is Open/InviteOnly; optional passcode is stored as a hash. scheduledStartAtUtc plus durationMinutes schedules a meeting; earlyJoinMinutes/maxExtensionMinutes/reminderMinutes define time limits. maxPublishers/maxScreenShares limit this room, while license quota is still enforced separately. mediaServerId/app select the media destination and namespace, not client-controlled free text after creation.
Ticket fields: subjectIssuer + subjectId are stable business identity; the backend confirms displayName; requested capabilities are an upper bound intersected with role and room policy. Only a permitted backend can grant bypassWaitingRoom. Never put accessTicket in a shareable URL or plaintext log.
Meeting SDK: device session and renewal
| Endpoint | Main input | Result/next step | Rule |
|---|---|---|---|
POST /api/v2/rtc/session/rooms/{roomId}/join |
JSON accessTicket, optional passcode, platform, clientVersion, initial mic/camera state |
participantToken, expiry, participant/device session, final capabilities, admissionStatus |
Only meeting action that does not yet have an RTC token. Waiting cannot publish. |
POST /api/v2/rtc/session/rooms/{roomId}/token/refresh |
Current device's X-AK-RTC-Token |
Rotated token/version/expiry | Old version becomes invalid. SDK renews before expiry; do not replay an old one indefinitely. |
GET /api/v2/rtc/session/rooms/{roomId} / GET .../participants |
Current device token | Room, members, policy, grants | Current room only. Former/replaced device identity is not reusable. |
GET .../admission/status |
Current device token | Waiting/Admitted/Denied | Host approval is required when waiting room is on. |
POST .../heartbeat |
Current device token | Keepalive state | Server verifies device binding. SDK sends periodically. |
POST .../leave |
Current device token | Device leave | Releases its publications/subscriptions; closing a tab alone relies on timeout cleanup. |
GET .../connection-settings |
Current device token | STUN/TURN config | Use current server candidates; do not embed TURN credentials in an app package. |
GET .../signaling/ws?lastSequence=N |
Current token and replay cursor | WebSocket event stream | Replay missing sequence after reconnect, without reviving old-session moderation effects. |
platform identifies an actual client such as pc-web/h5/android/ios/wechat-mini-program. A device session ID belongs to one join and is not a hardware serial number. Requested capabilities and initial mic/camera flags are not grants; all later HTTP/WS work uses the server's effective identity.
Independent publications and subscriptions
| Task / endpoint | Input | Result and completion | Edge case |
|---|---|---|---|
POST .../publications |
mediaKind=MicrophoneAudio/CameraVideo/ScreenVideo/ScreenAudio (mini-program may use MiniProgramCombined), optional codec/layers |
Publication ID pending negotiation | One member can have several tracks. Codec preference does not override SDP/media-node result. |
POST .../publications/{publicationId}/whip |
Content-Type: application/sdp offer |
SDP answer and session/release location | Not JSON. Only owning device may publish. available instance capacity still applies. |
GET .../publications |
Current token | Visible/subscribeable publications | Camera, mic, and screen have distinct IDs. Do not group by display name. |
POST .../subscriptions |
publicationId, optional priority -100..100, requested layer, visible/pinned |
Subscription ID | Only active and permitted publications. |
POST .../subscriptions/{subscriptionId}/whep |
SDP offer | SDP answer and media session | Release on leave/stop. A local preview is not proof the remote side decoded it. |
POST .../subscriptions/{subscriptionId}/stop / POST .../publications/{publicationId}/stop |
Owned ID | Stopped state | A device cannot stop another device's stream. |
POST .../playback-ticket |
Active publication in current room | Short-lived HTTP-FLV address | Different from join/admin/archive tickets; invalid after publication stops. |
Here ... means /api/v2/rtc/session/rooms/{roomId}. SDKs handle SDP, ICE, recovery, and release; application UI should call SDK methods rather than reimplement WHIP/WHEP. HTTP 200 only proves control-plane negotiation; verify real frames and audio on a second device.
Host governance, external sources, collaboration
| Endpoint group | Input/purpose | Permission boundary |
|---|---|---|
PUT .../access-policy, POST .../participants/{participantId}/admission |
Access/waiting/lock policy; admit/deny waiting member | Current authorized host/moderator, checked at execution time. |
POST .../host/transfer, POST .../host/claim, POST .../participants/{participantId}/cohost |
Transfer, recovery claim, cohost grant | Former host immediately loses host-only rights; claim cannot seize an active host. |
POST .../participants/{participantId}/moderation, PUT .../video-quality |
Mute/camera/kick/role or target quality | Actor and target identity verified. Desired quality is not immediate effective quality. |
POST .../invitations, GET .../invitations, POST .../invitations/{invitationId}/revoke |
Host issues/lists/revokes invitations | Only valid, unused, unrevoked invitation can join. |
POST .../whiteboard/access-request, POST .../participants/{participantId}/whiteboard-access, POST .../whiteboard/lock |
Request/grant/revoke writing, lock | Image commit rechecks write rights; lock does not erase prior events. |
POST .../chat/attachments, GET .../chat/attachments/{attachmentId} |
Upload/read chat or board material | Device and direct-message visibility checked at commit and read. |
GET .../external-sources/candidates, GET .../external-sources, POST .../external-sources, DELETE .../external-sources/{bindingId} |
Candidate grants, current bindings, add by grantId, remove by bindingId |
External source is not a participant. Remove does not stop the original channel. |
A trusted backend first creates/revokes source grants with GET/POST /api/v2/rtc/rooms/{roomId}/external-sources/grants and DELETE .../grants/{grantId} for an existing channelId. GrantRtcExternalSourceRequest can set allowRecording/allowHistoricalArchive; the meeting SDK selects only an authorized grantId. Candidate snapshots do not reveal RTSP source URLs. Verify device and codec combinations in the target environment.
Errors and next step
| Status/condition | Meaning and action |
|---|---|
| 400 | Invalid fields, SDP, capability, or range. Check this version's model and Content-Type. |
| 401 | Invalid/consumed access ticket, expired RTC token, or replaced device. Obtain a new backend ticket instead of looping old credentials. |
| 403 | Current room, role, device, or grant denies the action. Hiding a button is not authorization. |
| 404 | Room, member, publication/subscription, or grant does not belong here. |
| 409 / waiting | Capacity, leadership, or old media-session conflict. Refresh snapshot before supported recovery. |
| Local preview but no remote picture | Check WHIP/ICE/TURN, license quota, effective publication, and remote decode. |
See references/openapi.json in the matching Skill for all public HTTP methods, paths and models. Component interfaces are outside third-party integration; newer documentation does not establish support in an older deployment.