Classification: Restricted SC-API StealthX // SecureCall

Signaling Protocol Reference

WebSocket signaling API documentation for SecureCall developers · Last updated February 2026

Signaling Server API

Overview

The SecureCall signaling server handles real-time communication between clients during call setup using WebSocket connections, and provides a simple HTTP endpoint for health monitoring. The server is deployed on Railway and acts as an opaque relay — it forwards encrypted signaling messages between clients but cannot read or modify their content.

The signaling server is responsible for:

HTTP Endpoints

REST API

The signaling server exposes a single HTTP endpoint for health monitoring. This endpoint requires no authentication and is used by Railway for deployment health checks.

Method Path Auth Description
GET /health None Health check — returns {"status":"ok"}

Example Request

GET /health HTTP/1.1
Host: protective-healing-production.up.railway.app

HTTP/1.1 200 OK
Content-Type: application/json

{"status":"ok"}
WebSocket Protocol

Connection

Clients connect to the signaling server via a secure WebSocket connection. All communication after the initial handshake uses JSON-encoded messages.

Connection URL

wss://protective-healing-production.up.railway.app/signal

Message Format

All WebSocket messages follow a consistent JSON structure with a type field identifying the message kind and a payload object containing message-specific data:

{
  "type": "MESSAGE_TYPE",
  "payload": { ... }
}
Connection lifecycle: After establishing the WebSocket connection, the client must send a REGISTER message within 60 seconds to associate its client ID with the connection. Failure to register will result in the server closing the connection.

Typical Call Flow

A standard call setup follows this sequence:

  1. Both clients connect and send REGISTER messages
  2. Client A sends CALL_INITIATE with an SDP offer targeting Client B
  3. Server forwards the offer to Client B as INCOMING_CALL
  4. Client B sends CALL_ACCEPT with an SDP answer
  5. Server forwards the answer to Client A as CALL_ACCEPTED
  6. Both clients exchange ICE_CANDIDATE messages via the server
  7. WebRTC peer-to-peer connection is established — media flows directly
  8. Either client sends CALL_END to terminate the call
Message Types

Client → Server Messages

These message types are sent from the client application to the signaling server.

Type Description Payload
REGISTER Register client ID with server { "clientId": "abc123" }
CALL_INITIATE Start a call to another client { "targetId": "xyz789", "sdpOffer": "..." }
CALL_ACCEPT Accept an incoming call { "callId": "...", "sdpAnswer": "..." }
CALL_REJECT Reject an incoming call { "callId": "..." }
CALL_END End an active call { "callId": "..." }
ICE_CANDIDATE ICE candidate for NAT traversal { "callId": "...", "candidate": "..." }
PKD_REGISTER Register public key in directory { "clientId": "...", "publicKey": "..." }
PKD_LOOKUP Look up a client's public key { "clientId": "..." }

Server → Client Messages

These message types are sent from the signaling server to client applications, either as responses to client requests or as notifications of events initiated by other clients.

Type Description Payload
REGISTERED Registration confirmed { "clientId": "abc123" }
INCOMING_CALL Incoming call notification { "callId": "...", "callerId": "...", "sdpOffer": "..." }
CALL_ACCEPTED Call was accepted by peer { "callId": "...", "sdpAnswer": "..." }
CALL_REJECTED Call was rejected by peer { "callId": "..." }
CALL_ENDED Call ended by peer { "callId": "..." }
ICE_CANDIDATE ICE candidate from peer { "callId": "...", "candidate": "..." }
PKD_RESULT Public key lookup result { "clientId": "...", "publicKey": "..." }
ERROR Error message { "code": "...", "message": "..." }

Error Codes

The ERROR message type includes a code field that indicates the specific error condition:

Connection Limits

Server Parameters

The signaling server enforces the following limits to prevent abuse and ensure stability. Clients that exceed these limits may have their connections terminated or receive ERROR messages with the RATE_LIMITED code.

Parameter Value
Max payload size 64 KB
Max connections per IP Rate-limited (enforced by server)
Heartbeat interval 30 seconds
Connection timeout 60 seconds (no heartbeat)
Client ID format ^[a-zA-Z0-9_-]{1,64}$
Heartbeat requirement: The Android client sends keepalive pings every 8 seconds (via HeartbeatClient) to maintain the connection. If the server does not receive any message for 60 seconds, it will close the WebSocket connection. The client implements exponential backoff reconnection (1s to 30s max) to handle disconnections gracefully.
TURN Credentials

Relay Authentication

TURN server credentials are provisioned by the signaling server during call setup. Rather than embedding static credentials in the client application, the server generates time-limited credentials using a shared secret with the TURN provider (Metered.ca).

This approach ensures that:

TURN Server Configuration

Parameter Value
Provider Metered.ca
Server turn:a.relay.metered.ca:443?transport=tcp
Transport TCP on port 443 (maximizes firewall compatibility)
Credential type Time-limited (HMAC-based)