openapi: 3.1.0
info:
  title: zipcodestack
  version: "1"
  summary: Worldwide postal / zip code lookup, distance, radius and geometry queries.
  description: >-
    zipcodestack resolves postal (zip) codes worldwide to location data and
    supports distance, radius, polygon, city/state and coverage queries. All
    endpoints are served over HTTPS and return JSON. Authenticate every request
    with your API key, either as the `apikey` query parameter or the `apikey`
    request header.


    This document is generated from the zipcodestack service implementation and
    is the machine-readable source of truth for the v1 REST API. A human-readable
    version is available at https://zipcodestack.com/docs.


    Note: for these endpoints a missing required parameter currently returns
    HTTP 200 with an error-shaped body (e.g. `{"code": "required", "info": ...}`)
    rather than a 4xx status. Not-found lookups return 404.
  contact:
    name: zipcodestack support
    email: support@zipcodestack.com
  x-logo:
    url: https://zipcodestack.com/zipcodestack_logo.svg
servers:
  - url: https://api.zipcodestack.com
    description: Production
security:
  - ApiKeyQuery: []
  - ApiKeyHeader: []
tags:
  - name: Lookup
    description: Postal code lookups and geometry queries.
  - name: Reference
    description: Provinces and coverage.
  - name: Metadata
    description: Account status.
paths:
  /v1/search:
    get:
      tags: [Lookup]
      summary: Look up postal codes
      operationId: search
      description: Returns location data for one or more postal codes (up to 100).
      parameters:
        - name: codes
          in: query
          required: true
          description: Comma-separated list of postal codes (max 100).
          schema: { type: string }
          example: "99501,90210"
        - name: country
          in: query
          required: false
          description: Two-letter ISO country code to disambiguate the codes.
          schema: { type: string }
          example: "us"
      responses:
        '200':
          description: Postal code results keyed by the requested code.
          headers:
            X-RateLimit-Remaining-Quota-Month: { $ref: '#/components/headers/RateLimitRemainingQuotaMonth' }
            X-Cost: { $ref: '#/components/headers/Cost' }
          content:
            application/json:
              schema:
                type: object
                properties:
                  query:
                    type: object
                    properties:
                      codes: { type: array, items: { type: string } }
                      country: { type: [string, "null"] }
                  results:
                    type: object
                    additionalProperties:
                      type: array
                      items: { $ref: '#/components/schemas/PostalCode' }
                required: [query, results]
              example:
                query: { codes: ["99501"], country: "us" }
                results:
                  "99501":
                    - postal_code: "99501"
                      country_code: "US"
                      latitude: 61.2181
                      longitude: -149.9003
                      city: "Anchorage"
                      state: "Alaska"
                      city_en: "Anchorage"
                      state_en: "Alaska"
                      state_code: "AK"
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/distance:
    get:
      tags: [Lookup]
      summary: Distance from one code to others
      operationId: distance
      description: >-
        Calculates the distance between one postal code and a list of others
        (up to 100).
      parameters:
        - { name: code, in: query, required: true, description: "The origin postal code.", schema: { type: string }, example: "99501" }
        - { name: compare, in: query, required: true, description: "Comma-separated postal codes to compare against (max 100).", schema: { type: string }, example: "90210,15106" }
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
        - { name: unit, in: query, required: false, description: "Distance unit.", schema: { type: string, enum: [km, miles], default: km } }
      responses:
        '200':
          description: Distances keyed by the compared code (in the requested unit).
          content:
            application/json:
              schema:
                type: object
                properties:
                  query: { type: object, additionalProperties: true }
                  results:
                    type: object
                    additionalProperties: { type: number }
                required: [query, results]
              example:
                query: { code: "99501", compare: ["90210", "15106"], country: "us", unit: "km" }
                results: { "90210": 4368.2, "15106": 5389.7 }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/radius:
    get:
      tags: [Lookup]
      summary: Codes within a radius
      operationId: radius
      description: >-
        Returns all postal codes within a given radius of a postal code. The
        radius must be less than 500 (in the requested unit).
      parameters:
        - { name: code, in: query, required: true, description: "The center postal code.", schema: { type: string }, example: "99501" }
        - { name: radius, in: query, required: true, description: "Radius (must be < 500).", schema: { type: integer, maximum: 499 }, example: 50 }
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
        - { name: unit, in: query, required: false, description: "Distance unit.", schema: { type: string, enum: [km, miles], default: km } }
      responses:
        '200':
          description: Surrounding postal codes with their distance from the center.
          content:
            application/json:
              schema:
                type: object
                properties:
                  query: { type: object, additionalProperties: true }
                  results:
                    type: array
                    items: { $ref: '#/components/schemas/RadiusCode' }
                required: [query, results]
              example:
                query: { code: "99501", unit: "km", radius: 50, country: "us" }
                results:
                  - { code: "99502", city: "Anchorage", state: "AK", city_en: "Anchorage", state_en: "Alaska", distance: 5.23 }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '404': { $ref: '#/components/responses/NotFound' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/polygon:
    post:
      tags: [Lookup]
      summary: Codes inside a polygon
      operationId: polygon
      description: >-
        Returns all postal codes inside a polygon. The polygon is supplied as a
        JSON body of coordinate pairs `[longitude, latitude]` (at least 2), and
        the `country` is a query parameter.
      parameters:
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                coordinates:
                  type: array
                  minItems: 2
                  description: Array of `[longitude, latitude]` pairs describing the polygon.
                  items:
                    type: array
                    items: { type: number }
                    minItems: 2
                    maxItems: 2
              required: [coordinates]
            example:
              coordinates:
                - [-122.4, 37.8]
                - [-122.5, 37.9]
                - [-122.3, 37.9]
      responses:
        '200':
          description: Postal codes located inside the polygon.
          content:
            application/json:
              schema:
                type: object
                properties:
                  query: { type: object, additionalProperties: true }
                  results:
                    type: array
                    items: { $ref: '#/components/schemas/PolygonCode' }
                required: [query, results]
              example:
                query: { country: "us" }
                results:
                  - { code: "99501", city: "Anchorage", state: "AK", city_en: "Anchorage", state_en: "Alaska", latitude: 61.2181, longitude: -149.9003, distance: 0 }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/match:
    get:
      tags: [Lookup]
      summary: Match code pairs within a distance
      operationId: match
      description: >-
        Returns the pairs of the supplied postal codes (up to 100) whose
        distance is within the given maximum.
      parameters:
        - { name: codes, in: query, required: true, description: "Comma-separated postal codes (max 100).", schema: { type: string }, example: "99501,90210,15106" }
        - { name: distance, in: query, required: true, description: "Maximum distance between codes.", schema: { type: integer }, example: 100 }
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
        - { name: unit, in: query, required: false, description: "Distance unit.", schema: { type: string, enum: [km, miles], default: km } }
      responses:
        '200':
          description: Matching code pairs and their distance.
          content:
            application/json:
              schema:
                type: object
                properties:
                  query: { type: object, additionalProperties: true }
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        code_1: { type: string, example: "99501" }
                        code_2: { type: string, example: "99502" }
                        distance: { type: number, example: 5.23 }
                required: [query, results]
              example:
                query: { codes: ["99501", "90210"], distance: 100, unit: "km", country: "us" }
                results:
                  - { code_1: "99501", code_2: "99502", distance: 5.23 }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '404': { $ref: '#/components/responses/NotFound' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/code/city:
    get:
      tags: [Lookup]
      summary: Codes for a city
      operationId: codesByCity
      description: Returns the postal codes for a city, optionally filtered by state.
      parameters:
        - { name: city, in: query, required: true, description: "City name.", schema: { type: string }, example: "Anchorage" }
        - { name: state_name, in: query, required: false, description: "State name to disambiguate the city.", schema: { type: string }, example: "Alaska" }
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
        - { name: limit, in: query, required: false, description: "Maximum number of results.", schema: { type: integer }, example: 10 }
      responses:
        '200':
          description: Postal codes for the city.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CodeListResponse' }
              example:
                query: { city: "Anchorage", state: "Alaska", country: "us" }
                results: ["99501", "99502", "99503"]
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/code/state:
    get:
      tags: [Lookup]
      summary: Codes for a state
      operationId: codesByState
      description: Returns the postal codes for a state/province.
      parameters:
        - { name: state_name, in: query, required: true, description: "State/province name.", schema: { type: string }, example: "Alaska" }
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
        - { name: limit, in: query, required: false, description: "Maximum number of results.", schema: { type: integer }, example: 10 }
      responses:
        '200':
          description: Postal codes for the state.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CodeListResponse' }
              example:
                query: { state: "Alaska", country: "us" }
                results: ["99501", "99502", "99503"]
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /v1/country/province:
    get:
      tags: [Reference]
      summary: Provinces for a country
      operationId: provinces
      description: Returns the list of provinces/states for a country.
      parameters:
        - { name: country, in: query, required: true, description: "Two-letter ISO country code.", schema: { type: string }, example: "us" }
      responses:
        '200':
          description: Provinces/states for the country.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CodeListResponse' }
              example:
                query: { country: "us" }
                results: ["Alaska", "California", "New York", "Texas"]
        '401': { $ref: '#/components/responses/Unauthorized' }
  /v1/coverage:
    get:
      tags: [Reference]
      summary: Coverage by country
      operationId: coverage
      description: >-
        Returns the number of postal codes available per country. Does not count
        against your quota.
      responses:
        '200':
          description: Postal code counts keyed by ISO country code.
          content:
            application/json:
              schema:
                type: object
                properties:
                  coverage:
                    type: object
                    additionalProperties: { type: integer }
                required: [coverage]
              example:
                coverage: { US: 41000, DE: 16000, AT: 3000 }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /v1/status:
    get:
      tags: [Metadata]
      summary: Account quota status
      operationId: getStatus
      description: >-
        Returns your current monthly and grace quota usage. Requests to this
        endpoint do not count against your quota or rate limit.
      responses:
        '200':
          description: Current quota usage for the authenticated account.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StatusResponse' }
              example:
                account_id: 313373133731337
                quotas:
                  month: { total: 300, used: 72, remaining: 228 }
                  grace: { total: 0, used: 0, remaining: 0 }
        '401': { $ref: '#/components/responses/Unauthorized' }
components:
  securitySchemes:
    ApiKeyQuery: { type: apiKey, in: query, name: apikey, description: "API key as the apikey query parameter." }
    ApiKeyHeader: { type: apiKey, in: header, name: apikey, description: "API key as the apikey request header (recommended)." }
  headers:
    RateLimitRemainingQuotaMonth:
      description: Remaining requests in your monthly quota.
      schema: { type: integer }
      example: 228
    Cost:
      description: Requests this call counted against your quota.
      schema: { type: integer }
      example: 1
  responses:
    Unauthorized:
      description: An API key was supplied but is invalid.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
          example: { message: "If you specify an apikey it has to be a valid one." }
    NotFound:
      description: A requested postal code could not be found.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
          example:
            message: "99999 could not be found in our database."
            info: "For more information, see documentation: https://zipcodestack.com/docs/status-codes#_404"
    RateLimited:
      description: You have exceeded your monthly quota or minute rate limit.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
          example: { message: "You have reached your monthly limit, please upgrade your plan" }
  schemas:
    PostalCode:
      type: object
      properties:
        postal_code: { type: string, example: "99501" }
        country_code: { type: string, example: "US" }
        latitude: { type: number, example: 61.2181 }
        longitude: { type: number, example: -149.9003 }
        city: { type: string, example: "Anchorage" }
        state: { type: string, example: "Alaska" }
        city_en: { type: string, example: "Anchorage" }
        state_en: { type: string, example: "Alaska" }
        state_code: { type: [string, "null"], example: "AK" }
    RadiusCode:
      type: object
      properties:
        code: { type: string, example: "99502" }
        city: { type: string, example: "Anchorage" }
        state: { type: string, example: "AK" }
        city_en: { type: string, example: "Anchorage" }
        state_en: { type: string, example: "Alaska" }
        distance: { type: number, example: 5.23 }
    PolygonCode:
      type: object
      properties:
        code: { type: string, example: "99501" }
        city: { type: string, example: "Anchorage" }
        state: { type: string, example: "AK" }
        city_en: { type: string, example: "Anchorage" }
        state_en: { type: string, example: "Alaska" }
        latitude: { type: number, example: 61.2181 }
        longitude: { type: number, example: -149.9003 }
        distance: { type: number, example: 0 }
    CodeListResponse:
      type: object
      properties:
        query: { type: object, additionalProperties: true }
        results:
          type: array
          items: { type: string }
      required: [query, results]
    StatusResponse:
      type: object
      properties:
        account_id: { type: integer, example: 313373133731337 }
        quotas:
          type: object
          properties:
            month: { $ref: '#/components/schemas/QuotaBucket' }
            grace: { $ref: '#/components/schemas/QuotaBucket' }
          required: [month]
      required: [quotas]
    QuotaBucket:
      type: object
      properties:
        total: { type: integer, example: 300 }
        used: { type: integer, example: 72 }
        remaining: { type: integer, example: 228 }
    Error:
      type: object
      properties: { message: { type: string }, info: { type: string } }
      required: [message]
