Complete Guide to iroh RPC API Endpoints: Binary QUIC Protocol Reference

TLDR: iroh does not expose traditional HTTP REST or JSON-RPC interfaces; instead, the public relay service communicates via a binary QUIC-based protocol featuring six core message types—Connect, Announce, Lookup, Ping, StreamOpen, and Close—implemented in the iroh-relay crate and defined in noq-proto.

The n0-computer/iroh project implements a peer-to-peer networking stack that replaces conventional HTTP APIs with a high-performance binary protocol. Understanding the iroh RPC API endpoints requires examining how clients and relay servers exchange protobuf-encoded messages over QUIC connections rather than traditional REST paths.

Protocol Architecture: Binary QUIC vs. HTTP REST

Unlike typical cloud services that expose /api/v1/ HTTP endpoints, iroh utilizes a binary protocol transported over QUIC. When a client connects to a relay, it performs a short handshake and exchanges binary-encoded messages defined by the noq-proto crate. These messages function as the functional RPC endpoints, carrying commands and data without HTTP overhead.

Because the transport is multiplexed on a single QUIC connection, a single logical endpoint can carry many streams—such as data channels and control channels—without requiring separate HTTP URLs.

The Six Core iroh RPC API Endpoints

The protocol defines six primary message types that serve as the API surface between clients and the relay server.

Connect (Client → Relay)

Opens a QUIC connection and negotiates the application-layer protocol (ALPN). This is the initial handshake that establishes the secure channel for subsequent RPC messages.

Announce (Client → Relay)

Publishes the client’s public key (EndpointId) to the relay’s internal registry. This endpoint enables peer discovery by mapping EndpointIds to their current network addresses.

Lookup (Client → Relay)

Queries the relay for the current network address(es) associated with a specific EndpointId. This powers the peer resolution mechanism, returning RelayUrl mappings stored by previous Announce calls.

Ping (Client ↔ Relay)

Maintains connection liveness and measures round-trip latency. Bidirectional by design, this endpoint keeps NAT mappings open and provides health metrics.

StreamOpen (Client ↔ Relay)

Creates a bidirectional QUIC stream for data transfer after the initial handshake. This endpoint multiplexes multiple logical channels over the single QUIC connection.

Close (Client → Relay)

Gracefully terminates the connection, signaling the relay to release associated resources and remove temporary routing entries.

Source Code Implementation

The logic handling these endpoints spans several key files in the n0-computer/iroh repository:

  • iroh-relay/src/main.rs: Implements the relay server, parsing the binary protocol and dispatching each request type to appropriate handlers. The server routes Announce requests to update internal EndpointId-to-RelayUrl mappings and processes Lookup requests to return current address lists.
  • noq-proto/src/lib.rs: Contains the protobuf definitions for the binary message structs (Connect, Announce, Lookup, Ping, StreamOpen, Close). These definitions establish the wire format for all RPC communication.
  • iroh/src/lib.rs: Provides the core client implementation, including methods to build QUIC connections and transmit RPC messages. This file contains the client-side logic for connect(), announce(), and lookup() operations.
  • iroh-base/src/relay_url.rs: Defines the RelayUrl type that clients use to specify relay server addresses and that the Lookup endpoint returns in its responses.

Practical Code Examples

The following examples demonstrate how to interact with the iroh RPC API endpoints using the official Rust client library.

Connecting to a Relay and Announcing

use iroh::client::{Client, Config};
use iroh_base::EndpointId;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Load a configuration that contains the relay URL.
    let cfg = Config::load("example.config.toml")?;
    let client = Client::new(cfg).await?;

    // Connect to the relay (QUIC handshake happens under the hood).
    client.connect().await?;

    // Announce our public key so others can find us.
    client.announce().await?;

    // (optional) keep the connection alive.
    client.ping().await?;

    Ok(())
}

Looking Up a Remote Peer

use iroh::client::Client;
use iroh_base::EndpointId;

async fn resolve_peer(client: &Client, id: EndpointId) -> anyhow::Result<Vec<String>> {
    // Ask the relay for the current network addresses of `id`.
    let addrs = client.lookup(id).await?;
    Ok(addrs)
}

Server-Side Request Handling

use iroh_relay::server::Server;
use iroh_relay::protocol::{Request, Response};

async fn run_server() -> anyhow::Result<()> {
    let server = Server::bind("0.0.0.0:443").await?;
    while let Some(conn) = server.accept().await {
        tokio::spawn(async move {
            while let Some(req) = conn.next_request().await {
                match req {
                    Request::Announce { endpoint_id, .. } => {
                        // Store the mapping.
                        server.register(endpoint_id).await;
                        conn.respond(Response::Ok).await?;
                    }
                    Request::Lookup { endpoint_id } => {
                        let addrs = server.lookup(endpoint_id).await;
                        conn.respond(Response::LookupResult { addrs }).await?;
                    }
                    // …other request variants…
                    _ => {}
                }
            }
        });
    }
    Ok(())
}

Summary

  • iroh implements iroh RPC API endpoints as binary protobuf messages over QUIC, not HTTP REST.
  • The six core message types are Connect, Announce, Lookup, Ping, StreamOpen, and Close.
  • Client logic resides in iroh/src/lib.rs, while the relay server implementation lives in iroh-relay/src/main.rs.
  • Message definitions are located in noq-proto/src/lib.rs, establishing the wire format for all communication.
  • All endpoints are accessed through the Rust client library rather than raw HTTP requests.

Frequently Asked Questions

Does iroh expose HTTP REST API endpoints?

No. According to the source code in iroh-relay/src/main.rs, iroh uses a binary QUIC-based protocol defined in noq-proto. There are no HTTP paths like /api/v1/announce; instead, clients send protobuf-encoded messages over established QUIC connections.

How do I discover peer addresses using the iroh RPC API?

Use the Lookup endpoint. As implemented in the relay server, you call client.lookup(endpoint_id).await from iroh/src/lib.rs, which queries the internal mapping updated by Announce requests and returns a list of current network addresses.

What crate contains the protocol definitions for iroh RPC endpoints?

The noq-proto crate contains the protobuf definitions. The file noq-proto/src/lib.rs defines the binary structs for Connect, Announce, Lookup, Ping, StreamOpen, and Close messages that function as the API surface.

Can I use curl or standard HTTP clients to call iroh RPC endpoints?

No. Because the protocol uses binary-encoded protobuf messages over QUIC rather than HTTP/1.1 or HTTP/2, you must use the iroh client library (or implement the binary protocol yourself). The connection requires QUIC handshake and ALPN negotiation as seen in iroh/src/lib.rs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →