{
  "openapi": "3.0.3",
  "info": {
    "title": "ISPData.io ISP Data API",
    "description": "Programmatic access to verified ISP availability data for the entire United States. Over 115 million US broadband serviceable locations covering all 50 states, DC, and 5 US territories, refreshed monthly. Includes 9 enrichment datasets: speed tests, provider performance, consumer complaints, broadband funding, demographics, cell towers, E-Rate, market analysis, and digital divide data.",
    "version": "1.0.0",
    "contact": {
      "name": "ISPData.io Support",
      "url": "https://ispdata.io/developer"
    },
    "license": {
      "name": "Commercial",
      "url": "https://ispdata.io/developer"
    }
  },
  "servers": [
    {
      "url": "https://api.ispdata.io/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    }
  ],
  "paths": {
    "/broadband/lookup": {
      "get": {
        "operationId": "lookupAddress",
        "summary": "Address Lookup",
        "description": "Look up broadband providers available at a specific geographic location. Uses H3 geospatial indexing (resolution 8, ~0.74 km² hexagons) with a 1-ring neighbor search for comprehensive coverage matching.",
        "tags": ["Broadband"],
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "description": "Latitude (-90 to 90)",
            "schema": {
              "type": "number",
              "format": "float",
              "minimum": -90,
              "maximum": 90
            },
            "example": 40.7128
          },
          {
            "name": "lng",
            "in": "query",
            "required": true,
            "description": "Longitude (-180 to 180)",
            "schema": {
              "type": "number",
              "format": "float",
              "minimum": -180,
              "maximum": 180
            },
            "example": -74.006
          },
          {
            "name": "resolution",
            "in": "query",
            "required": false,
            "description": "H3 resolution (7-9, default: 8)",
            "schema": {
              "type": "integer",
              "minimum": 7,
              "maximum": 9,
              "default": 8
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LookupResponse"
                },
                "example": {
                  "status": "success",
                  "data": {
                    "query": {
                      "lat": 40.7128,
                      "lng": -74.006,
                      "h3_cell": "882a100d25fffff",
                      "h3_resolution": 8
                    },
                    "provider_count": 12,
                    "providers": [
                      { "name": "Verizon", "coverage_cells": 7, "state_fips": "36" },
                      { "name": "Spectrum", "coverage_cells": 5, "state_fips": "36" },
                      { "name": "T-Mobile", "coverage_cells": 7, "state_fips": "36" }
                    ]
                  },
                  "meta": {
                    "response_time_ms": 23,
                    "data_source": "ISPData.io Verified Database",
                    "data_vintage": "2025-06-30"
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/broadband/bulk-lookup": {
      "post": {
        "operationId": "bulkLookup",
        "summary": "Bulk Lookup",
        "description": "Look up broadband providers for multiple locations in a single request. Maximum locations per request depends on your plan: Starter (25), Pro (50), Enterprise (100). Requires Starter plan or higher.",
        "tags": ["Broadband"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkLookupRequest"
              },
              "example": {
                "locations": [
                  { "lat": 40.7128, "lng": -74.006, "id": "nyc-office" },
                  { "lat": 34.0522, "lng": -118.2437, "id": "la-branch" },
                  { "lat": 41.8781, "lng": -87.6298, "id": "chicago-hq" }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful bulk lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkLookupResponse"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/broadband/coverage": {
      "get": {
        "operationId": "getCoverage",
        "summary": "Coverage Analysis",
        "description": "Get coverage statistics by state and/or provider. Returns the number of unique H3 cells covered, which can be used to estimate geographic coverage area. Requires Pro plan or higher.",
        "tags": ["Broadband"],
        "parameters": [
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "description": "2-digit FIPS code (e.g., '36' for New York)",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{2}$"
            },
            "example": "36"
          },
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "description": "Provider name filter",
            "schema": {
              "type": "string"
            },
            "example": "Verizon"
          }
        ],
        "responses": {
          "200": {
            "description": "Coverage statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoverageResponse"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/broadband/providers": {
      "get": {
        "operationId": "listProviders",
        "summary": "Provider List",
        "description": "List all unique broadband providers in the database, optionally filtered by state. Results are sorted by coverage area (number of H3 cells) in descending order.",
        "tags": ["Broadband"],
        "parameters": [
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "description": "2-digit FIPS code to filter by state",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{2}$"
            },
            "example": "06"
          }
        ],
        "responses": {
          "200": {
            "description": "List of providers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvidersResponse"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/speedtest/location": {
      "get": {
        "operationId": "getSpeedtestByLocation",
        "summary": "Speed Test Data by Location",
        "description": "Real-world speed test results aggregated by geographic location. Returns download/upload speeds, latency, jitter, and packet loss metrics with percentile breakdowns.",
        "tags": ["Speed & Performance"],
        "parameters": [
          { "name": "lat", "in": "query", "required": true, "description": "Latitude", "schema": { "type": "number" }, "example": 40.7128 },
          { "name": "lng", "in": "query", "required": true, "description": "Longitude", "schema": { "type": "number" }, "example": -74.006 },
          { "name": "period", "in": "query", "required": false, "description": "Time period: 7d, 30d, 90d", "schema": { "type": "string", "default": "30d" } }
        ],
        "responses": {
          "200": { "description": "Speed test results with percentile breakdowns and national/state comparisons" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/performance/provider": {
      "get": {
        "operationId": "getProviderPerformance",
        "summary": "Provider Performance Metrics",
        "description": "Network performance metrics by ISP including advertised vs measured speeds, latency, reliability, and speed label compliance.",
        "tags": ["Speed & Performance"],
        "parameters": [
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } },
          { "name": "provider", "in": "query", "required": false, "description": "Provider name filter", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Provider performance data with speed consistency scores" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/complaints/provider": {
      "get": {
        "operationId": "getComplaintsByProvider",
        "summary": "Consumer Complaints",
        "description": "Consumer complaint data by provider. Includes categories (billing, speed, outages), trends, satisfaction scores. Requires Starter plan+.",
        "tags": ["Consumer Data"],
        "parameters": [
          { "name": "provider", "in": "query", "required": false, "description": "Provider name filter", "schema": { "type": "string" } },
          { "name": "category", "in": "query", "required": false, "description": "Complaint category filter", "schema": { "type": "string" } },
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Complaint data with categories, trends, and resolution metrics" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/funding/area": {
      "get": {
        "operationId": "getFundingByArea",
        "summary": "Broadband Funding & Infrastructure",
        "description": "Federal broadband funding data (BEAD, RDOF, CAF-II, ACP, ReConnect, E-Rate). Requires Starter plan+.",
        "tags": ["Infrastructure"],
        "parameters": [
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } },
          { "name": "program", "in": "query", "required": false, "description": "Program code: BEAD, RDOF, CAF-II, ACP, ReConnect, E-Rate", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Funding program data with allocations and deployment status" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/demographics/internet-access": {
      "get": {
        "operationId": "getDemographics",
        "summary": "Internet Access Demographics",
        "description": "Internet adoption and digital divide metrics by geographic area. Requires Pro plan+.",
        "tags": ["Demographics"],
        "parameters": [
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } },
          { "name": "county_fips", "in": "query", "required": false, "description": "5-digit county FIPS", "schema": { "type": "string" } },
          { "name": "tract_id", "in": "query", "required": false, "description": "Tract ID", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Internet access demographics with digital divide indicators" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/towers/search": {
      "get": {
        "operationId": "searchTowers",
        "summary": "Cell Tower Search",
        "description": "Search cell towers and antenna infrastructure by location.",
        "tags": ["Infrastructure"],
        "parameters": [
          { "name": "lat", "in": "query", "required": true, "description": "Latitude", "schema": { "type": "number" }, "example": 40.7128 },
          { "name": "lng", "in": "query", "required": true, "description": "Longitude", "schema": { "type": "number" }, "example": -74.006 },
          { "name": "radius_km", "in": "query", "required": false, "description": "Search radius in km (default: 5)", "schema": { "type": "number", "default": 5 } }
        ],
        "responses": {
          "200": { "description": "Tower data with operator, technology, and density classification" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/erate/entities": {
      "get": {
        "operationId": "getErateEntities",
        "summary": "E-Rate Program Data",
        "description": "E-Rate funded school and library ISP data. Requires Pro plan+.",
        "tags": ["Infrastructure"],
        "parameters": [
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } },
          { "name": "entity_type", "in": "query", "required": false, "description": "school or library", "schema": { "type": "string", "enum": ["school", "library"] } },
          { "name": "zip", "in": "query", "required": false, "description": "ZIP code filter", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "E-Rate entity data with funding and connectivity details" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/market/analysis": {
      "get": {
        "operationId": "getMarketAnalysis",
        "summary": "Market Analysis & Competition",
        "description": "Broadband market competition data including HHI index, technology breakdown, pricing, and top providers. Requires Pro plan+.",
        "tags": ["Market Intelligence"],
        "parameters": [
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } },
          { "name": "county_fips", "in": "query", "required": false, "description": "5-digit county FIPS", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Market analysis with competition, technology, and pricing data" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/adoption/barriers": {
      "get": {
        "operationId": "getAdoptionBarriers",
        "summary": "Internet Adoption & Digital Divide",
        "description": "Internet adoption barriers and digital divide analysis. Requires Pro plan+.",
        "tags": ["Demographics"],
        "parameters": [
          { "name": "state_fips", "in": "query", "required": false, "description": "2-digit FIPS code", "schema": { "type": "string" } },
          { "name": "demographic", "in": "query", "required": false, "description": "Demographic group: income, age, education, geography", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Adoption data with demographic gaps and affordability programs" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/status": {
      "get": {
        "operationId": "getStatus",
        "summary": "API Status",
        "description": "Check API health, database status, and data statistics. This endpoint does not require authentication.",
        "tags": ["System"],
        "security": [],
        "responses": {
          "200": {
            "description": "API health status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusResponse"
                },
                "example": {
                  "status": "operational",
                  "version": "1.0.0",
                  "database": {
                    "status": "healthy",
                    "total_records": 115800000,
                    "states_covered": 56
                  },
                  "data_source": "ISPData.io Verified Database",
                  "data_vintage": "2025-06-30",
                  "documentation": "/developer/docs"
                }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key obtained from the ISPData.io developer dashboard"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "API key passed as query parameter (less secure)"
      }
    },
    "schemas": {
      "Provider": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "Provider name" },
          "coverage_cells": { "type": "integer", "description": "Number of H3 cells covered" },
          "state_fips": { "type": "string", "description": "2-digit state FIPS code" }
        }
      },
      "Meta": {
        "type": "object",
        "properties": {
          "response_time_ms": { "type": "integer", "description": "Server response time in milliseconds" },
          "data_source": { "type": "string" },
          "data_vintage": { "type": "string", "format": "date" }
        }
      },
      "LookupResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["success"] },
          "data": {
            "type": "object",
            "properties": {
              "query": {
                "type": "object",
                "properties": {
                  "lat": { "type": "number" },
                  "lng": { "type": "number" },
                  "h3_cell": { "type": "string" },
                  "h3_resolution": { "type": "integer" }
                }
              },
              "provider_count": { "type": "integer" },
              "providers": {
                "type": "array",
                "items": { "$ref": "#/components/schemas/Provider" }
              }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "BulkLookupRequest": {
        "type": "object",
        "required": ["locations"],
        "properties": {
          "locations": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["lat", "lng"],
              "properties": {
                "lat": { "type": "number", "minimum": -90, "maximum": 90 },
                "lng": { "type": "number", "minimum": -180, "maximum": 180 },
                "id": { "type": "string", "description": "Optional client-provided identifier" }
              }
            }
          }
        }
      },
      "BulkLookupResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["success"] },
          "data": {
            "type": "object",
            "properties": {
              "location_count": { "type": "integer" },
              "results": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "lat": { "type": "number" },
                    "lng": { "type": "number" },
                    "h3_cell": { "type": "string" },
                    "provider_count": { "type": "integer" },
                    "providers": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Provider" }
                    }
                  }
                }
              }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "CoverageResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["success"] },
          "data": {
            "type": "object",
            "properties": {
              "state_fips": { "type": "string" },
              "provider_count": { "type": "integer" },
              "providers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": { "type": "string" },
                    "h3_cells": { "type": "integer" }
                  }
                }
              }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "ProvidersResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["success"] },
          "data": {
            "type": "object",
            "properties": {
              "provider_count": { "type": "integer" },
              "providers": {
                "type": "array",
                "items": { "$ref": "#/components/schemas/Provider" }
              }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "StatusResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["operational", "degraded", "down"] },
          "version": { "type": "string" },
          "database": {
            "type": "object",
            "properties": {
              "status": { "type": "string" },
              "total_records": { "type": "integer" },
              "states_covered": { "type": "integer" }
            }
          },
          "data_source": { "type": "string" },
          "data_vintage": { "type": "string", "format": "date" },
          "documentation": { "type": "string" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "message": { "type": "string" },
          "retry_after": { "type": "integer" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": {
              "error": "invalid_parameters",
              "message": "Missing required parameter: lat"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required or invalid API key",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": {
              "error": "authentication_required",
              "message": "No API key provided. Include X-API-Key header or api_key query parameter."
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient plan or inactive subscription",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": {
              "error": "plan_upgrade_required",
              "message": "This endpoint requires a Starter plan or higher."
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": {
              "error": "rate_limit_exceeded",
              "message": "Rate limit of 60 requests/minute exceeded. Try again in 45 seconds.",
              "retry_after": 45
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": {
              "error": "internal_error",
              "message": "An unexpected error occurred. Please try again later."
            }
          }
        }
      }
    }
  }
}
