{
  "openapi": "3.0.3",
  "info": {
    "title": "AddressAPI — Address Validation & Property Intelligence",
    "description": "Validate, standardize, and enrich any US address. USPS-format validation, deliverability checks, geocoding, and 30+ property data sources. 80% cheaper than Google or SmartyStreets.",
    "version": "2.0.0",
    "contact": {
      "name": "PortofCams",
      "url": "https://addressapi.portofcams.com"
    }
  },
  "servers": [
    {
      "url": "https://addressapi.portofcams.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/v1/enrich": {
      "get": {
        "summary": "Enrich Address",
        "description": "Returns property taxes, flood zones, demographics, walkability, crime risk, school districts, natural hazards, and broadband data for a US address.",
        "operationId": "enrichAddress",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "Full US street address (e.g. '1000 Ocean Drive, Miami Beach, FL 33139')",
            "schema": { "type": "string", "minLength": 5 }
          }
        ],
        "security": [{ "ApiKeyHeader": [] }],
        "responses": {
          "200": {
            "description": "Enriched address data from 9 sources",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EnrichResponse" }
              }
            }
          },
          "400": { "description": "Missing or invalid address parameter" },
          "401": { "description": "Missing or invalid API key" },
          "404": { "description": "Address not found" },
          "429": { "description": "Monthly limit reached" }
        }
      }
    },
    "/v1/batch": {
      "post": {
        "summary": "Batch Enrich",
        "description": "Enrich up to 100 addresses in a single request. Results processed in parallel.",
        "operationId": "batchEnrich",
        "security": [{ "ApiKeyHeader": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["addresses"],
                "properties": {
                  "addresses": {
                    "type": "array",
                    "items": { "type": "string" },
                    "maxItems": 100,
                    "description": "Array of US street addresses"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch results",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/BatchResponse" }
              }
            }
          },
          "400": { "description": "Invalid request body" },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Batch exceeds remaining quota" }
        }
      }
    },
    "/v1/validate": {
      "get": {
        "summary": "Validate Address",
        "description": "Validate and standardize a US address. Returns USPS-format components, deliverability status, coordinates, and address type. Fast — typically under 200ms for cached addresses.",
        "operationId": "validateAddressGet",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "Full US street address (e.g. '350 5th Ave, New York, NY 10118')",
            "schema": { "type": "string", "minLength": 5 }
          }
        ],
        "security": [{ "ApiKeyHeader": [] }],
        "responses": {
          "200": {
            "description": "Validation result",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidateResponse" }
              }
            }
          },
          "400": { "description": "Missing or invalid address" },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Rate or monthly limit exceeded" }
        }
      },
      "post": {
        "summary": "Validate Address (Structured)",
        "description": "Validate using structured address components or a freeform string.",
        "operationId": "validateAddressPost",
        "security": [{ "ApiKeyHeader": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": { "type": "string", "description": "Freeform address string" },
                  "street": { "type": "string", "description": "Street address line" },
                  "city": { "type": "string" },
                  "state": { "type": "string", "description": "State abbreviation (e.g. NY)" },
                  "zip": { "type": "string", "description": "5-digit ZIP code" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidateResponse" }
              }
            }
          },
          "400": { "description": "Invalid input" },
          "401": { "description": "Missing or invalid API key" }
        }
      }
    },
    "/v1/validate/batch": {
      "post": {
        "summary": "Batch Validate",
        "description": "Validate up to 1,000 addresses. Batches of 50 or less are processed synchronously. Larger batches return a job ID for async polling.",
        "operationId": "batchValidate",
        "security": [{ "ApiKeyHeader": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["addresses"],
                "properties": {
                  "addresses": {
                    "type": "array",
                    "items": { "type": "string" },
                    "maxItems": 1000,
                    "description": "Array of addresses to validate"
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL to POST results when batch completes (for async batches >50)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Synchronous batch results (<=50 addresses)" },
          "202": { "description": "Async batch accepted. Poll job_id for results." },
          "400": { "description": "Invalid request" },
          "429": { "description": "Batch exceeds remaining quota" }
        }
      }
    },
    "/v1/validate/batch/{jobId}": {
      "get": {
        "summary": "Get Batch Job Status",
        "description": "Poll the status and results of an async batch validation job.",
        "operationId": "getBatchJob",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "security": [{ "ApiKeyHeader": [] }],
        "responses": {
          "200": { "description": "Job status and results (if completed)" },
          "404": { "description": "Job not found" }
        }
      }
    },
    "/v1/signup": {
      "post": {
        "summary": "Get Free API Key",
        "description": "Create a free API key (100 lookups/month).",
        "operationId": "signup",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "API key created" },
          "400": { "description": "Invalid email" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "schemas": {
      "EnrichResponse": {
        "type": "object",
        "properties": {
          "address": { "type": "string" },
          "coordinates": {
            "type": "object",
            "properties": {
              "lat": { "type": "number" },
              "lon": { "type": "number" }
            }
          },
          "location": { "type": "object" },
          "flood": { "type": "object" },
          "demographics": { "type": "object" },
          "property": { "type": "object" },
          "schools": { "type": "object" },
          "walkability": { "type": "object" },
          "crime": { "type": "object" },
          "broadband": { "type": "object" },
          "hazards": { "type": "array", "items": { "type": "string" } },
          "hazard_details": { "type": "object" }
        }
      },
      "ValidateResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["validated", "not_found", "undeliverable", "invalid_input"], "description": "Validation result status" },
          "deliverability": { "type": "string", "enum": ["deliverable", "no_match"], "description": "Whether the address is deliverable" },
          "address_type": { "type": "string", "enum": ["street_address", "po_box", null], "description": "Type of address" },
          "input": { "type": "string", "description": "Original input address" },
          "standardized": {
            "type": "object",
            "properties": {
              "line1": { "type": "string", "description": "Street address line" },
              "line2": { "type": "string", "nullable": true, "description": "Secondary unit (apt, suite, etc.)" },
              "city": { "type": "string" },
              "state": { "type": "string", "description": "2-letter state abbreviation" },
              "state_name": { "type": "string" },
              "zip_code": { "type": "string" },
              "formatted": { "type": "string", "description": "Full USPS-formatted address" }
            }
          },
          "components": {
            "type": "object",
            "properties": {
              "number": { "type": "string" },
              "predirectional": { "type": "string", "nullable": true },
              "street": { "type": "string" },
              "suffix": { "type": "string", "nullable": true },
              "postdirectional": { "type": "string", "nullable": true },
              "secondary": { "type": "string", "nullable": true },
              "city": { "type": "string" },
              "state": { "type": "string" },
              "zip_code": { "type": "string" },
              "county": { "type": "string", "nullable": true }
            }
          },
          "coordinates": {
            "type": "object",
            "properties": {
              "lat": { "type": "number" },
              "lon": { "type": "number" }
            }
          },
          "metadata": {
            "type": "object",
            "properties": {
              "census_fips": { "type": "string" },
              "tiger_line_id": { "type": "string" },
              "tiger_side": { "type": "string" },
              "corrected": { "type": "boolean" }
            }
          },
          "_latency_ms": { "type": "integer" },
          "_cached": { "type": "boolean" }
        }
      },
      "BatchResponse": {
        "type": "object",
        "properties": {
          "total": { "type": "integer" },
          "successful": { "type": "integer" },
          "failed": { "type": "integer" },
          "results": { "type": "array" }
        }
      }
    }
  }
}
