API reference
Tunnels
Recording, countersigning and revoking a tunnel; the gateway search; one search across networks.
PIP-0018. The calls on a tunnel are made by the network's operator, with its credential. The federated search is made by any member.
POST /tunnels
Records a tunnel agreed with another network and signs it for this one. Both networks send the same
agreement; peer_kids are the keys the register lists for the other network.
{
"reference": "tnl_8f2k4m9q",
"networks": ["openconnect", "network-b"],
"gates": {
"openconnect": {
"inbound": { "identifier_types": ["alias", "phone"], "zones": ["+221"], "queries_per_day": 50000 },
"outbound": { "identifier_types": ["alias", "phone"] }
},
"network-b": {
"inbound": { "identifier_types": ["alias"] },
"outbound": { "identifier_types": ["alias", "phone"] }
}
},
"gateways": {
"openconnect": "https://gw.openconnect.example/api/path/v1",
"network-b": "https://gw.network-b.example/api/path/v1"
},
"disputes": { "rulebook": "network-b" },
"effective_at": "2026-11-01T00:00:00Z",
"expires_at": "2027-11-01T00:00:00Z",
"peer_kids": ["network-b_2026_01"]
}The answer is the tunnel, pending, with this network's signature. Hand that signature to the
other network.
POST /tunnels/{reference}/signatures
The other network's signature over the same tunnel.
{ "kid": "network-b_2026_01", "signed_at": "2026-10-09T10:00:00Z", "protocol_version": "0.2.0", "signature": "…" }The key is read from the other network's domain — the origin of its gateway — at
/.well-known/path-keys, and must be in peer_kids. The tunnel becomes active.
POST /tunnels/{reference}/revoke
Revokes the tunnel at once and publishes a signed revocation. No body.
GET /tunnels
Public. The network's active and revoked tunnels, each with status and signatures.
PUT /tunnels/exclusion
{ "excluded": true }Keeps all of the calling member's subjects out of tunnels. Their entries then answer within the network only.
POST /tunnel/sonar
Called by the other network's gateway, signed with its key:
| Header | Value |
|---|---|
Path-Tunnel | The tunnel reference |
Path-Key-Id | A key listed for that network |
Path-Timestamp | RFC 3339, within five minutes |
Path-Signature | Ed25519 over <method>\n<path>\n<timestamp>\n<sha256 of body> |
{ "identifier_type": "phone", "identifier": "+221771234567", "nonce": "b1f7c2d9e4a6" }{
"kind": "tunnel_sonar_answer",
"tunnel": "tnl_8f2k4m9q",
"network": "openconnect",
"requester_network": "network-b",
"identifier_type": "phone",
"identifier_hash": "…",
"nonce": "b1f7c2d9e4a6",
"found": true,
"member": "member-a",
"endpoint": "https://api.member-a.example",
"protocol_version": "0.2.0",
"signed_at": "…",
"kid": "openconnect_2026_01",
"signature": "…"
}Only federated and public entries answer. Negatives are indistinguishable.
| Error | When |
|---|---|
403 path.tunnel.inactive | The tunnel is not in force |
403 path.tunnel.not_admitted | This network's inbound gate does not admit the search |
429 path.tunnel.budget_exhausted | The gate's inbound budget is used for the day |
401 path.tunnel.signature_invalid | The key is not listed, or the signature does not verify |
POST /sonar/federated
Requires a member credential. One search, in this network and through every tunnel whose gates admit it.
{ "identifier_type": "phone", "identifier": "+221771234567" }{
"nonce": "4c1e…",
"holders": [
{ "network": "openconnect", "member": "member-a", "endpoint": "https://api.member-a.example", "proof": { "…": "…" } },
{ "network": "network-b", "member": "member-x", "endpoint": "https://api.member-x.example", "proof": { "…": "…" } }
],
"unavailable": []
}holders lists every holder found, this network's first. Each proof is signed by the network that
holds the entry. unavailable names the networks that did not answer in time. Show the network with
each holder and let the payer choose; then call RESOLVER at the chosen holder.