{
  "openapi": "3.1.0",
  "info": {
    "title": "Bare Public Provider Directory",
    "version": "1.3.0",
    "description": "Saved opt-in website observations. Hosting, cloud, network and CDN are separate roles. No exhaustive coverage or hosting-contract guarantee. Entries expire or can be withdrawn; reads never scan. IPinfo-derived data: IPinfo Lite, CC BY-SA 4.0. Preserve attribution and source terms."
  },
  "servers": [
    {
      "url": "https://bare.io"
    }
  ],
  "paths": {
    "/api/hosting-directory": {
      "get": {
        "summary": "Read saved public provider observations",
        "security": [],
        "description": "60 requests/IP/fixed minute; 10,000 shared reads/UTC day. Server HTTPS requests; cross-origin browser requests are not enabled. Filters appear at most once; unknown filters are rejected.",
        "parameters": [
          {
            "name": "role",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hosting",
                "cloud",
                "network",
                "cdn"
              ]
            }
          },
          {
            "name": "provider",
            "in": "query",
            "description": "Exact observed provider name, case-insensitive for ASCII.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Hostname or provider substring.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 209,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ready or empty saved data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Directory"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Limited"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "summary": "Withdraw a listing using its private removal token",
        "security": [],
        "description": "Ten requests/IP/minute. Use only from Bare's removal page or your server. The token identifies the managed listing; id is the hostname hint saved before redirects. Never place the token in a query string or logs.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id",
                  "token"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "maxLength": 253
                  },
                  "token": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{43}$",
                    "writeOnly": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listing removed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "removed": {
                      "const": true
                    }
                  },
                  "required": [
                    "removed"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Limited"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/hosting-overview": {
      "get": {
        "summary": "Read current opt-in provider counts by layer",
        "security": [],
        "description": "No live scan. Shared directory read quotas: 60/minute/IP, 10000/day. Layers and providers overlap. Current sample only, no historical or worldwide market-share claims. Percentages suppressed below 100 role sites. 24 providers per page including reviewed zero-observation providers.",
        "parameters": [
          {
            "name": "role",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hosting",
                "cloud",
                "network",
                "cdn"
              ],
              "default": "hosting"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 999,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counts, role denominator, per-provider confidence counts, latestObservedAt, profile/company links, scope and IPinfo attribution."
          },
          "400": {
            "description": "Invalid filters"
          },
          "429": {
            "description": "Read limit; Retry-After supplied"
          },
          "503": {
            "description": "Data unavailable, not an empty dataset"
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Error": {
        "description": "Request rejected or unavailable; never interpret as an empty result",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error",
                "code"
              ],
              "properties": {
                "error": {
                  "type": "string"
                },
                "code": {
                  "type": "string"
                },
                "returnedAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "Limited": {
        "description": "Limit reached; wait before retrying",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Seconds before retry"
          }
        }
      }
    },
    "schemas": {
      "Layer": {
        "type": "object",
        "required": [
          "key",
          "role",
          "provider",
          "confidence",
          "evidence"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "role": {
            "enum": [
              "hosting",
              "cloud",
              "network",
              "cdn"
            ]
          },
          "provider": {
            "type": "string",
            "maxLength": 100
          },
          "confidence": {
            "enum": [
              "high",
              "medium",
              "inferred",
              "unknown"
            ]
          },
          "evidence": {
            "type": "object",
            "required": [
              "summary",
              "sources"
            ],
            "properties": {
              "summary": {
                "type": "string"
              },
              "sources": {
                "type": "array",
                "maxItems": 8,
                "items": {
                  "type": "object",
                  "required": [
                    "label",
                    "url"
                  ],
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Listing": {
        "type": "object",
        "required": [
          "id",
          "hostname",
          "origin",
          "layers",
          "firstSeenAt",
          "observedAt",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "origin": {
            "type": "string",
            "format": "uri"
          },
          "layers": {
            "type": "array",
            "maxItems": 12,
            "items": {
              "$ref": "#/components/schemas/Layer"
            }
          },
          "ipNetworkAnswer": {
            "$ref": "#/components/schemas/IpNetworkAnswer",
            "description": "Optional separate low-confidence network clue; never an ordinary hosting layer."
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "observedAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "IpNetworkAnswer": {
        "type": "object",
        "additionalProperties": false,
        "required": ["version","attributionTier","confidence","category","providerId","provider","label","summary","asn","observedAt","networkObservedAt","derivedAt","expiresAt","ruleId","catalogVersion","sources"],
        "properties": {
          "version": {"const": 1},
          "attributionTier": {"const": "ip-network"},
          "confidence": {"const": "low"},
          "category": {"type":"string","enum":["brand","server","cloud"]},
          "providerId": {"type":"string"}, "provider": {"type":"string"}, "label": {"type":"string"}, "summary": {"type":"string"},
          "asn": {"type":"string","pattern":"^AS[1-9][0-9]{0,9}$"},
          "observedAt": {"type":"string","format":"date-time"}, "networkObservedAt": {"type":"string","format":"date-time"},
          "derivedAt": {"type":"string","format":"date-time"}, "expiresAt": {"type":"string","format":"date-time"},
          "ruleId": {"type":"string"}, "catalogVersion": {"type":"string"},
          "sources": {"type":"array","minItems":1,"maxItems":8,"items":{"type":"object","additionalProperties":false,"required":["label","url"],"properties":{"label":{"type":"string"},"url":{"type":"string","format":"uri","pattern":"^https:"}}}}
        }
      },
      "Directory": {
        "type": "object",
        "required": [
          "version",
          "status",
          "entries",
          "page",
          "pageSize",
          "hasMore",
          "total",
          "facets",
          "generatedAt",
          "scope",
          "attribution"
        ],
        "properties": {
          "version": {
            "const": 1
          },
          "status": {
            "enum": [
              "ready",
              "empty"
            ]
          },
          "entries": {
            "type": "array",
            "maxItems": 24,
            "items": {
              "$ref": "#/components/schemas/Listing"
            }
          },
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "const": 24
          },
          "hasMore": {
            "type": "boolean"
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "facets": {
            "type": "object",
            "properties": {
              "roles": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "providers": {
                "type": "array",
                "maxItems": 100,
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "scope": {
            "type": "string"
          },
          "attribution": {
            "type": "object"
          }
        }
      }
    }
  }
}
