/docs/registry-api
Registry API
Public read-only API for browsing the IICP node directory. No authentication required. Rate limit: 60 requests/minute per IP. Responses are cached for 60 seconds.
discover() does this for you. The full endpoint reference is below.GET/api/v1/registry/nodes
Returns a paginated list of heartbeating nodes the directory currently sees. Public routability, encryption readiness, backend readiness and health are separate fields. Only public fields are returned — no tokens, endpoints, or private identifiers.
Query parameters
| Parameter | Description |
|---|---|
| intent | Filter by intent URN (e.g. urn:iicp:intent:llm:chat:v1) |
| region | Filter by region slug (e.g. eu-central, us-east) |
| cip_enabled | 1 to return only CIP-worker nodes (allow_remote_inference=true); accepts 1 or 0 |
| page | Page number, starting at 1 (default: 1) |
| limit | Results per page, 1–100 (default: 20) |
Request
# All heartbeating nodes curl -sf 'https://iicp.network/api/v1/registry/nodes' # Filter: CIP workers in eu-central curl -sf 'https://iicp.network/api/v1/registry/nodes?region=eu-central&cip_enabled=1' # Filter: chat nodes, page 2 curl -sf 'https://iicp.network/api/v1/registry/nodes?intent=urn:iicp:intent:llm:chat:v1&page=2&limit=10'
Illustrative response 200
Example timestamps, counts and node values are representative. Fetch the endpoint for current mesh state.
{
"total": 5,
"page": 1,
"limit": 20,
"resilience": {
"visible_nodes_now": 5,
"public_routable_nodes_now": 5,
"heartbeating_nodes_now": 5,
"recovering_nodes_now": 0,
"relay_available_now": true,
"last_relay_seen_at": "2026-07-12T10:00:00+00:00",
"recovery_window": false
},
"nodes": [
{
"node_id_prefix": "b33d00e5",
"region": "eu-central",
"active": true,
"reputation_score": 0.54,
"reputation_tier": "silver",
"probation": true,
"intents": ["urn:iicp:intent:llm:chat:v1"],
"models": ["qwen2.5-coder-14b-instruct-mlx"],
"backend": "lmstudio",
"last_seen": "2026-06-25T16:31:34+00:00",
"credit_cost_multiplier": 1.0,
"pricing_model": "per_token",
"attested": false,
"cip_enabled": true,
"public_listing": true,
"routing_hint": "https_direct",
"browser_usable": true,
"recovery_state": "stable",
"route_recovery_hint": "none",
"performance": {
"task_latency_ms": 120,
"task_latency_ms_basis": "proxy_observed_task",
"health_impact": "separate_from_operational_health"
},
"sdk_status": "current",
"upgrade_required": false,
"key_ready": true,
"backend_stability": {
"backend_state": "ok",
"reason_class": "ok",
"routing_guard": "none",
"evidence": "self_reported"
},
"auto_update": {
"enabled": true,
"interval_s": 3600,
"latest_seen": "0.7.102",
"evidence": "self_reported"
},
"status_summary": {
"state": "ready",
"headline": "Routable, key-ready, and currently healthy.",
"public_routable": true,
"key_ready": true,
"client_current": true,
"recovery_state": "stable",
"route_recovery_hint": "none"
}
}
]
}GET /api/v1/discover?view=public&intent=….resilience block summarizes visible, heartbeating, recent/recovering nodes and relay availability. Per-node recovery_state and route_recovery_hint explain whether a node is stable, rebuilding a tunnel/relay route, cooling down after a failed route, or unavailable. Dashboards should present that as temporary recovery evidence, not as a trust score.GET/api/v1/registry/nodes/{prefix}
Returns the public profile for a specific node. The prefix is the value from the node_id_prefix field in the nodes list — an 8-character hex prefix for UUID node IDs, or the full operator-chosen name (alphanumeric, ≤ 36 chars) for custom node IDs.
curl -sf 'https://iicp.network/api/v1/registry/nodes/550e8400'
This is a representative public profile shape, not a live node record.
{
"node_id_prefix": "b33d00e5",
"region": "eu-central",
"active": true,
"last_seen": "2026-06-25T16:31:34+00:00",
"reputation_score": 0.54,
"reputation_tier": "silver",
"probation": true,
"completed_tasks": 247,
"observed_latency_ms": 120,
"performance": {
"task_latency_ms": 120,
"task_latency_ms_basis": "proxy_observed_task",
"health_impact": "separate_from_operational_health",
"summary": "Task/inference latency is a performance signal, not a reachability-health input."
},
"health": {
"score": 89,
"label": "healthy",
"observed": true,
"confidence": "high",
"components": {
"liveness": 1,
"reachability": 1,
"latency": 0.633,
"uptime": 0.475,
"stability": 0.293,
"freshness": 1
}
},
"directory_observed_reachable": true,
"routing_hint": "https_direct",
"browser_usable": true,
"recovery_state": "stable",
"route_recovery_hint": "none",
"backend_stability": {
"backend_state": "degraded",
"reason_class": "backend_cold",
"routing_guard": "observe_only",
"evidence": "self_reported",
"summary": "Backend is reachable but cold; first request may warm it up."
},
"transport": ["https", "iicp-native"],
"intents": ["urn:iicp:intent:llm:chat:v1"],
"models": ["qwen2.5-coder-14b-instruct-mlx"],
"backend": "lmstudio",
"credit_cost_multiplier": 1.0,
"pricing_model": "per_token",
"attested": false,
"cip_enabled": true,
"sdk_language": "rust",
"implementation_name": "iicp-node",
"implementation_version": "0.7.102",
"sdk_compatibility_version": "0.7.102",
"sdk_version": "0.7.102",
"sdk_status": "current",
"upgrade_required": false,
"key_ready": true,
"auto_update": {
"enabled": true,
"interval_s": 3600,
"latest_seen": "0.7.102",
"evidence": "self_reported"
},
"public_listing": true,
"operator_url": "https://example.com",
"uptime_history": [
{ "date": "2026-06-25", "uptime_pct": 99.7, "evidence": "heartbeat_samples" }
],
"latency_percentiles": { "p50_ms": 120, "p95_ms": 310, "sample_count": 42 }
}backend_stability is backward-compatible; explicit draining is the only state clients should treat as a hard admission guard.performance.task_latency_ms describes recent task/inference speed. The health block describes operational reachability and uses directory-observed route latency when available; slow model generation should not by itself make a reachable node look network-degraded.| Error | HTTP | Cause |
|---|---|---|
| REGISTRY-INVALID-PREFIX | 422 | Prefix is not alphanumeric, or exceeds 36 characters |
| REGISTRY-NODE-NOT-FOUND | 404 | No visible node matches this prefix |
GET/api/v1/registry/intents
Returns all intent URNs currently advertised by heartbeating nodes, with live node counts.
curl -sf 'https://iicp.network/api/v1/registry/intents'
{
"intents": [
{
"intent": "urn:iicp:intent:llm:chat:v1",
"node_count": 8
}
]
}GET/api/v1/registry/stats
Summary statistics for the registry: total nodes, heartbeating nodes, region breakdown.
curl -sf 'https://iicp.network/api/v1/registry/stats'
Registry vs. Discover — which to use?
| Endpoint | Use when |
|---|---|
| /registry/nodes | Browsing the directory, building dashboards, counting nodes by region — public, no auth, returns partial IDs only |
| /v1/discover | Dispatching tasks — default view returns full node_id + endpoint + scoring fields needed by the proxy to route; requires intent param |
| /v1/discover?view=public | Inspecting scored candidates without route URLs — returns node prefixes, health, trust and capability clues only |
Discover-only fields. Beyond the public registry fields, each node in a /v1/discover response also carries:
reachability_tier—direct(dial-back-verified) orrelay(heartbeating with a routable surface, reached via relay — e.g. CGNAT/IPv6 nodes). Both tiers are returned by default; clients preferdirectand fall back torelay.input_modalities— the union of accepted chat input modalities for the queried intent (e.g.["text","image"]for a vision node,["text","audio"]for an audio node). Defaults to["text"].- Filter by modality with
?modality=image(oraudio/video) to return only nodes whose capability for that intent accepts the modality:/v1/discover?view=public&intent=urn:iicp:intent:llm:chat:v1&modality=image.