Files
rondevu-server/API.md
Bas van den Aakster 82c0e8b065 Initial commit: Rondevu signaling server
Open signaling and tracking server for peer discovery in distributed P2P applications.

Features:
- REST API for WebRTC peer discovery and signaling
- Origin-based session isolation
- Multiple storage backends (SQLite, in-memory, Cloudflare KV)
- Docker and Cloudflare Workers deployment support
- Automatic session cleanup and expiration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 14:32:25 +01:00

10 KiB

HTTP API

This API provides peer signaling and tracking endpoints for distributed peer-to-peer applications. Uses JSON request/response bodies with Origin-based session isolation.

All endpoints require an Origin header and accept application/json content type.


Overview

Sessions are organized by:

  • Origin: The HTTP Origin header (e.g., https://example.com) - isolates sessions by application
  • Topic: A string identifier for grouping related peers (max 256 chars)
  • Info: User-provided metadata (max 1024 chars) to uniquely identify each peer

This allows multiple peers from the same application (origin) to discover each other through topics while preventing duplicate connections by comparing the info field.


GET /

Lists all topics with the count of available peers for each (paginated). Returns only topics that have unanswered sessions.

Request

Headers:

  • Origin: https://example.com (required)

Query Parameters:

Parameter Type Required Default Description
page number No 1 Page number (starting from 1)
limit number No 100 Results per page (max 1000)

Response

Content-Type: application/json

Success (200 OK):

{
  "topics": [
    {
      "topic": "my-room",
      "count": 3
    },
    {
      "topic": "another-room",
      "count": 1
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 100,
    "total": 2,
    "hasMore": false
  }
}

Notes:

  • Only returns topics from the same origin as the request
  • Only includes topics with at least one unanswered session
  • Topics are sorted alphabetically
  • Counts only include unexpired sessions
  • Maximum 1000 results per page

Examples

Default pagination (page 1, limit 100):

curl -X GET http://localhost:3000/ \
  -H "Origin: https://example.com"

Custom pagination:

curl -X GET "http://localhost:3000/?page=2&limit=50" \
  -H "Origin: https://example.com"

GET /:topic/sessions

Discovers available peers for a given topic. Returns all unanswered sessions from the requesting origin.

Request

Headers:

  • Origin: https://example.com (required)

Path Parameters:

Parameter Type Required Description
topic string Yes Topic identifier to query

Response

Content-Type: application/json

Success (200 OK):

{
  "sessions": [
    {
      "code": "550e8400-e29b-41d4-a716-446655440000",
      "info": "peer-123",
      "offer": "<SIGNALING_DATA>",
      "offerCandidates": ["<SIGNALING_DATA>"],
      "createdAt": 1699564800000,
      "expiresAt": 1699565100000
    },
    {
      "code": "660e8400-e29b-41d4-a716-446655440001",
      "info": "peer-456",
      "offer": "<SIGNALING_DATA>",
      "offerCandidates": [],
      "createdAt": 1699564850000,
      "expiresAt": 1699565150000
    }
  ]
}

Notes:

  • Only returns sessions from the same origin as the request
  • Only returns sessions that haven't been answered yet
  • Sessions are ordered by creation time (newest first)
  • Use the info field to avoid answering your own offers

Example

curl -X GET http://localhost:3000/my-room/sessions \
  -H "Origin: https://example.com"

POST /:topic/offer

Announces peer availability and creates a new session for the specified topic. Returns a unique session code (UUID) for other peers to connect to.

Request

Headers:

  • Content-Type: application/json
  • Origin: https://example.com (required)

Path Parameters:

Parameter Type Required Description
topic string Yes Topic identifier for grouping peers (max 256 characters)

Body Parameters:

Parameter Type Required Description
info string Yes Peer identifier/metadata (max 1024 characters)
offer string Yes Signaling data for peer connection

Response

Content-Type: application/json

Success (200 OK):

{
  "code": "550e8400-e29b-41d4-a716-446655440000"
}

Returns a unique UUID session code.

Example

curl -X POST http://localhost:3000/my-room/offer \
  -H "Content-Type: application/json" \
  -H "Origin: https://example.com" \
  -d '{
    "info": "peer-123",
    "offer": "<SIGNALING_DATA>"
  }'

# Response:
# {"code":"550e8400-e29b-41d4-a716-446655440000"}

POST /answer

Connects to an existing peer session by sending connection data or exchanging signaling information.

Request

Headers:

  • Content-Type: application/json
  • Origin: https://example.com (required)

Body Parameters:

Parameter Type Required Description
code string Yes The session UUID from the offer
answer string No* Response signaling data for connection establishment
candidate string No* Additional signaling data for connection negotiation
side string Yes Which peer is sending: offerer or answerer

*Either answer or candidate must be provided, but not both.

Response

Content-Type: application/json

Success (200 OK):

{
  "success": true
}

Notes:

  • Origin header must match the session's origin
  • Sessions are isolated by origin to group topics by domain

Examples

Sending connection response:

curl -X POST http://localhost:3000/answer \
  -H "Content-Type: application/json" \
  -H "Origin: https://example.com" \
  -d '{
    "code": "550e8400-e29b-41d4-a716-446655440000",
    "answer": "<SIGNALING_DATA>",
    "side": "answerer"
  }'

# Response:
# {"success":true}

Sending additional signaling data:

curl -X POST http://localhost:3000/answer \
  -H "Content-Type: application/json" \
  -H "Origin: https://example.com" \
  -d '{
    "code": "550e8400-e29b-41d4-a716-446655440000",
    "candidate": "<SIGNALING_DATA>",
    "side": "offerer"
  }'

# Response:
# {"success":true}

POST /poll

Retrieves session data including offers, responses, and signaling information from the other peer.

Request

Headers:

  • Content-Type: application/json
  • Origin: https://example.com (required)

Body Parameters:

Parameter Type Required Description
code string Yes The session UUID
side string Yes Which side is polling: offerer or answerer

Response

Content-Type: application/json

Success (200 OK):

Response varies by side:

For side=offerer (the offerer polls for response from answerer):

{
  "answer": "<SIGNALING_DATA>",
  "answerCandidates": [
    "<SIGNALING_DATA_1>",
    "<SIGNALING_DATA_2>"
  ]
}

For side=answerer (the answerer polls for offer from offerer):

{
  "offer": "<SIGNALING_DATA>",
  "offerCandidates": [
    "<SIGNALING_DATA_1>",
    "<SIGNALING_DATA_2>"
  ]
}

Notes:

  • answer will be null if the answerer hasn't responded yet
  • Candidate arrays will be empty [] if no additional signaling data has been sent
  • Use this endpoint for polling to check for new signaling data
  • Origin header must match the session's origin

Examples

Answerer polling for signaling data:

curl -X POST http://localhost:3000/poll \
  -H "Content-Type: application/json" \
  -H "Origin: https://example.com" \
  -d '{
    "code": "550e8400-e29b-41d4-a716-446655440000",
    "side": "answerer"
  }'

# Response:
# {
#   "offer": "<SIGNALING_DATA>",
#   "offerCandidates": ["<SIGNALING_DATA>"]
# }

Offerer polling for response:

curl -X POST http://localhost:3000/poll \
  -H "Content-Type: application/json" \
  -H "Origin: https://example.com" \
  -d '{
    "code": "550e8400-e29b-41d4-a716-446655440000",
    "side": "offerer"
  }'

# Response:
# {
#   "answer": "<SIGNALING_DATA>",
#   "answerCandidates": ["<SIGNALING_DATA>"]
# }

GET /health

Health check endpoint.

Response

Content-Type: application/json

Success (200 OK):

{
  "status": "ok",
  "timestamp": 1699564800000
}

Error Responses

All endpoints may return the following error responses:

400 Bad Request:

{
  "error": "Missing or invalid required parameter: topic"
}

404 Not Found:

{
  "error": "Session not found, expired, or origin mismatch"
}

500 Internal Server Error:

{
  "error": "Internal server error"
}

Usage Flow

Peer Discovery and Connection

  1. Discover active topics:

    • GET / to see all topics and peer counts
    • Optional: paginate through results with ?page=2&limit=100
  2. Peer A announces availability:

    • POST /:topic/offer with peer identifier and signaling data
    • Receives a unique session code
  3. Peer B discovers peers:

    • GET /:topic/sessions to list available sessions in a topic
    • Filters out sessions with their own info to avoid self-connection
    • Selects a peer to connect to
  4. Peer B initiates connection:

    • POST /answer with the session code and their signaling data
  5. Both peers exchange signaling information:

    • POST /answer with additional signaling data as needed
    • POST /poll to retrieve signaling data from the other peer
  6. Peer connection established

    • Peers use exchanged signaling data to establish direct connection
    • Session automatically expires after configured timeout