# Bootnode API

The Bootnode API provides controlled access for frontends (e.g., scanners, stats dashboards) to query the subnet bootnode list and heartbeats (i.e., the DHT Records `"nodes"` key).

{% hint style="warning" %}
**Do not give any party API access without trusting them.**
{% endhint %}

To prevent abuse, requests are rate-limited by both API key and IP address.

By default, each combination of API key and IP is limited to 5 requests per minute.

### API Keys <a href="#api-keys" id="api-keys"></a>

Each request requires a valid API key. API keys are managed locally and stored in bootnode\_rest\_keys.json.

**Parameters**

`owner` – Identifier for the owner of the API key\
`key` – The API key string (generated if not provided)\
`active` – Boolean flag indicating whether the key is enabled

**Example**

```python
[
  { "owner": "party1", "key": "key-party1-abc123", "active": true },
  { "owner": "party2", "key": "key-party2-xyz456", "active": true },
  { "owner": "party3", "key": "key-party3-789qwe", "active": false }
]
```

### Managing API Keys <a href="#managing-api-keys" id="managing-api-keys"></a>

Keys can be manually added to the JSON file or by using the following CLI commands.

**Add a new API key**

Generates a new key for the given owner (unless one already exists):

```bash
subnet-add-api-key --owner <owner_name>
```

**Deactivate an API key**

Mark an owner's key as inactive without removing it:

```bash
subnet-add-api-key --owner <owner_name> --inactive
```

**Reactivate an API key**

Restore access for an owner's key:

```bash
subnet-add-api-key --owner <owner_name>
```

### Notes <a href="#notes" id="notes"></a>

By default, keys are stored in `bootnode_rest_keys.json` or the directory of your choosing.

Updating a key will overwrite the existing one for that owner.

Only active keys are accepted by the API.

***

## Endpoints

## Get Bootnodes

<mark style="color:blue;">`GET`</mark>`/v1/get_heartbeat`

Returns the subnet bootnodes in the P2P network.

{% hint style="info" %}
This comes directly from the peer-to-peer network and should be identical to the [bootnodes the subnet owner lists on-chain](/network/subnet-owner.md#update-bootnodes), but is not a gaurantee to match.
{% endhint %}

**Headers**

| Name          | Value                 |
| ------------- | --------------------- |
| Content-Type  | `application/json`    |
| Authorization | `X-API-Key <api key>` |

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "value": [
    "/ip4/123.123.123.123/tcp/31330/p2p/QmSjcNmhbRvek3YDQAAQ3rV8GKR8WByfW8LC4aMxk6gj7v",
    "/ip4/123.123.123.123/udp/31330/quic/p2p/QmSjcNmhbRvek3YDQAAQ3rV8GKR8WByfW8LC4aMxk6gj7v"
  ]
}
```

{% endtab %}

{% tab title="400" %}

```json
{
    "detail":"Invalid or missing API Key"
}
```

{% endtab %}
{% endtabs %}

## Get Peers Info

<mark style="color:blue;">`GET`</mark>`/v1/get_peers_info`

Returns each peer's information in the P2P network.

{% hint style="info" %}
This comes directly from the peer-to-peer network.
{% endhint %}

**Headers**

| Name          | Value                 |
| ------------- | --------------------- |
| Content-Type  | `application/json`    |
| Authorization | `X-API-Key <api key>` |

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
    "value":{
        "12D3KooWEdfS2dGfBGJZiftYyDx2PyFPi3qxXQx57DhEoZsTgLhh":{
            "123.123.123.123":{
                "location": {
                    "status": "success",
                    "country": "United States",
                    "countryCode": "US",
                    "region": "CA",
                    "regionName": "California",
                    "city": "Los Angeles",
                    "zip": "90001",
                    "lat": 34.0549,
                    "lon": -118.2426,
                    "timezone": "America/Los_Angeles",
                    "isp": "Verizon",
                    "org": "Level 3",
                    "as": "Verizon",
                    "query": "123.123.123.123"
                },
            },
            "multiaddrs":[
                "/ip4/123.123.123.123/tcp/34490"
            ]
        },
        "QmbRz8Bt1pMcVnUzVQpL2icveZz2MF7VtELC44v8kVNwiG":{
            "123.123.123.123":{
                "location": {
                    "status": "success",
                    "country": "United States",
                    "countryCode": "US",
                    "region": "NY",
                    "regionName": "New York",
                    "city": "New York",
                    "zip": "10001",
                    "lat": 40.7128,
                    "lon": -74.0060,
                    "timezone": "America/New_York",
                    "isp": "AT&T",
                    "org": "Level 3",
                    "as": "AT&T",
                    "query": "123.123.123.123"
                },
            },
            "multiaddrs":[
                "/ip4/123.123.123.123/tcp/31332"
            ]
        },
    }
}
```

{% endtab %}

{% tab title="400" %}

```json
{
    "detail":"Invalid or missing API Key"
}
```

{% endtab %}
{% endtabs %}

## Get Heartbeat

<mark style="color:blue;">`GET`</mark>`/v1/get_heartbeat`

Returns the subnet's heartbeats from all peers in the DHT records under the `"nodes"` key.

**Headers**

| Name          | Value                 |
| ------------- | --------------------- |
| Content-Type  | `application/json`    |
| Authorization | `X-API-Key <api key>` |

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
    "value": [
        {
        "peer_id": "QmShJYgxNoKn7xqdRQj5PBcNfPSsbWkgFBPA4mK5PH73JB",
        "server": {
            "state": "ONLINE",
            "role": "VALIDATOR",
            "throughput": 1,
            "public_name": null,
            "version": "1.0.0",
            "using_relay": false,
            "next_pings": {
                "QmTJ8uyLJBwVprejUQfYFAywdXWfdnUQbC1Xif6QiTNta9": 0.005177857035560813,
                "QmbRz8Bt1pMcVnUzVQpL2icveZz2MF7VtELC44v8kVNwiG": 0.004115824259442489
            }
        },
        "expiration_time": 1765332171.7576787
        },
        {
        "peer_id": "QmbRz8Bt1pMcVnUzVQpL2icveZz2MF7VtELC44v8kVNwiG",
        "server": {
            "state": "ONLINE",
            "role": "VALIDATOR",
            "throughput": 1,
            "public_name": null,
            "version": "1.0.0",
            "using_relay": false,
            "next_pings": {
                "QmShJYgxNoKn7xqdRQj5PBcNfPSsbWkgFBPA4mK5PH73JB": 0.005389619574915292,
                "QmTJ8uyLJBwVprejUQfYFAywdXWfdnUQbC1Xif6QiTNta9": 0.004811888599831563
            }
        },
        "expiration_time": 1765332163.220499
        },
        {
        "peer_id": "QmTJ8uyLJBwVprejUQfYFAywdXWfdnUQbC1Xif6QiTNta9",
        "server": {
            "state": "ONLINE",
            "role": "VALIDATOR",
            "throughput": 1,
            "public_name": null,
            "version": "1.0.0",
            "using_relay": false,
            "next_pings": {
                "QmShJYgxNoKn7xqdRQj5PBcNfPSsbWkgFBPA4mK5PH73JB": 0.005134013483953814,
                "QmbRz8Bt1pMcVnUzVQpL2icveZz2MF7VtELC44v8kVNwiG": 0.004351709186359328
            }
        },
        "expiration_time": 1765332164.4520426
        }
    ]
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hypertensor.org/subnet-template/bootnode-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
