API Reference
bilbycast-relay exposes a small REST API on port 4480 (default) for health checks, Prometheus scraping, and tunnel introspection. The API is read-only — operational changes (authorize_tunnel, revoke_tunnel, disconnect_edge) flow through the manager’s WebSocket protocol, not REST.
Authentication
Section titled “Authentication”Set api_token in relay.json to require Bearer auth. The token must be 32–128 characters:
{ "quic_addr": "0.0.0.0:4433", "api_addr": "0.0.0.0:4480", "api_token": "<32-128 chars>"}When api_token is configured, every endpoint except /health requires:
Authorization: Bearer <token>When unset, every endpoint is open. The relay does constant-time comparison so an invalid token can’t be discovered by timing the 401 response.
Endpoints
Section titled “Endpoints”GET /health (public)
Section titled “GET /health (public)”Always reachable, even when api_token is set. Used by load balancers, the manager’s reachability probe, and your own monitoring.
curl http://relay-host:4480/health{ "status": "ok", "version": "0.x.y", "uptime_secs": 12345, "connected_edges": 4, "total_tunnels": 7, "active_tunnels": 5}A tunnel is active when both legs (ingress + egress) are bound. Total counts include tunnels in the half-bound TunnelWaiting state.
GET /metrics
Section titled “GET /metrics”Prometheus exposition format. Auth-gated when api_token is set.
curl -H "Authorization: Bearer <token>" \ http://relay-host:4480/metricsUseful series:
bilbycast_relay_uptime_secondsbilbycast_relay_connected_edgesbilbycast_relay_active_tunnels/bilbycast_relay_total_tunnelsbilbycast_relay_bytes_ingress_total/bilbycast_relay_bytes_egress_totalbilbycast_relay_bandwidth_bpsbilbycast_relay_peak_tunnels/bilbycast_relay_peak_edges
Pair with the Stats reference for the full series catalogue.
GET /api/v1/stats
Section titled “GET /api/v1/stats”Aggregate relay-wide stats. Auth-gated.
curl -H "Authorization: Bearer <token>" \ http://relay-host:4480/api/v1/stats{ "uptime_secs": 12345, "connected_edges": 4, "total_tunnels": 7, "active_tunnels": 5, "total_bytes_ingress": 1234567890, "total_bytes_egress": 1234567890, "total_bytes_forwarded": 2469135780, "total_bandwidth_bps": 50000000, "total_tcp_streams": 14, "active_tcp_streams": 6, "total_udp_datagrams": 9876543, "peak_tunnels": 12, "peak_edges": 9, "connections_total": 87}total_bandwidth_bps is computed across the most recent reporting window — it’s the live throughput, not a lifetime average.
GET /api/v1/tunnels
Section titled “GET /api/v1/tunnels”Per-tunnel state. Auth-gated.
curl -H "Authorization: Bearer <token>" \ http://relay-host:4480/api/v1/tunnels{ "tunnels": [ { "tunnel_id": "550e8400-e29b-41d4-a716-446655440000", "state": "active", "ingress_edge_id": "edge-syd-1", "egress_edge_id": "edge-perth-1", "bytes_ingress": 1234567, "bytes_egress": 1234567, "tcp_streams_total": 4, "tcp_streams_active": 2, "udp_datagrams_total": 5678 } ]}state is one of waiting (only one leg bound), active (both legs bound), or unbinding (transition state).
GET /api/v1/edges
Section titled “GET /api/v1/edges”Connected edge nodes. Auth-gated.
curl -H "Authorization: Bearer <token>" \ http://relay-host:4480/api/v1/edges{ "edges": [ { "edge_id": "edge-syd-1", "remote_addr": "203.0.113.10:53219" } ]}edge_id is whatever the edge sent in its optional Identify { edge_id } message — typically the manager node_id so the manager can correlate topology. If the edge never sent Identify, the relay synthesises a connection_id from the remote address plus a counter.
Tunnel authorisation (manager-driven)
Section titled “Tunnel authorisation (manager-driven)”Per-tunnel HMAC-SHA256 bind authentication is managed by bilbycast-manager through its WebSocket protocol — not via REST. The manager pre-registers expected ingress + egress bind tokens on the relay using authorize_tunnel, and revokes them with revoke_tunnel. When relay.json sets require_bind_auth: true, every TunnelBind from an edge must include a matching bind_token or the relay rejects the bind with TunnelDown { reason: "bind authentication failed" }.
This is the mechanism the manager uses to ensure that only the two edges it pairs end up sharing a tunnel. The relay holds no operator-supplied state for this — it just maintains a DashMap of pre-registered tokens that the manager refreshes.
For the operator-visible side of this — how the manager authors tunnels and which UI surfaces the per-tunnel auth state — see IP tunneling.
Limits
Section titled “Limits”- Bearer tokens: 32–128 characters.
- QUIC control messages: max 1 MB per message.
- Per-connection: 1024 bidirectional QUIC streams, 256 unidirectional, 15 s keep-alive.
- UDP datagram buffers: 2 MB send + 2 MB receive (sized for SRT at 10 Mbps in flight).
Where to read next
Section titled “Where to read next”- Install the relay — download, configure, and run.
- Architecture — internal design and stateless forwarding.
- Security & authentication — bind tokens, ChaCha20-Poly1305 end-to-end encryption.
- Stats reference — Prometheus metrics catalogue.
- Events & alarms — operational events the relay emits to the manager.