/api/drd/server/get

GET

Reads server descriptors published with /api/drd/server/post. With no parameters it lists every registered server of every role. Narrow it with role, or fetch exactly one server by its identity coin, or one RAIDA by slot number. The core queries all 25 RAIDAs with protocol command 150 server_get and merges the answers. No authentication: the directory is public.

Parameters

Name Type Required Description
role string No raida, qmail, beacon, drd, rke, or all (default). Required when sn or raida_id is given.
sn integer No Fetch one server by identity coin serial number. Needs role (not all) and denomination.
denomination integer With sn Denomination of the identity coin (5 = 100,000 CC, 4 = 10,000 CC).
raida_id integer No Fetch one RAIDA by slot number 0–24. Needs role=raida. Ignored if sn is also given.

Responses

Success Response (200)

servers holds the merged descriptors. Which fields appear depends on the role and on what the server chose to publish; optional measured fields (benchmark_ms, network_speed_bps, ram, storage_available, max_object, version) are omitted when the server never reported them. An empty directory is a success with count 0. Fan-out fields are as on every DRD endpoint.

{
    "command": "drd-server-get",
    "success": true,
    "count": 2,
    "servers": [
        {
            "role": "raida",
            "denomination": 5,
            "serial_number": 17,
            "raida_id": 11,
            "ip4": "203.0.113.11",
            "jurisdiction": "Iceland",
            "benchmark_ms": 42,
            "network_speed_bps": 1000000000,
            "is_a_raida": true,
            "created_at": 1788393600,
            "updated_at": 1788393600,
            "last_seen_at": 1788480000
        },
        {
            "role": "qmail",
            "denomination": 5,
            "serial_number": 17,
            "ip4": "203.0.113.11",
            "storage_available": 2000000000000,
            "max_object": 1073741824,
            "version": 20260905,
            "welfare_bytes": 307200,
            "min_mailbox_class": 0,
            "subscriptions_available": true,
            "subscription_url": "https://mail.example.com/subscribe",
            "tiers": "100000:0.00010;1000000:0.00008;10000000:0.00006;4294967295:0.00004",
            "encryption_types": "4,8",
            "accepting_uploads": true,
            "is_a_raida": true,
            "created_at": 1788393700,
            "updated_at": 1788393700,
            "last_seen_at": 1788480100
        }
    ],
    "pass_count": 25,
    "fail_count": 0,
    "no_response_count": 0,
    "skipped_count": 0,
    "quorum": true,
    "raida_results": [
        { "raida": 0, "success": true, "status": 250 },
        { "raida": 1, "success": true, "status": 250 }
    ]
}
Field Type Description
countintegerNumber of descriptors in servers (server-side cap 100 per role per RAIDA).
servers[].rolestringraida, qmail, beacon, drd, or rke.
servers[].denomination, serial_numberintegerIdentity coin. One machine may appear once per role under the same coin.
servers[].raida_idintegerSlot 0–24. RAIDA role only.
servers[].ip4, ip6stringAddresses to dial. At least one is always present.
servers[].jurisdiction, benchmark_msstring, integerRAIDA role only.
servers[].network_speed_bpsintegerAny role, if measured.
servers[].ram, processorinteger, stringService roles, if reported.
servers[].storage_available, max_object, version, tiers, accepting_uploadsmixedQMail role only.
servers[].welfare_bytesintegerService roles. Always present (0 when none is offered); reported for beacon too but not settable there.
servers[].min_mailbox_classintegerService roles. Minimum sender address-coin denomination code, 0–4 (0 = 1 CC @bit, 4 = 10,000 CC @giga).
servers[].subscriptions_available, subscription_url, encryption_typesmixedService roles.
servers[].registration_neededbooleanBeacon role only.
servers[].is_a_raidabooleanAlways true for RAIDA rows. For service rows, true only when the same 100,000 CC coin also holds a RAIDA slot — computed by the RAIDAs, never self-asserted.
servers[].created_at, updated_at, last_seen_atintegerUnix seconds stamped by the RAIDA: first registration, last change to a fact, last successful post (the heartbeat). A stale last_seen_at means the server stopped re-posting.

Error Responses

400 Bad Request

Unknown role; sn without role and denomination, or sn of 0; raida_id without role=raida or outside 0–24.

{
    "error": true,
    "message": "sn lookup needs role, denomination and a valid sn",
    "code": 400
}
{
    "error": true,
    "message": "raida_id lookup needs role=raida and raida_id 0-24",
    "code": 400
}

404 Not Found

A single-server lookup (sn or raida_id) found nothing and at least one RAIDA explicitly reported no such entry (status 193). A listing never returns 404; an empty directory is count 0.

{
    "error": true,
    "message": "Server not registered",
    "code": 404
}

500 Internal Server Error

The core could not select an HV=2 encryption coin pair, or the fan-out failed outright.

{
    "error": true,
    "message": "DRD server get failed",
    "code": 500
}

Examples

cURL Example

# Every registered server, all roles
curl -X GET "http://localhost:8080/api/drd/server/get"

# All QMail servers
curl -X GET "http://localhost:8080/api/drd/server/get?role=qmail"

# RAIDA slot 11
curl -X GET "http://localhost:8080/api/drd/server/get?role=raida&raida_id=11"

# One server by identity coin
curl -X GET "http://localhost:8080/api/drd/server/get?role=qmail&denomination=5&sn=17"

JavaScript Example

fetch(`http://localhost:8080/api/drd/server/get?role=qmail`)
    .then(r => r.json())
    .then(data => {
        if (!data.success) { console.error(data.message); return; }
        const dayAgo = Date.now() / 1000 - 86400;
        data.servers
            .filter(s => s.accepting_uploads && s.last_seen_at > dayAgo)
            .forEach(s => console.log(`${s.ip4 || s.ip6}  free=${s.storage_available ?? '?'}  enc=${s.encryption_types ?? ''}`));
    });

Python Example

import requests, time

url = 'http://localhost:8080/api/drd/server/get'
data = requests.get(url, params={'role': 'raida'}).json()

if data.get('success'):
    slots = {s['raida_id']: s for s in data['servers']}
    for i in range(25):
        s = slots.get(i)
        if s is None:
            print(f"RAIDA {i:2}: not registered")
        else:
            age = int(time.time() - s['last_seen_at'])
            print(f"RAIDA {i:2}: {s.get('ip4') or s.get('ip6')}  {s['jurisdiction']}  seen {age}s ago")
else:
    print('Error', data.get('code'), data.get('message'))

Notes

  • Independent directories. Each RAIDA keeps its own copy of the server tables, so a freshly registered server may be missing from a few. The merged result is the union; treat pass_count as a confidence measure.
  • Discovery, not trust. A listing tells a client where to try. Whether a server actually serves that client is decided by the server itself when the client connects.
  • Listings can exceed one UDP datagram; the core handles the TCP retry (RAIDA status 218) internally.
  • Older RAIDAs without HV=2 group-16 support answer status 219 and show up in raida_results as failures with no descriptors.