Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Calls API

10 endpoints. ScaiWave delegates SFU duties to LiveKit; this API mints LiveKit tokens, tracks call state, and handles recordings.

Method Path Purpose
POST /v1/calls/initiate Start a call in a room.
POST /v1/calls/{call_id}/join Join an in-flight call.
POST /v1/calls/{call_id}/leave Leave.
POST /v1/calls/{call_id}/reject Decline a ringing call.
POST /v1/calls/{call_id}/end End the call for everyone (initiator or power ≥ 50).
GET /v1/calls/{call_id} Call state.
POST /v1/calls/{call_id}/recording/start Start recording (admin).
POST /v1/calls/{call_id}/recording/stop Stop.
GET /v1/calls/{call_id}/recordings List finished recordings as media references.
POST /v1/calls/webhook LiveKit webhook callback (server-to-server).

POST /v1/calls/initiate#

jsonc
{
  "room_id": "<scaiwave-room-id>",
  "type": "audio"        // or "video"
}

Returns a LiveKit token and call id:

jsonc
{
  "data": {
    "call_id": "call-…",
    "livekit_url": "wss://livekit.example.com",
    "livekit_token": "eyJ…",
    "livekit_room": "scaiwave-<call_id>"
  }
}

The client connects to LiveKit with that token; LiveKit handles media. Other room members get a swp.call.invite WebSocket event with a ringing UI.

POST /v1/calls/{call_id}/join#

bash
1
2
curl -X POST "$BASE/v1/calls/$CALL_ID/join" \
  -H "Authorization: Bearer $TOKEN"

Returns a token scoped to this caller. The same LiveKit room already exists.

Recordings#

bash
1
2
3
curl -X POST "$BASE/v1/calls/$CALL_ID/recording/start" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"audio": true, "video": true, "transcript": true}'

LiveKit egress streams to MinIO under recordings/<call_id>/<timestamp>.mp4. Once egress finishes, the recording is registered as a media entry and attached to the ScaiWave call. If transcript: true, an async transcription job runs and posts the result back to the room.

Webhook#

LiveKit POSTs back when room state changes (participant joined / left, egress finished). Signed via LiveKit's HMAC scheme; ScaiWave verifies before processing.

You don't call this; LiveKit does. Configure the URL in your LiveKit project's webhook settings.

State#

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "data": {
    "id": "call-…",
    "room_id": "room-…",
    "type": "video",
    "status": "active",
    "started_at": "...",
    "ended_at": null,
    "initiator_id": "5e4d…",
    "participants": [
      { "participant_id": "5e4d…", "joined_at": "...", "video_on": true, "audio_on": true }
    ],
    "recordings": []
  }
}

Errors#

  • SW_CALL_NOT_FOUND / SW_CALL_ENDED — call no longer active.
  • SW_CALL_LIVEKIT_UNREACHABLE — backend ops issue.
  • SW_CALL_FORBIDDEN — caller isn't in the room.
  • SW_CALL_RECORDING_DISABLED — tenant has recordings disabled.
Updated 2026-05-18 12:07:13 View source (.md) rev 4