Operator API

URnetwork API: Network

Version 2026.9.14 · 187 operations across 14 groups.OpenAPI spec ↗

URnetwork implements the UR protocol operator spec in full. UR protocol ↗

Network

36 operations
POST/network/auth-clientBearer authauthNetworkClient

Gain permission to use the connect protocol as the requested clientId, or assign a new clientId.

When the deployment enforces concurrent clients, a network is limited to 100 TOP-LEVEL clients (clients with no source_client_id, which are the network's peers); ancillary clients are not counted. Over the limit the call answers 200 with error.upgrade_required -- a plan limit, not a hard cap -- and an agent can settle it inline with the x402 round trip below.

show schema
client_id
string

udid. Optional. If this is given, it must currently exist in the network. Omit this to assign a new client id.

source_client_id
string

udid. Optional. The source client id when creating an ancillary client id.

description
string

If this is a new device, sets the device name to the description of the device.

device_spec
string

If this is a new device, sets the device spec.

time_zone
string

Optional. The device's IANA time zone (e.g. America/Chicago), used only to place the onboarding campaign's emails in the user's local day (08:00-21:00 local); never stored on the client. Every app sends it on each auth-client call; the latest wins.

locale
string

Optional. The device's BCP 47 locale ("de-DE"). Selects the onboarding campaign's template language, falling back to English. Same rules as time_zone.

roles
array<string>

Optional. Identity roles assigned to the client at creation, immutable after. Only a network session may set these; when omitted, the session's own roles are inherited. The values have no meaning to the network.

array
string
principal
string

Optional. Identity principal assigned to the client at creation, immutable after. Only a network session may set this; when omitted, the session's own principal is inherited.

proxy_config
object

Optional. Set if the intended use case of the client is cloud proxy. Note local traffic is not allowed on the cloud proxy. A destination must be set via the SDK.

lock_caller_ip
boolean

Optional. Allow only the caller's IP subnet to access the proxy.

lock_ip_list
array<string>

Optional. Allow only IPs/subnets in the list to access the proxy. The IPs/subnets are converted to the internal IP subnet width.

array
string
https_require_auth
boolean

Optional. If the client supports ECH, this is not needed, since the HTTP proxy URL will itself be the auth.

enable_wg
boolean

Optional. If enabled, a WireGuard configuration will be created for the proxy.

initial_device_state
object

Optional. Whenever the device is created, it will be set up with this initial state. To configure the device beyond the initial state, the SDK ProxyDevice must be used. Note that the SDK ProxyDevice must reconfigure the device each time it receives a change notice.

country_code
string

Optional. Use one of country_code or location

location
object

Optional. Use one of country_code or location

connect_location_id
object
client_id
string

udid. Optional.

location_id
string

udid. Optional.

location_group_id
string

udid. Optional.

best_available
boolean

udid. Optional.

name
string
location_type
one of
one of
value
value
value
provider_count
integer
promoted
boolean
match_distance
integer
city
string
region
string
country
string
country_code
string
city_location_id
string

udid. Optional.

region_location_id
string

udid. Optional.

country_location_id
string

udid. Optional.

stable
boolean
strong_privacy
boolean
network_peer
boolean

Marks the location as one of the network's own trusted peers, which egresses under ProvideModeNetwork. It is explicit state: a fixed client id alone does not imply a trusted peer, since it can be a public exit.

performance_profile
object
allow_direct
boolean

Setting this exposes the real source IP to the provider.

post_quantum_encryption
boolean

Opportunistic post-quantum end-to-end encryption to providers that support it; providers without support fall back to plaintext at this layer.

window_type
one of

Optional. The default is "quality"

one of
value
value
window_size
object
window_size_min
integer
window_size_min_p2p_only
integer

The minimumum number of items in the windows that must be connected via p2p only. Leave 0 for default behavior.

window_size_max
integer

Inclusive, soft limit. When window_size_max==window_size_min, a special fixed size mode is enabled.

window_size_hard_max
integer

Leave 0 to disable (no hard limit)

window_size_reconnect_scale
number

Clients per source per stream

keep_healthiest_count
integer

Leave 0 to disable

ulimit
integer

Leave 0 to disable (no limit)

dns_resolver_settings
object

Optional. How the proxy device resolves DNS. DoH urls are queried as RFC 8484 wire format, and each must present an IP-SAN certificate when addressed by IP.

enable_remote_doh
boolean
enable_local_doh
boolean
enable_remote_dns
boolean
enable_local_dns
boolean
dns_upgrade_mask_address
string

A stand-in destination for the platform's plain DNS configuration while the upgrade mux intercepts UDP/TCP :53. It is not an upstream resolver.

remote_doh_urls_ipv4
array<string>
array
string
remote_doh_urls_ipv6
array<string>
array
string
local_doh_urls_ipv4
array<string>
array
string
local_doh_urls_ipv6
array<string>
array
string
remote_dns_ipv4
array<string>
array
string
remote_dns_ipv6
array<string>
array
string
local_dns_ipv4
array<string>
array
string
local_dns_ipv6
array<string>
array
string
2 statuses · show schema
200
by_client_jwt
string
client_id
string

udid

proxy_config_result
all of

The following proxy URLs and auths may be used:

URLAuth
https://.:no auth needed when the client connects with TLS
https://:use HTTP Proxy-Authorization Basic with access_token as the username (empty pass), or Bearer with access_token as the bearer token
http://:use HTTP Proxy-Authorization Basic with access_token as the username (empty pass), or Bearer with access_token as the bearer token
tcp://:use access_token as the username (empty pass)
wg://:use wg_config.config as the full WireGuard config file content, which contains all the necessary keys
keepalive_seconds
integer

The proxy url will be valid until the client is removed. However, to keep the device and state in memory, the proxy must receive a message at least once per this interval. The SDK ProxyDevice will automatically send a heartbeat with this many seconds. If the proxy is removed from memmory, the next call to the proxy will create a new device set up to the initial_device_state (if present).

change_id
integer
create_time
string

datetime

proxy_id
string

udid

client_id
string

udid

api_base_url
string
block
string
api_port
integer
http_proxy_url
string
https_proxy_url
string
socks_proxy_url
string
auth_token
string
instance_id
string

udid. The instance_id of the proxy device.

proxy_host
string
socks_proxy_port
integer
http_proxy_port
integer
https_proxy_port
integer
wg_config
objectnull
wg_proxy_port
integer
client_private_key
string
client_public_key
string
client_ipv4
string
proxy_public_key
string
config
string

The WireGuard config file for this client.

error
object
client_limit_exceeded
boolean

A hard cap or a rate limit was hit.

upgrade_required
boolean

The network is at its plan's limit for concurrent connected top-level clients. Unlike client_limit_exceeded this is a plan limit, not a hard cap: surface an upgrade prompt. It is the flag the x402 inline-payment round trip keys off.

message
string
401
No body
POST/network/remove-clientBearer authRemove Network Client

Remove a client from the network.

show schema
client_id
string

udid

1 status · show schema
200
error
object
message
string
POST/network/remove-clientsBearer authRemove Network Clients

Remove many clients from the caller's network in one call, so a network with hundreds of thousands of offline clients can be cleared without the caller chunking the request. Duplicate ids are collapsed; at most 1,000,000 ids per call (more is an error), and the body is capped at 100 MB.

A small request (at most 10,000 ids) runs synchronously when the deployment's hourly bulk-removal budget has room right now, and the result is empty. Anything else is handed to a background task and the result says so: scheduled with scheduled_for naming the hourly bucket it was reserved against (the present moment when this hour had room, a future hour when it did not). The work is NOT complete when scheduled is true.

Two refusals leave the ids unscheduled and ask the caller to retry: already_in_progress when this network already has a background run going, and too_many_concurrent_runs when the deployment-wide cap on concurrent runs is reached.

show schema
client_ids
array<string>

udids. Duplicates are collapsed; at most 1,000,000 per call.

array
string
1 status · show schema
200
scheduled
boolean

Handed off to the background task; deactivation is NOT complete yet.

scheduled_for
string (date-time)

The start of the hourly bucket the request was reserved against; present whenever scheduled is true. Now (or a moment before) when this hour had room, a future time when it did not.

already_in_progress
boolean

This network already has a background run going; the ids were NOT scheduled.

too_many_concurrent_runs
boolean

The deployment-wide cap on concurrent runs was reached; the ids were NOT scheduled.

POST/network/extender-activateBearer authExtender Activate

Offer the calling client as an extender and, if it proves out, publish it in the directory (connect/EXTENDER.md C2).

Requires a CLIENT jwt (from /network/auth-client): the activation is attributed to a network and a client, and is rate limited per user (6 per hour). Call it on the family api host of the family being activated -- api-v4.bringyour.com for an IPv4 address, api-v6.bringyour.com for an IPv6 one -- so the caller address the operator probes back has exactly one family. An operator without family hosts (a development operator on an ip literal, say) is activated through its plain api url instead, and the family of the outcome is the one the result reports. NEVER call it through an extender: the address that is probed and published is the address this request arrived from.

Nothing is taken on the caller's word. Inside the request, and within a 10 second budget, the operator dials BACK to the caller's own address on every carrier offered and on every dns port listed, each time sending a challenge and verifying the response signature against public_key_hex; it then performs a verified GET /hello forward through the tcp carrier to its own api. The tcp carrier is therefore required, since only it can prove the forward. One dns port failing is not the dns carrier failing -- only a dns carrier with no port left is refused -- and the forward must arrive on the same family the probe reached, or the record would promise an address that does not carry the traffic.

A refusal is a NORMAL 200 with activated: false and error naming the carrier that failed, not an HTTP error: the caller is a provider running this on a timer, and it needs to tell "this carrier did not answer" from "the request was malformed". Nothing is stored on a refusal.

On success the extender row and the family's address row are upserted active and a record publish row is queued for gossip. The answer carries the extender's own freshly signed record and up to 8 signed records of other active extenders, which is the only bootstrap an app has before it has any peer.

show schema
public_key_hex
string

The extender's identity public key, hex. Every probe requires a signature over a fresh challenge under this key.

tcp_port
integer

The tcp carrier port. 0 takes the default, 443.

udp_port
integer

The quic carrier port. 0 takes the default, 443.

dns_port
integer

The extender's configured dns port, which is what a reader that predates dns_ports dials. 0 takes the default whodis port.

dns_ports
array<integer>

Every dns port the caller is listening on, each probed on its own. Empty offers dns_port alone. One port failing does not fail the dns carrier; only a carrier with no port left is refused.

array
integer
dns_tld
string

The dns carrier's tld. Empty takes the default; at most 128 characters.

carriers
array<string>

The carriers offered, lower-cased and de-duplicated: tcp, quic and dns. At least one is required, and tcp is always required because only it can prove the forward. An unknown carrier is refused.

array
string
enum: tcp, quic, dns
2 statuses · show schema
200
activated
boolean
ip
string

The caller address that was probed and published.

ip_version
integer

4 or 6. The forward must arrive on this same family.

carriers
array<string>

The carriers that passed their probe, which is what the stored address and the signed record list.

array
string
dns_ports
array<integer>

The dns ports that passed their probe, ascending, which is what the stored address and the signed record list. Empty when the dns carrier was not offered.

array
integer
error
string

Why the activation was refused; empty on success. A refusal is a normal answer, not a request error: the caller is told which carrier failed so it can fix its own binding.

expire_time
string (date-time)

When the signed record expires, 24 hours from issue. The operator re-releases every active extender's record within 12 hours (connect/GEOMAP.md §2.8).

allowed_hosts
array<string>

The operator host patterns this extender may forward to.

array
string
record
string

base64 of the extender's own serialized protocol.ExtenderRecord.

bootstrap
array<string>

base64 serialized protocol.ExtenderRecord messages of up to 8 other active extenders, chosen at random -- the directory an app starts from before it has any peer.

array
string
401
No body
GET/network/extender-hintPublicExtender Hint

The continent the operator places the caller's address on (connect/DESIGNNOTES4.md §4), upper case, from the same mapping the extender geo dns and the continent_code tag on signed extender records use -- so a client can order the records it holds by "on my continent" before it has measured anything.

No credential. The answer is derived from the address this request arrived from, which the operator sees on every request anyway, and a client needs it before it has logged in. NEVER call it through an extender: the address placed is the address the request arrived from. An empty continent_code is an address the operator cannot place, which a client treats as no hint rather than as a continent.

1 status · show schema
200
continent_code
string

The continent of the caller's address, upper case: one of AF, AN, AS, EU, NA, OC, SA. Empty when the operator cannot place the caller.

POST/network/extender-latencyBearer authExtender Latency Report

Forward the latency attestations providers made to this client's extenders (connect/DESIGNNOTES4.md §3). Accepted for one release for extenders on the previous binary, and superseded by /network/ping-report, where the pinger reports its own pings with the target's co-signature (connect/GEOMAP.md D14).

A provider that probes an extender puts its client id in the probe; the extender answers with a fresh nonce; the provider sends back its measured round trip under its own client key signature, over the nonce, the extender's identity key, its client id and a timestamp. The extender forwards the claim only when it is no lower than the interval the extender itself observed between its response and the provider's frame, less a tolerance -- so the provider cannot claim to be closer than it was seen to be, and the extender cannot change what the provider signed. Only a provider attests; a consumer client probes without identifying itself.

Requires a CLIENT jwt: every attestation must name, by identity key, an extender the calling client activated, and the report is rate limited per user (240 per hour). The operator verifies each attestation's signature against the provider's registered client key and stores what verifies. An attestation that does not decode, does not verify, names an extender the caller does not own, names the extender's own client as the provider, carries a timestamp more than a day from the operator's clock or a round trip no column can hold, or repeats one already stored (same extender, provider and nonce) is counted in rejected and not named. A report of more than 256 attestations is refused whole.

show schema
attestations
array<ExtenderLatencyAttestation>

At most 256.

array
client_id
string

The provider's client id.

extender_public_key_hex
string

The identity key of the extender the round trip was measured to, hex.

probe_nonce
string

The 32 byte nonce the extender issued for this probe, base64.

rtt_ms
integer

The provider's measured round trip, whole milliseconds rounded up.

timestamp_ms
integer

The provider's clock when it signed, unix milliseconds.

signature
string

The provider's ed25519 signature, base64.

2 statuses · show schema
200
accepted
integer

Attestations that verified and were stored.

rejected
integer

Attestations that did not decode, did not verify, named an extender the caller does not own or its own client as the provider, were out of the time window or unstorable, or repeated one already stored.

error
string

Why the report was refused whole; empty otherwise.

401
No body
POST/network/ping-reportBearer authextenderPingReport

Report the pings this client measured of extenders, and what each target answered (connect/GEOMAP.md §2.5). The PINGER reports: a provider over its client credential, an extender over its activation credential. Both kinds share one report and one attestation, and sign under different domains (see ExtenderPing).

A probe that identifies its pinger is answered with a fresh nonce; the pinger sends back its measured round trip under its own signature; the target accepts the claim only when it is no lower than the interval it observed itself, less a tolerance, and answers every claim with one verdict: an acceptance carrying the target's co-signature over the exact claim, or a refusal with its reason. The pinger reports the claim and what became of it, whatever that was.

Requires a CLIENT jwt, and every ping must name the calling client as its pinger: a provider ping by the caller's client id, an extender ping by the identity key of an extender the caller activated. The target must be an extender the operator has activated, active or not, and not one the caller activated itself. The operator verifies the pinger's signature under the key it holds for the pinger -- the provider's registered client key, or the extender's stored identity key -- and RECOMPUTES the verdict under the target's stored identity key: a ping is stored as co-signed only when its co-signature verifies, whatever outcome says. A ping without a verifying co-signature is the pinger's claim only, never a measurement; at most 64 of them are accepted from one report and the rest are rejected. A ping that does not decode, names another pinger, names an unknown target or the caller's own, does not verify, carries a timestamp more than a day from the operator's clock, or repeats one already stored (same target, pinger and nonce) is counted in rejected and not named. A report of more than 256 pings is refused whole, and reports are rate limited per user (240 per hour).

show schema
pings
array<ExtenderPing>

At most 256.

array
pinger_kind
string

Who pinged.

enum: provider, extender
pinger_client_id
string

The provider's client id; empty for an extender pinger.

pinger_extender_public_key_hex
string

The pinging extender's identity key, hex; empty for a provider pinger.

target_extender_public_key_hex
string

The identity key, hex, of the extender the claim names: the one that judged and co-signed it, which for a probe relayed through an NLayer chain is the chain end.

probe_nonce
string

The 32 byte nonce the target issued for this probe, base64.

rtt_ms
integer

The pinger's measured round trip, whole milliseconds rounded up.

timestamp_ms
integer

The pinger's clock when it signed, unix milliseconds. It must be within a day of the operator's clock.

signature
string

The pinger's ed25519 signature over the claim, base64.

outcome
string

What the pinger recorded of the target's verdict. cosigned: the target accepted, and its co-signature verified under its key. rejected: the target refused, with reason -- or accepted with a co-signature that did not verify, which the pinger records as the refusal it amounts to. unknown: no verdict arrived (a close, a timeout, a target that predates the verdict), which is kept apart from a refusal so a flaky path is not read as a refusing extender. The operator recomputes the stored verdict from cosignature under the target's stored key and never trusts this field: a claimed cosigned whose co-signature does not verify is stored as rejected with reason 5.

enum: cosigned, rejected, unknown
reason
integer

The target's refusal reason, 0 without a verdict: 0 ok, 1 round trip below what the target observed, 2 nonce, 3 wrong extender, 4 unknown pinger, 5 bad signature, 6 rate limited.

cosignature
string

The target's co-signature, base64; empty unless cosigned.

hop_count
integer

The NLayer relays the probe crossed to reach the chain end the claim names, 0 for a direct ping (connect/GEOMAP.md §2.9); a relayed ping is stored and counted but is never a location measurement, since its round trip includes the detour through the front.

2 statuses · show schema
200
accepted
integer

Pings that verified and were stored, co-signed or not.

rejected
integer

Pings that did not decode, named another pinger, an unknown target or the caller's own, did not verify, were out of the time window or unstorable, were past the 64 uncosigned pings one report may carry, or repeated one already stored.

error
string

Why the report was refused whole; empty otherwise.

401
No body
GET/network/clientsBearer authNetwork Clients

Get the latest status of the network's devices: every top-level client (no sourceclientid) that is not a hosted proxy device, with no provide-mode qualification. Child clients are never listed, and neither are the network's cloud proxy devices (the "resident proxy" clients the proxy host runs), which /network/proxies lists instead.

Includes:

  • Resident status, which is the platform counterpart

for the client that handles control commands.

  • Connections, which are transports from the client to the platform.

Note there can be multiple active connections for a single client.

  • Provide status

proxy_client is never present on this list.

1 status · show schema
200
clients
array<object>
array
client_id
string

udid

source_client_id
string

udid

device_id
string

udid

network_id
string

udid

description
string
device_name
string
device_spec
string
create_time
string
auth_time
string
roles
array<string>

identity roles assigned at creation

array
string
principal
string

identity principal assigned at creation

provide_mode
ProvideMode
one of
value
value
value
value
value
value
proxy_client
ProxyClient
change_id
integer
create_time
string

datetime

proxy_id
string

udid

client_id
string

udid

api_base_url
string
block
string
api_port
integer
http_proxy_url
string
https_proxy_url
string
socks_proxy_url
string
auth_token
string
instance_id
string

udid. The instance_id of the proxy device.

proxy_host
string
socks_proxy_port
integer
http_proxy_port
integer
https_proxy_port
integer
wg_config
objectnull
wg_proxy_port
integer
client_private_key
string
client_public_key
string
client_ipv4
string
proxy_public_key
string
config
string

The WireGuard config file for this client.

connections
array<object>
array
client_id
string

udid

connection_id
string

udid

connect_time
string
disconnect_time
string
connection_host
string
connection_service
string
connection_block
string
GET/network/proxiesBearer authNetwork Proxies

The network's cloud proxy devices: the clients that carry a hosted proxy device (created with proxy_config on /network/auth-client), each with its proxy_client credentials (proxy URLs, auth token, WireGuard details). Same row shape as /network/clients otherwise: resident status, connections, provide status.

1 status · show schema
200
clients
array<object>
array
client_id
string

udid

source_client_id
string

udid

device_id
string

udid

network_id
string

udid

description
string
device_name
string
device_spec
string
create_time
string
auth_time
string
roles
array<string>

identity roles assigned at creation

array
string
principal
string

identity principal assigned at creation

provide_mode
ProvideMode
one of
value
value
value
value
value
value
proxy_client
ProxyClient
change_id
integer
create_time
string

datetime

proxy_id
string

udid

client_id
string

udid

api_base_url
string
block
string
api_port
integer
http_proxy_url
string
https_proxy_url
string
socks_proxy_url
string
auth_token
string
instance_id
string

udid. The instance_id of the proxy device.

proxy_host
string
socks_proxy_port
integer
http_proxy_port
integer
https_proxy_port
integer
wg_config
objectnull
wg_proxy_port
integer
client_private_key
string
client_public_key
string
client_ipv4
string
proxy_public_key
string
config
string

The WireGuard config file for this client.

connections
array<object>
array
client_id
string

udid

connection_id
string

udid

connect_time
string
disconnect_time
string
connection_host
string
connection_service
string
connection_block
string
GET/network/peersBearer authNetwork Peers

Fast network peer discovery.

Lists the currently connected network peers: the top-level clients of the network (clients with no sourceclientid) and their identity metadata (provide modes, principal, roles), plus disconnect markers for peers that disconnected within the recent window.

Allowed for network sessions and top-level client sessions. A client session's own client is excluded from the list.

1 status · show schema
200
peers
arraynull

connected peers

disconnected
array<NetworkPeer>

disconnect markers within the recent window

array
client_id
string

udid

provide_modes
array<ProvideMode>

the peer's enabled provide modes

array
one of
value
value
value
value
value
value
principal
string

identity principal assigned at creation

roles
array<string>

identity roles assigned at creation

array
string
device_name
string
device_spec
string
disconnect_time
string

set when the entry is a disconnect marker for a recently disconnected peer

disconnected_count
integer
error
object
message
string
GET/network/provider-locationsPublicNetwork Provider Locations

A list of locations and groups where there is at least one active provider in good health. Note that a location or group will need to be mapped to an actual provider using /network/find-providers2. groups carries the promoted location groups that apply to the caller; /network/find-provider-locations always returns it empty.

1 status · show schema
200
groups
array<object>
array
location_group_id
string

udid

name
string
provider_count
integer
promoted
boolean
match_distance
integer
locations
array<object>
array
location_id
string

udid

location_type
string
enum: city, region, country
name
string
city
string
city_location_id
string

udid

region
string
region_location_id
string

udid

country
string
country_location_id
string

udid

country_code
string
provider_count
integer
match_distance
integer
stable
boolean
strong_privacy
boolean
devices
array<object>
array
client_id
string

udid

device_name
string
country_count
integer
region_count
integer
city_count
integer
stable_count
integer
strong_privacy_count
integer
POST/network/find-provider-locationsPublicNetwork Find Provider Locations

Search for locations and groups that match a query, where there are at least one active provider in good health. The match algorithm accounts for typos and misspelling, and the tolerance can be tuned in the input. Note that a location or group will need to be mapped to an actual provider using /network/find-providers2.

show schema
query
string
max_distance_fraction
number
enable_max_distance_fraction
boolean
rank_mode
string

The bucket whose supply decides whether a location is listed as stable: quality, the default, or speed, as rank_mode of FindProviders2Args describes them.

1 status · show schema
200
groups
array<object>
array
location_group_id
string

udid

name
string
provider_count
integer
promoted
boolean
match_distance
integer
locations
array<object>
array
location_id
string

udid

location_type
string
enum: city, region, country
name
string
city
string
city_location_id
string

udid

region
string
region_location_id
string

udid

country
string
country_location_id
string

udid

country_code
string
provider_count
integer
match_distance
integer
stable
boolean
strong_privacy
boolean
devices
array<object>
array
client_id
string

udid

device_name
string
country_count
integer
region_count
integer
city_count
integer
stable_count
integer
strong_privacy_count
integer
POST/network/find-providers2PublicNetwork Find Providers 2

Randomly sample providers for locations, groups, or devices, which are active and in good health. This allows random iteration by using the exclude input to mark visited providers.

show schema
specs
array<ProviderSpec>
array
location_id
string

udid

location_group_id
string

udid

client_id
string

udid

best_available
boolean
count
integer
force_count
boolean
exclude_client_ids
array<string>
array
string

udid

exclude_destinations
array<array<string>>
array
array
string

udid

rank_mode
string

The bucket to draw from and rank in. Every bucket leaves out, always, a provider with a current blackhole verdict or a TLS-authentication failure, a provider named by client_id included, and, unless force_minimum is set, a provider a fresh egress probe observed exiting in a country other than the one it is listed in. quality, the default, is the probed providers whose latest egress health run passed at least nine in ten of its real-site loads, ordered by the egress index and then by latency and throughput. speed is every probed provider, whatever its probe found, ordered by latency and throughput alone. A bucket short of count is filled from the others: quality from the providers speed holds that it does not, speed from the quality providers its latency and throughput cutoffs excluded, and both last from the online bucket, which no request names: the unprobed providers that pass the reliability and performance minimums the other buckets apply, so a provider no client has measured is not among them. The borrowed rank behind every native provider through tier.

enum: quality, speed
force_minimum
boolean
ip_family
string

Filter providers by PROVEN address family. "" and v4-capable take dualstack providers first, then v4-only; v6-capable takes dualstack first, then v6-only; dualstack, v4-only and v6-only are the exact categories.

enum: , v4-capable, v6-capable, dualstack, v4-only, v6-only
1 status · show schema
200
providers
array<object>
array
client_id
string

udid

estimated_bytes_per_second
integer
has_estimated_bytes_per_second
boolean
tier
integer

The provider's band in the requested rank_mode, 0 best, one tier per 20 points of score. In quality the score is 20 times the egress index -- the real-site loads of the provider's latest health run that failed every retry, weighted and capped -- plus the latency and throughput adjustment; in speed it is the adjustment alone. A missing latency or throughput test costs two tiers. A provider of the requested bucket within its latency and throughput cutoffs carries 0 to 2, and 0 means nothing was found against it and it is fast. A provider borrowed from another bucket because the requested one came up short carries its tier there plus an offset, 11 by default and never under 3, and one borrowed from the online bucket twice the offset. The default leaves room for the largest demerit a client adds to a tier (7), so every native provider ranks ahead of every borrowed one, and every borrowed one ahead of the online bucket, however the client demerits them, and the borrowed keep their order; a tier has no upper bound and a larger one only ranks later. A provider named by client_id carries 0, since it bypasses discovery.

intermediary_ids
array<string>

Reserved for future multi-hop routes: the intermediaries to reach client_id through, in order. Find-providers never returns multi-hop routes today, so this is always absent.

array
string

udid

network_only
boolean

The provider carries traffic only for its own network.

reputation_failed_names
string

The joined destination names the provider's exit address failed the reputation class on. Reputation is not health -- nearly every honest hosted provider fails most of it.

ip_family
string

The provider's proven category: dualstack, v4-only or v6-only. Absent for a fixed client-id spec, which bypasses discovery.

location
ProviderLocation
country
string
country_code
string

lowercase iso 3166-1 alpha-2

region
string
city
string
country_location_id
string

udid

region_location_id
string

udid

city_location_id
string

udid

region_coordinates
LocationCoordinates
lat
number
lon
number
city_coordinates
LocationCoordinates
lat
number
lon
number
GET/network/rankingBearer authNetwork Get Ranking

Get leaderboard ranking of current network. Besides the data leaderboard rank, the result carries the network's points leaderboard settings (points_leaderboard_public, emoji_tag) and its points ranks (rank_points, rank_blocks, rank_streak; 0 until the network has points and a ranking snapshot exists).

1 status · show schema
200
network_ranking
NetworkRanking
net_mib_count
number (float)
leaderboard_rank
integer
leaderboard_public
boolean

Whether your network is publicly visibile on the leaderboard

points_leaderboard_public
boolean

Whether the network is listed on the points leaderboard

emoji_tag
string

The network's emoji tag (1 to 6 emoji), absent when unset

rank_points
integer (int64)

Competition rank by total points, 0 when unranked

rank_blocks
integer (int64)

Competition rank by finalized epochs with points, 0 when unranked

rank_streak
integer (int64)

Competition rank by current streak, 0 when unranked

error
object
message
string
POST/network/ranking-visibilityBearer authNetwork Ranking Visibility

Allow network to toggle leaderboard ranking visibility

show schema
is_public
boolean

User can set whether their network is visible on the leaderboard

1 status · show schema
200
error
object
message
string
POST/network/points-ranking-visibilityBearer authNetwork Points Ranking Visibility

Turn the network's name on or off on the points leaderboard. Every network with points is ranked and listed either way; this switch only decides whether its row shows the network name or "Anonymous". The emoji tag (/network/emoji) shows on the row regardless.

show schema
public
boolean

true to list the network on the points leaderboard

1 status · show schema
200
points_leaderboard_public
boolean
error
object
message
string
POST/network/emojiBearer authNetwork Set Emoji Tag

Set the network's emoji tag: 1 to 6 emoji (each grapheme cluster must be a single emoji: pictographs with skin tones, ZWJ sequences, keycaps, flags). Letters, digits and punctuation are rejected with the message "Use 1 to 6 emoji.". An empty string clears the tag. The tag is shown on the points leaderboard row and in the network's own header.

show schema
emoji_tag
string

1 to 6 emoji; an empty string clears the tag

1 status · show schema
200
emoji_tag
string

The stored (NFC-normalized) tag, empty when cleared

error
object
message
string
POST/network/block-locationBearer authNetwork Block Location

Block providing to a location

show schema
location_id
string

uuid

1 status · show schema
200
error
object
message
string
POST/network/unblock-locationBearer authNetwork Unblock Location

Unblock providing to a location

show schema
location_id
string

uuid

1 status · show schema
200
error
object
message
string
GET/network/blocked-locationsBearer authNetwork Blocked Locations

Get list locations to block from providing for the network

1 status · show schema
200
blocked_locations
arraynull
error
object
message
string
GET/network/reliabilityBearer authNetwork Reliability

Get network reliability stats

1 status · show schema
200
reliability_window
ReliabilityWindow
mean_reliability_weight
number (double)
min_time_unix_milli
integer (int64)
min_bucket_number
integer (int64)
max_time_unix_milli
integer (int64)
max_bucket_number
integer (int64)

exclusive

bucket_duration_seconds
integer
max_client_count
integer
max_total_client_count
integer
reliability_weights
array<number (double)>

indexed by relative bucket number (bucket number minus minbucketnumber)

array
number (double)
client_counts
array<integer>
array
integer
total_client_counts
array<integer>
array
integer
country_multipliers
arraynull
error
object
message
string
GET/network/userBearer authGet Network User

Get the user and configured auth methods for the caller network.

1 status · show schema
200
network_user
object
user_id
string

udid

user_auth
string

email or phone number

verified
boolean
auth_type
string
network_name
string
wallet_address
string
user_auths
array<object>
array
user_auth
string
auth_type
string
sso_auths
array<object>
array
user_id
string

udid

auth_type
string
auth_jwt
string
user_auth
string
wallet_auths
array<object>
array
user_id
string

udid

wallet_address
string
blockchain
string
seedphrase_auths
array<object>

The recovery seedphrases on file. The phrase itself is never returned -- only when it was created.

array
create_time
string
auth_types
arraynull

Every configured sign-in method's type, including seedphrase. The singular auth_type is the session's own.

error
object
message
string
POST/network/user/updateBearer authUpdate Network Name

Update the caller network's name.

show schema
network_name
string
1 status · show schema
200
error
object
message
string
GET/network/provider-egress-duePublicProvider Egress Location Due

The providers to probe next: those whose stored egress location or health run has gone stale and those never probed at all, oldest deadline first. A provider is skipped while it has a fresh success, a recent failed attempt (a much shorter backoff, so a provider that cannot be probed does not starve the queue), or a current dark verdict -- consecutive failed blackhole checks spanning a minimum time, not a single failed check (connect/GEOMAP.md §11.3). A batch the prober's run guard held back (attempt class run_batch_guard) is offered again after the first dark-backoff step.

Each provider carries the country and region it is published under, so the prober draws its sample only from the destinations compatible with that place.

limit(query)
integer

Batch size, default 100, clamped to the deployment ceiling (provider_egress_due.yml max_due_limit, default 500). A non-integer or non-positive value is a 400 rather than a clamp, because an empty list must not be confused with "nothing is due".

shard_count(query)
integer

Partitions the queue across independent workers; default 1.

shard_index(query)
integer

This worker's partition, 0-based and below shard_count.

3 statuses · show schema
200
providers
array<ProviderEgressDueProvider>

In due order.

array
client_id
string

udid

country_code
string

Lowercase alpha-2; absent when the provider has not been placed.

region
string

The region's name, as incompatible places name it; absent when unknown.

400
No body
401
No body
POST/network/provider-egress-locationPublicProvider Egress Location Submit

Store where a provider's traffic exits: exit_ip, the address the operator's own /my-ip-info echo saw the probe come from THROUGH the provider's tunnel. The server places it with its own GeoLite2 (the location row, the country, and city_confident when GeoLite2's accuracy radius is within the configured city radius) and prefers it over the lookup on the provider's control-connection address. The address itself is never stored, and no ip-intelligence verdict is recorded (connect/GEOMAP.md §11.3, D24).

A submission without exit_ip -- the retired vendor-consensus shape -- is refused with a 400; the legacy fields are accepted and ignored for one release. The body is capped at 16 KiB.

show schema
client_id
string

udid

exit_ip
string

Required. The address the operator's /my-ip-info echo saw through the provider's tunnel, in canonical form.

observed_at
string (date-time)
country_code
string

Ignored.

country
string

Ignored.

region
string

Ignored.

city
string

Ignored.

asn
integer

Ignored.

org
string

Ignored.

hosting
boolean

Ignored.

proxy
boolean

Ignored.

mobile
boolean

Ignored.

country_confident
boolean

Ignored.

city_confident
boolean

Ignored.

4 statuses · show schema
200
location_id
string

udid

400
No body
401
No body
413
No body
POST/network/provider-egress-attemptPublicProvider Egress Location Attempt

Record that the prober TRIED to probe a provider, whether or not the try produced a location. The prober reports failures here; a success is already implied by the stored location. Without this, a provider that can never be probed successfully would sort to the head of the due queue on every poll forever.

show schema
client_id
string

udid

probe_failure
string

Empty when the attempt succeeded, otherwise a short failure class (tunnel_failed, health_not_run, run_not_measured, no_exit_ip, submit_failed, run_batch_guard, ...).

4 statuses · show schema
200
attempt_at
string (date-time)
400
No body
401
No body
413
No body
GET/network/provider-blackhole-duePublicProvider Blackhole Check Due

The blackhole sweep queue: every provider whose next check has come due -- a backoff step after a failed or unmeasured check, the ordinary due age after a pass -- oldest due first, before any provider never checked, so a failing provider's retry is never pushed out of a batch by first checks (connect/GEOMAP.md §11.3). Each provider carries the place it is published under. A check is three small loads through the provider's tunnel, so the batches are much larger than the egress-location ones.

limit(query)
integer

Batch size, default 500, capped at 5000. A non-positive value is a 400.

shard_count(query)
integer
shard_index(query)
integer
3 statuses · show schema
200
providers
array<ProviderEgressDueProvider>

In due order.

array
client_id
string

udid

country_code
string

Lowercase alpha-2; absent when the provider has not been placed.

region
string

The region's name, as incompatible places name it; absent when unknown.

400
No body
401
No body
POST/network/provider-blackhole-checksPublicSubmit Provider Blackhole Checks

Submit up to 10,000 blackhole results at once: for each provider, did anything get through. The WHOLE batch is validated before any of it is written, so a caller reporting fire-and-forget is never left unable to tell which results landed. checked_at is required and is never fabricated server-side (an "as of now" stamp would defeat the freshness bound the gate depends on) and may not be in the future; a failed check must name a failure class of at most 64 characters. Unknown fields are rejected.

A failed check is a failure, not a verdict: the server keeps each provider's run of consecutive failures, and the provider is dark only once the run reaches the configured count over the configured span (connect/GEOMAP.md §11.3); a TLS-authentication failure is dark at once. A check marked not_measured -- its tunnel was gone and could not be re-created -- counts nothing and only reschedules the provider.

show schema
checks
array<SubmitProviderBlackholeCheckArgs>

1 to 10,000 results. The whole batch is validated before any of it is written.

array
client_id
string

udid

ok
boolean

Something got through.

failure
string

A short failure class when ok is false (tunnel_failed, all_destinations_failed, tls_authentication_failed, not_measured, ...), at most 64 characters. Required when ok is false; ignored when it is true.

not_measured
boolean

None of the check's loads could be measured (its tunnel was gone and could not be re-created): not a verdict either way. The check counts nothing against the provider and only reschedules it.

checked_at
string (date-time)

Required, never fabricated server-side, and never in the future.

3 statuses · show schema
200
empty object
400
No body
401
No body
GET/network/provider-bandwidth-testPublicProvider Bandwidth Test

Stream a bounded number of arbitrary bytes, so the prober has something to download THROUGH a provider's tunnel and time. Only the byte count matters; the content is a small repeating block streamed under a limit reader and never materialized. Operator-gated so the deployment is not a free public speed-test target.

bytes(query)
integer

Bytes to stream. Default 1 MiB; clamped to 5 MiB. Absent, malformed or non-positive values take the default. One probe is 8 parallel streams, and the aggregate is bounded by the reservation rather than by this clamp.

2 statuses · show schema
200
string (binary)
401
No body
POST/network/provider-bandwidth-reservePublicProvider Bandwidth Reserve

Take deployment-wide byte budget before spending any probe bytes. Active probing pulls real paid contract traffic through a provider's tunnel, so it is rationed per hourly bucket. byte_count is clamped to the per-probe maximum (16 MiB), so an oversized request cannot swallow a bucket.

The prober measures over a tunnel it has open right now, so a reservation that lands in a LATER bucket is cancelled again and the request answered 429 with Retry-After pointing at the bucket that does have room; without that the hourly ceiling would be decorative.

show schema
client_id
string

udid

byte_count
integer

Must be positive; clamped to the per-probe maximum (16 MiB).

4 statuses · show schema
200
reservation_id
string

udid

bucket_start
string (date-time)

The hourly bucket the reservation was taken in, always the current one.

400
No body
401
No body
429
No body
POST/network/provider-bandwidth-resultPublicProvider Bandwidth Result

Store one active bandwidth measurement taken over a provider's tunnel. An active probe is a point measurement rather than a window, so the server stamps arrival time as both window bounds.

The row is keyed on (client_id, source), so source must be one of the known ACTIVE values; an unrecognised tag would create a row nothing ever reads or replaces. passive is refused outright: that figure is derived server-side from bytes the provider was already paid to carry, which is what makes it ungameable, and accepting a submitted one would let this endpoint overwrite a derived figure with an asserted one. A non-positive rate or sample size is refused rather than allowed to overwrite a real measurement.

show schema
client_id
string

udid

source
string

Which target produced this figure. Part of the storage key, which is what keeps the two targets' figures in separate rows. passive is refused: it is derived server-side and must never be asserted.

enum: active-operator, active-cdn
bytes_per_second
number

Must be positive.

sample_byte_count
integer

Must be positive.

4 statuses · show schema
200
empty object
400
No body
401
No body
413
No body
POST/network/provider-egress-healthPublicProvider Egress Health Result

Store one egress-health run: over the provider's tunnel, how many of the sampled loads of each class passed after their retries -- a load fails only when every attempt failed (connect/GEOMAP.md §11.3). Loads whose tunnel could not be re-created, and canaries, are in no count and are named apart. A failed load of a site on probation, or of one marked incompatible with the provider's place, is taken out of the counts by the server and named in the stored row's unscored_failed_names. The row is an upsert keyed on client_id, so a bad submission does not sit beside the good one -- it destroys the last good measurement. Everything is therefore validated before anything is stored, and unknown fields are rejected outright (a misspelled field would decode to a perfectly consistent zero, filling the table with plausible rows describing a measurement that never happened).

class_results must sum EXACTLY to ok_count/total_count: the classes are the score, and a total that does not decompose into them means the two halves came from different runs. The reputation class dissolved into the sites: reputation_ok, reputation_total and reputation_failed_names are accepted, always zero from a current prober, and ignored, and a reputation key inside class_results is still refused.

show schema
client_id
string

udid

ok_count
integer

Scored loads that passed on some attempt; loads not measured and canaries are in neither count.

total_count
integer

Scored loads measured.

class_results
map

The per-class tally for the scored classes. Its ok and total must sum to exactly ok_count and total_count. A reputation key is refused.

map
ok
integer
total
integer
reputation_ok
integer

Always zero; accepted and ignored since the reputation class dissolved into the sites.

reputation_total
integer

Always zero; accepted and ignored.

failed_names
string

The comma-joined names of the scored loads that failed every attempt.

reputation_failed_names
string

Always empty; accepted and ignored.

tls_authentication_failure
boolean

Separate from the score. A peer that cannot authenticate the requested HTTPS host is a hard integrity failure even when the counts look healthy.

not_measured_count
integer

Loads whose tunnel was gone and could not be re-created in time; in no count.

not_measured_names
string

Their comma-joined names.

canary_passed_names
string

Comma-joined canaries (unscored loads from a place their site is marked incompatible with) that passed.

canary_failed_names
string

Comma-joined canaries that failed.

short_classes
string

Comma-joined classes too thin, for the provider's place, to fill their sample.

4 statuses · show schema
200
empty object
400
No body
401
No body
413
No body
GET/network/provider-egress-destinationsPublicProvider Egress Destinations

The sites the prober loads (connect/GEOMAP.md §11.4): the active destinations per class with their load contracts, the pool version, when it was generated, and the request profile to load them with -- the prober module's own Pool shape. The prober fetches it at the start of every pass and probes its built-in table when it cannot. A site on probation is served and loaded like the rest; what it may not do is count, which the health ingest decides. A destination marked incompatible with places is served with canary set in a small share of fetches, asking for it to be loaded there anyway, unscored.

The first request seeds an empty pool from the prober's built-in table, so the route never serves nothing for want of a refresh.

3 statuses · show schema
200
version
integer

Identifies the pool's contents.

generated_at
string (date-time)
destinations
array<ProviderEgressDestination>
array
name
string
class
string
enum: dns, connectivity, cdn, site
url
string

https on port 443.

headers
map

Sent over the request profile; Range and Accept-Encoding are never sent.

map
string
expect
string

body (a 2xx with a body), status (exactly status), or reachable (any 2xx or 3xx, sites only).

enum: body, status, reachable
status
integer
max_bytes
integer

The body read cap; at most 1024.

verify
ProviderEgressDestinationVerify
kind
string
enum: dns_json, ip_text, contains
text
string

What contains looks for.

incompatible
array<ProviderEgressDestinationPlace>
array
country
string

Lowercase alpha-2.

region
string
canary
boolean

Load this destination, unscored, from the places it is incompatible with.

profile
ProviderEgressRequestProfile
user_agent
string
headers
map
map
string
401
No body
500
No body
POST/network/provider-verdictBearer authProvider Client Verdict Submit

A real client network reporting that a provider carried nothing. This is the ONE route in this group that is not operator-secret authed: the reporter is a network, and the network is the unit the quorum counts, so the reporting network is taken from the session jwt and never from the body. A met quorum only brings the provider's next probe forward. Unknown fields in the body are rejected.

show schema
exit_client_id
string

udid. The provider being reported.

reason
string
send_ack_count
integer
send_ack_bytes
integer
receive_ack_count
integer
receive_ack_bytes
integer
syn_sent
integer
syn_received
integer
window_seconds
integer
2 statuses · show schema
200
empty object
401
No body
GET/network/prober-credentialPublicProber Credential

The network client jwt the bootstrap task minted for the operator's prober, so no human step remains between a fresh deployment and a probing prober.

The response is narrow -- the jwt and the client id it names -- but do NOT read that as containment. The jwt itself carries network_id, user_id and network_name as readable claims, and holding it is enough to authenticate as the account and regenerate its seedphrase. The operator secret checked here is the actual gate.

404 means there is no credential YET (no prober row, or one whose client jwt has not been minted or was cleared for re-provisioning), which the prober must be able to tell from a failure -- so it is a 404 rather than an empty 200.

3 statuses · show schema
200
by_client_jwt
string

The prober's network client jwt. Revocable and re-mintable, but holding it authenticates as the prober's account.

client_id
string

udid. The client the jwt already names.

401
No body
404
No body
GET/network/geolocation-source-pinsPublicGeolocation Source Pins

Retired with the geolocation sources (connect/GEOMAP.md D24): the server no longer observes new pins, and the rows already stored are for hosts no probe dials, which the prober drops before it opens a tunnel. Every host a probe loads, the operator's /my-ip-info echo included, is verified by WebPKI. The route stays one release, because the prober fetches it every pass.

The certificate pins this server observed DIRECTLY for the geolocation source hosts, on its own network, with no provider in the path and full chain validation. The prober fetches them here instead of carrying a compile-time constant, and refuses to probe at all without a complete set: the geolocation lookup is issued THROUGH the provider under test, and the pin is what stops that provider substituting a certificate and forging its own location.

The body is a BARE map from host to its pin, with no wrapping field. Both the leaf and its issuing intermediate SPKI hashes are served, because a match anywhere in the verified chain is accepted: the intermediate absorbs routine leaf renewal between observations, and the leaf is the tighter of the two while it lasts.

A host that has never been observed is simply absent, and an empty table is {} with 200 rather than a 404 -- 404 would be indistinguishable from "this server does not implement the endpoint". This endpoint is read-only; nothing here ever accepts a pin from a request.

2 statuses · show schema
200
map
leaf
string
intermediate
string
401
No body