| layout | default |
|---|---|
| title | API Reference - AtlasP2P |
This document describes the JSON API endpoints for programmatic access to node data. The API structure matches Bitnodes.io for compatibility while adding extended features specific to your blockchain network.
http://localhost:4000/api (Development)
https://nodes.example.com/api (Production - replace with your domain)
The JSON endpoints (/api/*.json) are public and do not require authentication. Rate limiting headers are included in responses.
Some endpoints require authentication via JWT (user session) or API key:
API Key Authentication:
# Via Authorization header (recommended)
curl -H "Authorization: Bearer {ticker}_sk_xxxxxxxx" https://nodes.example.com/api/nodes.json
# Via X-API-Key header
curl -H "X-API-Key: {ticker}_sk_xxxxxxxx" https://nodes.example.com/api/nodes.jsonSession Authentication: Requires valid Supabase session cookie (for browser-based access).
All endpoints include proper CORS headers:
Access-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, OPTIONSAccess-Control-Allow-Headers: Content-Type, Authorization
Rate limit information is provided in response headers:
X-RateLimit-Limit: Maximum requests per hour (1000)X-RateLimit-Remaining: Remaining requests in current windowX-RateLimit-Reset: Unix timestamp when limit resets
Retrieve a list of nodes with filtering, sorting, and pagination support.
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 |
Page number for pagination |
limit |
integer | 100 |
Results per page (max: 500) |
country |
string | - | Filter by ISO 3166-1 alpha-2 country code (e.g., US, DE) |
tier |
string | - | Filter by tier: diamond, gold, silver, bronze, standard |
version |
string | - | Filter by specific client version |
verified |
boolean | - | Filter by verification status: true or false |
online |
boolean | - | Filter by online status: true or false |
sort |
string | last_seen |
Sort field: last_seen, first_seen, pix_score, tier, uptime_percentage |
order |
string | desc |
Sort order: asc or desc |
curl "https://nodes.example.com/api/nodes.json?country=US&tier=diamond&page=1&limit=50"{
"timestamp": 1702345678,
"total_nodes": 1234,
"latest_height": 5678901,
"nodes": {
"192.168.1.1:33117": {
"protocol_version": 70015,
"user_agent": "/Dingocoin:1.16.0/",
"connected_since": 1702345678,
"services": "0000000000000001",
"height": 5678901,
"hostname": null,
"city": "San Francisco",
"country": "US",
"country_name": "United States",
"latitude": 37.7749,
"longitude": -122.4194,
"timezone": "America/Los_Angeles",
"asn": "AS15169",
"organization_name": "Google LLC",
"isp": "Google LLC",
"status": "up",
"last_seen": 1702345678,
"latency_ms": 45.2,
"uptime_percentage": 99.8,
"reliability": 98.5,
"tier": "diamond",
"pix_score": 965.3,
"rank": 1,
"is_verified": true,
"tips_enabled": true
}
},
"pagination": {
"page": 1,
"limit": 50,
"total": 1234,
"total_pages": 25
}
}Standard Fields (Bitnodes-compatible):
protocol_version: Bitcoin protocol version numberuser_agent: Node client version stringconnected_since: Unix timestamp of first discoveryservices: Service flags as hex stringheight: Current blockchain heighthostname: Reverse DNS hostname (if available)city: City name from GeoIPcountry: ISO 3166-1 alpha-2 country codelatitude/longitude: Geographic coordinatestimezone: IANA timezone identifierasn: Autonomous System Numberorganization_name: ASN organization name
Extended Fields (AtlasP2P-specific):
status: Current node status (up,down,pending)last_seen: Unix timestamp of last successful connectionlatency_ms: Average connection latency in millisecondsuptime_percentage: Uptime percentage (0-100)reliability: Reliability score (0-100)tier: Node tier classificationpix_score: Performance Index Score (PIX)rank: Global rank based on PIX scoreis_verified: Whether node ownership is verifiedtips_enabled: Whether tipping is enabled for this node
Retrieve comprehensive network statistics including node counts, distributions, and health metrics.
None.
curl "https://nodes.example.com/api/stats.json"{
"timestamp": 1702345678,
"total_nodes": 1234,
"available_nodes": 1200,
"countries": 89,
"versions": {
"/Dingocoin:1.16.0/": 850,
"/Dingocoin:1.15.0/": 350,
"unknown": 34
},
"countries_distribution": {
"US": {
"count": 450,
"name": "United States"
},
"DE": {
"count": 280,
"name": "Germany"
},
"CN": {
"count": 150,
"name": "China"
}
},
"tiers_distribution": {
"diamond": 45,
"gold": 120,
"silver": 230,
"bronze": 305,
"standard": 500
},
"network_health": {
"health_score": 92.5,
"average_uptime": 98.3,
"average_latency": 125.4,
"verified_nodes": 678,
"tips_enabled_nodes": 234
},
"latest_height": 5678901,
"historical_data": [
{
"timestamp": 1702259278,
"total_nodes": 1220,
"available_nodes": 1190,
"average_uptime": 98.1,
"countries": 87
}
]
}Standard Fields (Bitnodes-compatible):
timestamp: Unix timestamp of data generationtotal_nodes: Total number of discovered nodesavailable_nodes: Number of currently online nodescountries: Number of unique countriesversions: Version distribution (version string → count)countries_distribution: Country distribution (country code → {count, name})latest_height: Highest blockchain height observed
Extended Fields (AtlasP2P-specific):
tiers_distribution: Distribution of nodes across tiersnetwork_health: Aggregate network health metricshealth_score: Overall health (0-100) based on uptime, availability, latency, and verificationaverage_uptime: Network-wide average uptime percentageaverage_latency: Network-wide average latency in msverified_nodes: Number of verified nodestips_enabled_nodes: Number of nodes with tipping enabled
historical_data: 7-day historical snapshots
Retrieve detailed country-based distribution of nodes with performance metrics.
| Parameter | Type | Default | Description |
|---|---|---|---|
sort |
string | count |
Sort field: code, name, count |
order |
string | desc |
Sort order: asc or desc |
online_only |
boolean | true |
Filter to only online nodes |
curl "https://nodes.example.com/api/countries.json?sort=count&order=desc"{
"timestamp": 1702345678,
"total_countries": 89,
"total_nodes": 1234,
"countries": [
{
"code": "US",
"name": "United States",
"count": 450,
"percentage": 36.4,
"online_count": 445,
"verified_count": 123,
"tiers": {
"diamond": 15,
"gold": 45,
"silver": 89,
"bronze": 130,
"standard": 171
},
"average_uptime": 98.5,
"average_latency": 125.3
},
{
"code": "DE",
"name": "Germany",
"count": 280,
"percentage": 22.7,
"online_count": 275,
"verified_count": 87,
"tiers": {
"diamond": 10,
"gold": 35,
"silver": 70,
"bronze": 90,
"standard": 75
},
"average_uptime": 97.8,
"average_latency": 98.6
}
]
}timestamp: Unix timestamp of data generationtotal_countries: Number of unique countries representedtotal_nodes: Total number of nodes (filtered by online_only if set)countries: Array of country objects, each containing:code: ISO 3166-1 alpha-2 country codename: Full country namecount: Total number of nodes in this countrypercentage: Percentage of total nodesonline_count: Number of currently online nodesverified_count: Number of verified nodestiers: Distribution across node tiersaverage_uptime: Average uptime percentage for countryaverage_latency: Average latency in milliseconds for country
All endpoints return standard HTTP status codes and error responses in JSON format:
{
"error": "Error message",
"details": "Detailed error description"
}200 OK: Successful request400 Bad Request: Invalid query parameters404 Not Found: Resource not found500 Internal Server Error: Server error
curl "https://nodes.example.com/api/nodes.json?tier=invalid"{
"error": "Invalid query parameters",
"details": "Validation failed: tier: Invalid enum value. Expected 'diamond' | 'gold' | 'silver' | 'bronze' | 'standard'"
}All endpoints include cache headers:
Cache-Control: public, s-maxage=60, stale-while-revalidate=120
Data is cached for 60 seconds at the edge, with stale content served for up to 120 seconds while revalidating in the background.
curl "https://nodes.example.com/api/nodes.json?country=US&tier=diamond&online=true"curl "https://nodes.example.com/api/stats.json"curl "https://nodes.example.com/api/countries.json?sort=count&order=desc" | jq '.countries[:10]'curl "https://nodes.example.com/api/nodes.json?verified=true&sort=uptime_percentage&order=desc&limit=100"# Fetch current stats
curl "https://nodes.example.com/api/stats.json" | jq '.network_health'
# Output:
{
"health_score": 92.5,
"average_uptime": 98.3,
"average_latency": 125.4,
"verified_nodes": 678,
"tips_enabled_nodes": 234
}Nodes are classified into tiers based on performance metrics:
| Tier | Requirements |
|---|---|
| Diamond | PIX > 950, Uptime > 99%, Latency < 50ms |
| Gold | PIX > 900, Uptime > 98%, Latency < 100ms |
| Silver | PIX > 850, Uptime > 95%, Latency < 200ms |
| Bronze | PIX > 800, Uptime > 90%, Latency < 500ms |
| Standard | All other nodes |
PIX Score Formula:
PIX = (uptime% × 0.5) + ((100 - latency_ms) × 0.3) + (reliability% × 0.2)
import requests
# Fetch all diamond nodes
response = requests.get(
'https://nodes.example.com/api/nodes.json',
params={'tier': 'diamond', 'online': 'true'}
)
data = response.json()
print(f"Total diamond nodes: {len(data['nodes'])}")
for address, node in data['nodes'].items():
print(f"{address}: {node['user_agent']} (PIX: {node['pix_score']})")const axios = require('axios');
async function getNetworkStats() {
const response = await axios.get('https://nodes.example.com/api/stats.json');
const stats = response.data;
console.log(`Total Nodes: ${stats.total_nodes}`);
console.log(`Online Nodes: ${stats.available_nodes}`);
console.log(`Health Score: ${stats.network_health.health_score}`);
}
getNetworkStats();# Get top 5 countries
curl -s "https://nodes.example.com/api/countries.json" | \
jq -r '.countries[:5] | .[] | "\(.code): \(.count) nodes (\(.percentage)%)"'
# Output:
# US: 450 nodes (36.4%)
# DE: 280 nodes (22.7%)
# CN: 150 nodes (12.2%)
# ...While maintaining compatibility with Bitnodes.io's API structure, this API includes several enhancements:
- Extended Node Data: Additional fields like
tier,pix_score,rank,reliability,is_verified,tips_enabled - Advanced Filtering: Filter by tier, verification status, and more
- Performance Metrics: Detailed uptime, latency, and reliability tracking
- Network Health: Aggregate health scoring and historical trends
- Country Statistics: Per-country performance metrics and tier distribution
- Pagination: Efficient pagination for large result sets
The following endpoints require authentication (session or API key).
Retrieve all nodes verified by the authenticated user.
Authentication: Required (session)
curl -H "Cookie: sb-xxx-auth-token=xxx" "https://nodes.example.com/api/my-nodes"{
"nodes": [
{
"id": "uuid",
"ip": "192.168.1.1",
"port": 33117,
"status": "up",
"tier": "gold",
"pixScore": 920,
"isVerified": true,
"verificationMethod": "message_sign",
"verifiedAt": "2025-01-15T10:30:00Z",
"displayName": "My Node",
"avatarUrl": "/avatars/xxx.png",
"countryName": "United States",
"city": "San Francisco"
}
]
}Create and manage API keys for programmatic access.
| Scope | Description |
|---|---|
read:nodes |
Read node information |
read:stats |
Read network statistics |
read:leaderboard |
Read leaderboard data |
read:profiles |
Read node profiles |
List user's API keys (key values are masked).
Authentication: Required (session)
curl -H "Cookie: sb-xxx-auth-token=xxx" "https://nodes.example.com/api/keys"Response:
{
"keys": [
{
"id": "uuid",
"name": "Production Key",
"keyPrefix": "dingo_sk_abc12345",
"description": "For my dashboard",
"scopes": ["read:nodes", "read:stats"],
"rateLimit": 1000,
"lastUsedAt": "2025-01-20T15:00:00Z",
"requestCount": 5420,
"isActive": true,
"expiresAt": null,
"createdAt": "2025-01-01T00:00:00Z"
}
]
}Create a new API key.
Authentication: Required (session)
Request Body:
{
"name": "My API Key",
"description": "Optional description",
"scopes": ["read:nodes", "read:stats"],
"rateLimit": 1000,
"expiresAt": "2026-01-01T00:00:00Z"
}Response (201 Created):
{
"key": {
"id": "uuid",
"name": "My API Key",
"keyPrefix": "dingo_sk_abc12345",
"scopes": ["read:nodes", "read:stats"],
"rateLimit": 1000,
"isActive": true,
"createdAt": "2025-01-21T00:00:00Z"
},
"rawKey": "dingo_sk_abc12345xyzfullkeyhere",
"warning": "Store this key securely. It will not be shown again."
}Limits:
- Maximum 10 active API keys per user
- Rate limit: 10-10000 requests per hour
Delete an API key.
Authentication: Required (session)
curl -X DELETE "https://nodes.example.com/api/keys/{keyId}"Rotate an API key (revokes old key, creates new with same settings).
Authentication: Required (session)
curl -X POST "https://nodes.example.com/api/keys/{keyId}/rotate"Subscribe to node status change notifications.
List user's alert subscriptions.
Authentication: Required (session)
curl -H "Cookie: sb-xxx-auth-token=xxx" "https://nodes.example.com/api/alerts"Response:
{
"subscriptions": [
{
"id": "uuid",
"node_id": "uuid",
"alert_offline": true,
"alert_online": true,
"alert_version_outdated": false,
"alert_tier_change": false,
"email_enabled": true,
"webhook_enabled": true,
"webhook_url": "https://discord.com/api/webhooks/xxx",
"webhook_type": "discord",
"cooldown_minutes": 60,
"created_at": "2025-01-15T00:00:00Z",
"node": {
"id": "uuid",
"ip": "192.168.1.1",
"port": 33117,
"status": "up",
"country_name": "United States"
}
}
]
}Create a new alert subscription.
Authentication: Required (session)
Request Body:
{
"nodeId": "uuid",
"alertOffline": true,
"alertOnline": true,
"alertVersionOutdated": false,
"alertTierChange": false,
"emailEnabled": true,
"webhookEnabled": true,
"webhookUrl": "https://discord.com/api/webhooks/xxx/yyy",
"webhookType": "discord",
"cooldownMinutes": 60
}Notes:
nodeIdmust be a node you have verified ownership of- At least one notification channel (email or webhook) must be enabled
- Cooldown prevents duplicate alerts within the specified time window
Update an existing subscription.
Delete a subscription.
Unsubscribe from email alerts without logging in (token from email link).
Authentication: None (token-based)
curl "https://nodes.example.com/api/alerts/unsubscribe?token=64hexchars"Response:
{
"success": true,
"message": "You have been successfully unsubscribed from email alerts.",
"nodeInfo": {
"ip": "192.168.1.1",
"port": 33117
}
}Get user's alert history (sent notifications).
Authentication: Required (session)
Query Parameters:
limit: Max results (default: 50)offset: Pagination offset (default: 0)nodeId: Filter by specific node
Response:
{
"history": [
{
"id": "uuid",
"subscription_id": "uuid",
"node_id": "uuid",
"alert_type": "offline",
"email_sent": true,
"webhook_sent": true,
"message": "Node MyNode offline",
"created_at": "2025-01-20T15:30:00Z",
"node": {
"ip": "192.168.1.1",
"port": 33117,
"country_name": "United States"
}
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 125
}
}Manually register a node (if not discovered by crawler).
Authentication: Required (session)
Request Body:
{
"ip": "192.168.1.1",
"port": 33117
}Process:
- Validates IP and port format
- Probes the node to verify it's reachable (TCP connection test)
- If reachable, adds to database with
source: "manual" - Crawler will update full details on next pass
Response (201 Created):
{
"success": true,
"message": "Node registered successfully! The crawler will update its details shortly.",
"node": {
"id": "uuid",
"ip": "192.168.1.1",
"port": 33117,
"status": "up"
}
}Errors:
409 Conflict: Node already registered422 Unprocessable: Node not reachable
Get nodes registered by the authenticated user.
Authentication: Required (session)
Administrative endpoints for moderation and user management.
Authentication: Required (admin session - email must be in ADMIN_EMAILS or admin_users table)
Check if current user is an admin.
{
"isAdmin": true,
"role": "super_admin"
}Get moderation queue (pending verifications, profile changes, avatars).
Query Parameters:
status:pending,approved,rejected,all(default:pending)type:verification,profile,avatar,all(default:all)page,limit: Pagination
Response:
{
"items": [
{
"id": "uuid",
"item_type": "verification",
"item_id": "uuid",
"user_id": "uuid",
"user_email": "user@example.com",
"status": "pending",
"created_at": "2025-01-20T00:00:00Z",
"node_info": {
"ip": "192.168.1.1",
"port": 33117,
"country_name": "United States"
},
"verification_info": {
"method": "http_file",
"created_at": "2025-01-20T00:00:00Z"
}
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 15,
"pages": 1
}
}Review a moderation item.
Request Body:
{
"itemId": "uuid",
"action": "approve",
"notes": "Optional review notes"
}Actions: approve, reject, flag
List all users with admin management options.
Ban a user.
Get admin audit logs.
Get admin settings.
These endpoints are called by internal services (crawler, cron jobs). Protected by API keys set in environment variables.
Process pending alerts based on node status changes. Called by crawler after each pass.
Authentication: Bearer token (ALERTS_PROCESS_KEY env var)
curl -X POST -H "Authorization: Bearer $ALERTS_PROCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"checkMinutes": 10}' \
"https://nodes.example.com/api/alerts/process"Request Body:
{
"checkMinutes": 10
}Process:
- Finds nodes with status changes in the last N minutes
- Matches against alert subscriptions
- Sends email and/or webhook notifications
- Records alert history
- Respects cooldown settings
Response:
{
"processed": 5,
"sent": 3,
"details": ["192.168.1.1:offline:sub-uuid", "..."]
}Create a network snapshot for historical tracking. Deprecated - snapshots are now created automatically by the crawler.
Authentication: Bearer token (CRON_SECRET env var)
curl -X POST -H "Authorization: Bearer $CRON_SECRET" \
"https://nodes.example.com/api/cron/snapshots"Response:
{
"success": true,
"message": "Snapshot created",
"timestamp": "2025-01-21T00:00:00Z",
"totalNodes": 1234,
"onlineNodes": 1200
}Get the latest snapshot information.
Authentication: None
{
"lastSnapshot": "2025-01-21T00:00:00Z",
"totalNodes": 1234,
"onlineNodes": 1200
}Health check endpoint for monitoring.
Authentication: None
curl "https://nodes.example.com/api/health"Response:
{
"status": "healthy",
"timestamp": "2025-01-21T00:00:00Z"
}For issues or questions about the API:
- GitHub: RaxTzu/AtlasP2P
Last Updated: 2026-01-21 API Version: 1.1.0