openapi: 3.0.3 info: title: P2NS Admin API description: | REST API for managing the P2NS (Peer-to-Peer Name System) decentralized DNS system. Provides endpoints for domain management, Holesail servers/clients, local DNS records, certificates, virtual interfaces, and system monitoring. version: 1.0.0 contact: name: P2NS Support url: https://git.ssh.surf/snxraven/p2ns servers: - url: https://p2ns.admin description: P2NS Admin Interface tags: - name: System description: System status and health endpoints - name: Domains description: Domain management endpoints - name: Holesail description: Holesail server and client management - name: DNS description: Local DNS record management - name: Certificates description: Certificate management - name: Interfaces description: Virtual interface management - name: Settings description: Configuration management - name: Backups description: Backup and restore operations - name: Diagnostics description: Network diagnostics and testing tools - name: Metrics description: System metrics and monitoring - name: Consensus description: Consensus and voting endpoints - name: Subscriptions description: Service subscription management endpoints paths: /api/health: get: tags: - System summary: Health check endpoint description: | Returns system health status. Supports liveness and readiness probes. - Liveness: Checks if process is alive - Readiness: Checks if services are ready to accept traffic parameters: - name: probe in: query schema: type: string enum: [liveness, readiness] default: liveness description: Type of health probe responses: '200': description: System is healthy content: application/json: schema: $ref: '#/components/schemas/HealthStatus' '503': description: System is degraded or not ready content: application/json: schema: $ref: '#/components/schemas/HealthStatus' /api/status: get: tags: - System summary: Get system status responses: '200': description: System status content: application/json: schema: $ref: '#/components/schemas/Status' /api/stats: get: tags: - Metrics summary: Get system metrics responses: '200': description: System metrics content: application/json: schema: $ref: '#/components/schemas/Metrics' /api/stats/historical: get: tags: - Metrics summary: Get historical metrics parameters: - name: minutes in: query schema: type: integer minimum: 1 maximum: 1440 default: 60 description: Time range in minutes responses: '200': description: Historical metrics data content: application/json: schema: $ref: '#/components/schemas/HistoricalMetrics' /api/resolved-domains: get: tags: - Domains summary: List all resolved domains responses: '200': description: List of domains content: application/json: schema: type: array items: $ref: '#/components/schemas/Domain' /api/add-domain: post: tags: - Domains summary: Add a domain requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddDomainRequest' responses: '200': description: Domain added successfully content: text/plain: schema: type: string example: OK '500': description: Error adding domain /api/remove-domain: post: tags: - Domains summary: Remove a domain requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RemoveDomainRequest' responses: '200': description: Domain removed successfully content: text/plain: schema: type: string example: OK '500': description: Error removing domain /api/holesail-servers: get: tags: - Holesail summary: List Holesail servers responses: '200': description: List of servers content: application/json: schema: type: array items: $ref: '#/components/schemas/HolesailServer' /api/holesail-create: post: tags: - Holesail summary: Create a Holesail server requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateHolesailServerRequest' responses: '200': description: Server created content: application/json: schema: type: object properties: id: type: string /api/holesail-client-create: post: tags: - Holesail summary: Create a Holesail client description: Creates a new Holesail client for a domain and port. If serviceName is provided, the client ID will be domain_servicename. The client is added to the domain's claim record clients array. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateHolesailClientRequest' responses: '200': description: Client created content: application/json: schema: type: object properties: id: type: string '400': description: Invalid request (missing required fields or domain not owned) '500': description: Failed to create Holesail client /api/local-dns: get: tags: - DNS summary: Get local DNS records and conflicts responses: '200': description: DNS records and conflicts content: application/json: schema: $ref: '#/components/schemas/LocalDNS' /api/add-local-dns: post: tags: - DNS summary: Add a local DNS record requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DNSRecord' responses: '200': description: Record added content: text/plain: schema: type: string example: OK /api/certs: get: tags: - Certificates summary: List certificates responses: '200': description: List of domains with certificates content: application/json: schema: type: array items: type: string /api/generate-cert: post: tags: - Certificates summary: Generate a certificate requestBody: required: true content: application/json: schema: type: object properties: domain: type: string responses: '200': description: Certificate generated content: text/plain: schema: type: string example: OK /api/backups: get: tags: - Backups summary: List all backups responses: '200': description: List of backups content: application/json: schema: type: array items: $ref: '#/components/schemas/Backup' /api/backups/create: post: tags: - Backups summary: Create manual backup responses: '200': description: Backup created content: application/json: schema: $ref: '#/components/schemas/BackupCreateResponse' /api/backups/restore: post: tags: - Backups summary: Restore from backup requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RestoreBackupRequest' responses: '200': description: Backup restored content: application/json: schema: $ref: '#/components/schemas/BackupRestoreResponse' /api/backups/{id}: delete: tags: - Backups summary: Delete backup parameters: - name: id in: path required: true schema: type: string description: Backup name responses: '200': description: Backup deleted content: application/json: schema: type: object properties: success: type: boolean message: type: string /api/network-interfaces: get: tags: - Settings summary: Get available network interfaces description: | Retrieves a list of available network interfaces on the system. Used by the admin interface to populate the Subnet Interface Name dropdown setting. Interfaces are sorted with loopback interfaces and OS-specific defaults prioritized first. responses: '200': description: List of available network interfaces content: application/json: schema: type: object properties: interfaces: type: array items: type: object properties: value: type: string description: Interface name (e.g., "lo0", "lo", "eth0") example: "lo0" label: type: string description: Display label for the interface (may include "(default)" for OS default) example: "lo0" '500': description: Failed to fetch network interfaces content: application/json: schema: type: object properties: error: type: string /api/backups/{id}/metadata: get: tags: - Backups summary: Get backup metadata parameters: - name: id in: path required: true schema: type: string description: Backup name responses: '200': description: Backup metadata content: application/json: schema: $ref: '#/components/schemas/BackupMetadata' '404': description: Backup not found /api/diagnostics/dns-lookup: post: tags: - Diagnostics summary: DNS lookup diagnostic requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DNSLookupRequest' responses: '200': description: DNS lookup result content: application/json: schema: $ref: '#/components/schemas/DNSLookupResponse' /api/diagnostics/ping: post: tags: - Diagnostics summary: Ping diagnostic requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PingRequest' responses: '200': description: Ping result (non-streaming) or NDJSON stream (streaming) content: application/json: schema: $ref: '#/components/schemas/PingResponse' application/x-ndjson: schema: $ref: '#/components/schemas/PingStreamResponse' /api/diagnostics/traceroute: post: tags: - Diagnostics summary: Traceroute diagnostic requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TracerouteRequest' responses: '200': description: Traceroute result (non-streaming) or NDJSON stream (streaming) content: application/json: schema: $ref: '#/components/schemas/TracerouteResponse' application/x-ndjson: schema: $ref: '#/components/schemas/TracerouteStreamResponse' /api/diagnostics/connection-test: post: tags: - Diagnostics summary: Connection test requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ConnectionTestRequest' responses: '200': description: Connection test result content: application/json: schema: $ref: '#/components/schemas/ConnectionTestResponse' /api/diagnostics/bandwidth: get: tags: - Diagnostics summary: Network interface bandwidth information responses: '200': description: Network interface information content: application/json: schema: $ref: '#/components/schemas/BandwidthResponse' /api/consensus/{domain}: get: tags: - Consensus summary: Get consensus state for a domain parameters: - name: domain in: path required: true schema: type: string description: The domain name responses: '200': description: Consensus state content: application/json: schema: $ref: '#/components/schemas/ConsensusState' '500': description: Failed to get consensus state /api/consensus/metrics: get: tags: - Consensus summary: Get consensus metrics responses: '200': description: Consensus metrics content: application/json: schema: $ref: '#/components/schemas/ConsensusMetrics' '500': description: Failed to get consensus metrics /api/consensus/recalculate: post: tags: - Consensus summary: Force consensus recalculation for all domains responses: '200': description: Recalculation triggered content: application/json: schema: $ref: '#/components/schemas/RecalculateResponse' '500': description: Failed to recalculate consensus /api/consensus/recalculate/{domain}: post: tags: - Consensus summary: Force consensus recalculation for a specific domain parameters: - name: domain in: path required: true schema: type: string description: The domain name responses: '200': description: Recalculation triggered content: application/json: schema: $ref: '#/components/schemas/RecalculateResponse' '500': description: Failed to recalculate consensus /api/domain-services: get: tags: - Subscriptions summary: Get services for a domain parameters: - name: domain in: query required: true schema: type: string description: The domain name responses: '200': description: List of services for the domain content: application/json: schema: type: array items: $ref: '#/components/schemas/DomainService' '400': description: Missing domain parameter '500': description: Failed to fetch domain services /api/service-subscriptions: get: tags: - Subscriptions summary: List all service subscriptions responses: '200': description: List of subscriptions content: application/json: schema: type: array items: $ref: '#/components/schemas/ServiceSubscription' '500': description: Failed to fetch subscriptions /api/subscribe-all-domains: get: tags: - Subscriptions summary: List domains with subscribe-all enabled responses: '200': description: List of domains content: application/json: schema: type: array items: type: string '500': description: Failed to fetch subscribe-all domains /api/service-subscribe: post: tags: - Subscriptions summary: Subscribe to a service requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ServiceSubscribeRequest' responses: '200': description: Successfully subscribed content: application/json: schema: type: object properties: success: type: boolean '400': description: Missing required fields '409': description: Already subscribed to this service '500': description: Failed to subscribe /api/service-unsubscribe: post: tags: - Subscriptions summary: Unsubscribe from a service requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ServiceUnsubscribeRequest' responses: '200': description: Successfully unsubscribed content: application/json: schema: type: object properties: success: type: boolean '400': description: Missing required fields '404': description: Subscription not found '500': description: Failed to unsubscribe /api/subscribe-all: post: tags: - Subscriptions summary: Enable subscribe-all for a domain requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SubscribeAllRequest' responses: '200': description: Successfully enabled subscribe-all content: application/json: schema: type: object properties: success: type: boolean '400': description: Missing domain field '500': description: Failed to set subscribe-all /api/unsubscribe-all: post: tags: - Subscriptions summary: Disable subscribe-all for a domain requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SubscribeAllRequest' responses: '200': description: Successfully disabled subscribe-all content: application/json: schema: type: object properties: success: type: boolean '400': description: Missing domain field '500': description: Failed to clear subscribe-all components: schemas: HealthStatus: type: object properties: status: type: string enum: [healthy, degraded, not_ready] timestamp: type: string format: date-time uptime: type: integer probe: type: string services: type: object dependencies: type: object Status: type: object properties: isMaster: type: boolean isConnected: type: boolean peersCount: type: integer Domain: type: object properties: domain: type: string hash: type: string isLocal: type: boolean description: Whether the local writer has a claim for this domain isOwner: type: boolean description: Whether the local writer is the resolved claimant (owner) of this domain consensusState: $ref: '#/components/schemas/ConsensusState' description: Detailed consensus information for this domain consensusStatus: type: string enum: [resolved, conflict, insufficient_quorum, tie, no_claims, error, internal] description: Simplified consensus status, may include 'conflict' for domains where local peer has claim but another claimant won services: type: array items: $ref: '#/components/schemas/DomainService' description: Array of services configured for this domain AddDomainRequest: type: object required: - domain - hash properties: domain: type: string description: Domain name to add hash: type: string description: Holesail connection hash (e.g., hs://...) ssl: type: boolean default: false description: Whether the Holesail connection uses SSL/TLS. When true, proxy connections will use HTTPS/WSS instead of HTTP/WS. RemoveDomainRequest: type: object required: - domain properties: domain: type: string HolesailServer: type: object properties: id: type: string opts: type: object info: type: object CreateHolesailServerRequest: type: object properties: name: type: string port: type: integer host: type: string secure: type: boolean udp: type: boolean log: type: integer domain: type: string CreateHolesailClientRequest: type: object required: - domain - key - port properties: domain: type: string description: Domain name (must be owned by local writer) key: type: string description: Holesail connection hash (e.g., hs://s00084bf...) port: type: integer description: Port number serviceName: type: string description: Service name for naming the client (format: domain_servicename) protocol: type: string enum: [tcp, udp] default: tcp description: Protocol type LocalDNS: type: object properties: records: type: array items: type: object conflicts: type: array items: type: object DNSRecord: type: object properties: name: type: string type: type: string ttl: type: integer data: type: string Metrics: type: object description: Comprehensive system metrics properties: requests: type: object properties: total: type: integer successful: type: integer failed: type: integer successRate: type: number avgResponseTime: type: number holesailChildren: type: array items: type: object HistoricalMetrics: type: object description: Historical metrics data properties: timestamp: type: string format: date-time data: type: object Backup: type: object properties: name: type: string timestamp: type: string format: date-time size: type: integer sizeFormatted: type: string fileCount: type: integer BackupCreateResponse: type: object properties: success: type: boolean path: type: string RestoreBackupRequest: type: object required: - backupName properties: backupName: type: string BackupRestoreResponse: type: object properties: success: type: boolean message: type: string BackupMetadata: type: object properties: timestamp: type: string format: date-time files: type: array items: type: object properties: name: type: string size: type: integer sizeFormatted: type: string modified: type: string format: date-time DNSLookupRequest: type: object required: - domain properties: domain: type: string type: type: string enum: [A, AAAA, MX, TXT, NS, CNAME, SRV, PTR, SOA] default: A DNSLookupResponse: type: object properties: success: type: boolean domain: type: string type: type: string results: type: array items: type: string responseTime: type: integer PingRequest: type: object required: - target properties: target: type: string count: type: integer default: 4 stream: type: boolean default: false PingResponse: type: object properties: success: type: boolean target: type: string count: type: integer output: type: string error: type: string responseTime: type: integer PingStreamResponse: type: object properties: type: type: string enum: [output, error, complete] data: type: string timestamp: type: integer success: type: boolean exitCode: type: integer TracerouteRequest: type: object required: - target properties: target: type: string stream: type: boolean default: false TracerouteResponse: type: object properties: success: type: boolean target: type: string output: type: string error: type: string responseTime: type: integer TracerouteStreamResponse: type: object properties: type: type: string enum: [output, error, complete] data: type: string timestamp: type: integer success: type: boolean exitCode: type: integer ConnectionTestRequest: type: object required: - domain - port properties: domain: type: string port: type: integer ConnectionTestResponse: type: object properties: success: type: boolean domain: type: string ip: type: string port: type: integer latency: type: integer error: type: string responseTime: type: integer BandwidthResponse: type: object properties: interfaces: type: object additionalProperties: type: object properties: name: type: string addresses: type: array items: type: object note: type: string responseTime: type: integer ConsensusState: type: object description: Consensus state for a domain properties: status: type: string enum: [resolved, insufficient_quorum, tie, no_claims, error] description: Consensus status hash: type: string nullable: true description: Resolved Holesail hash if status is resolved resolvedClaimant: type: string nullable: true description: Public key of winning claimant if resolved voteCounts: type: object additionalProperties: type: integer description: Mapping of claimant public keys to vote counts activePeers: type: integer description: Number of active peers in network (including local node) quorumMet: type: boolean description: Whether quorum threshold has been met minVotes: type: integer description: Minimum votes required to meet quorum totalVotes: type: integer description: Total number of votes cast for all claimants lastResolution: type: integer nullable: true description: Timestamp of last resolution, or null if never resolved error: type: string description: Error message if status is error ConsensusState: type: object description: Detailed consensus state for a specific domain properties: status: type: string enum: [resolved, conflict, insufficient_quorum, tie, no_claims, error] description: Current consensus status hash: type: string description: Resolved hash for the domain (null if not resolved) resolvedClaimant: type: string description: Public key of the resolved claimant (null if not resolved) voteCounts: type: object additionalProperties: type: integer description: Vote counts per claimant (claimant -> vote count) activePeers: type: integer description: Number of active peers in the network quorumMet: type: boolean description: Whether quorum requirements were met minVotes: type: integer description: Minimum votes required for quorum totalVotes: type: integer description: Total votes cast for this domain lastResolution: type: integer description: Timestamp of last resolution attempt ConsensusMetrics: type: object description: Overall consensus metrics properties: resolutions: type: integer description: Total number of successful domain resolutions quorumFailures: type: integer description: Number of times quorum was not met ties: type: integer description: Number of ties that required tie-breaking validationFailures: type: integer description: Number of invalid votes that were rejected totalVotes: type: integer description: Total number of votes cast across all domains avgVotesPerDomain: type: number description: Average number of votes per domain domainResolutions: type: array items: type: object properties: domain: type: string resolved: type: integer description: Number of successful resolutions for this domain failed: type: integer description: Number of failed resolutions for this domain description: Per-domain resolution statistics RecalculateResponse: type: object description: Response from consensus recalculation request properties: success: type: boolean description: Whether recalculation was triggered successfully message: type: string description: Status message DomainService: type: object description: Service information for a domain properties: serviceName: type: string description: Unique identifier for the service key: type: string description: Holesail connection hash port: type: integer description: Port number for the service protocol: type: string enum: [tcp, udp] description: Protocol type ServiceSubscription: type: object description: Service subscription information properties: domain: type: string description: Domain name serviceName: type: string description: Service identifier key: type: string description: Holesail connection hash port: type: integer description: Port number protocol: type: string enum: [tcp, udp] description: Protocol type ServiceSubscribeRequest: type: object required: - domain - serviceName - key - port properties: domain: type: string description: Domain name serviceName: type: string description: Service identifier key: type: string description: Holesail connection hash port: type: integer description: Port number protocol: type: string enum: [tcp, udp] default: tcp description: Protocol type ServiceUnsubscribeRequest: type: object required: - domain - serviceName properties: domain: type: string description: Domain name serviceName: type: string description: Service identifier SubscribeAllRequest: type: object required: - domain properties: domain: type: string description: Domain name