openapi: 3.0.3

info:
  title: IPGuardian
  version: "1.0.0"
  description: |
    IPGuardian — IP blocklist check API. Free IP reputation API: checks whether
    an IP address appears in any of
    140+ public threat-intelligence blocklists — FireHOL, Spamhaus, Emerging
    Threats, DShield, TorProject, StopForumSpam, AbuseIPDB-derived lists and
    others — covering more than 2.1 billion addresses.

    No registration and no API key. Up to 100 addresses per request,
    100 requests per minute per client IP. Feeds are re-fetched and rebuilt
    daily; every match names the source list, its category and its maintainer.

    Responses carry `Access-Control-Allow-Origin: *`, so the API can be called
    directly from a browser.
  termsOfService: https://ipguardian.net/terms
  contact:
    name: IPGuardian
    url: https://ipguardian.net/contact
  license:
    name: Terms of Service
    url: https://ipguardian.net/terms

externalDocs:
  description: Documentation with code examples
  url: https://ipguardian.net/docs

servers:
  - url: https://ipguardian.net/api

tags:
  - name: Lookup
    description: Check addresses against the aggregated blocklists
  - name: Statistics
    description: Figures about the data set behind the service

paths:
  /check:
    post:
      tags: [Lookup]
      summary: Check one or more IP addresses against blocklists
      operationId: checkAddresses
      description: |
        Accepts a single address or a batch of up to 100. The body may be a
        bare JSON string, a JSON array, or an object with an `ip` or `ips`
        field — use whichever shape fits your client.

        Both IPv4 and IPv6 addresses are accepted. The aggregated source lists
        are currently IPv4-only, so IPv6 addresses come back with
        `found: false`.

        Checking 100 addresses in one call costs the same rate-limit budget
        as checking one, so batch where you can.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/IPAddress'
                - $ref: '#/components/schemas/IPAddressList'
                - type: object
                  required: [ip]
                  properties:
                    ip:
                      $ref: '#/components/schemas/IPAddress'
                - type: object
                  required: [ips]
                  properties:
                    ips:
                      $ref: '#/components/schemas/IPAddressList'
            examples:
              single:
                summary: One address as a bare string
                value: "8.8.8.8"
              batch:
                summary: Several addresses
                value: ["8.8.8.8", "1.1.1.1", "192.0.2.77"]
              objectSingle:
                summary: Object with one address
                value: {"ip": "8.8.8.8"}
              objectBatch:
                summary: Object with a list
                value: {"ips": ["8.8.8.8", "1.1.1.1"]}
      responses:
        '200':
          description: >
            Lookup completed. `results` is a single object when exactly one
            address was submitted and an array otherwise, in input order.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CheckResponse'
              examples:
                listed:
                  summary: Address found in three lists
                  value:
                    success: true
                    timestamp: "2026-09-07T10:45:37.972Z"
                    count: 1
                    results:
                      ip: "192.0.2.77"
                      found: true
                      sources:
                        - type: subnet
                          subnet: "192.0.2.0/24"
                          filename: cidr_report_bogons.netset
                          category: unroutable
                          maintainer: CIDR-Report.org
                        - type: subnet
                          subnet: "192.0.2.0/24"
                          filename: firehol_level1.netset
                          category: attacks
                          maintainer: FireHOL
                        - type: subnet
                          subnet: "192.0.2.0/24"
                          filename: iblocklist_cidr_report_bogons.netset
                          category: unroutable
                          maintainer: iBlocklist.com
                clean:
                  summary: Batch with one clean address
                  value:
                    success: true
                    timestamp: "2026-09-07T10:45:37.986Z"
                    count: 2
                    results:
                      - ip: "8.8.8.8"
                        found: false
                        sources: []
                      - ip: "2001:db8::1"
                        found: false
                        sources: []
        '400':
          description: >
            Malformed JSON, an empty list, more than 100 addresses, or an
            entry that is not a valid IP address. Invalid entries are listed
            in `invalid`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalidAddress:
                  value: {"error": "Invalid IP addresses", "invalid": ["not-an-ip"]}
                tooMany:
                  value: {"error": "Too many IPs. Maximum 100 allowed"}
                empty:
                  value: {"error": "No IP addresses provided"}
                badJson:
                  value: {"error": "Invalid JSON body"}
        '405':
          description: Method other than POST.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: {"error": "Method not allowed. Use POST"}
        '413':
          description: Request body larger than 1 MB.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: {"error": "Request too large"}
        '429':
          description: More than 100 requests per minute from one client IP. Retry after a minute.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: {"error": "Too many requests"}
        '502':
          description: The lookup backend is unreachable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: {"error": "API server not available"}
        '503':
          description: Service temporarily unavailable (database offline or server overloaded).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: {"error": "Server overloaded. Try again later"}
        '504':
          description: Lookup did not finish in time.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: {"error": "Request timeout"}

  /stats:
    get:
      tags: [Statistics]
      summary: Statistics about the aggregated data set
      operationId: getStatistics
      description: >
        Number of source lists, addresses and ranges, coverage, the time of
        the last successful rebuild, a per-category breakdown, the ten largest
        sources and the outcome of the last seven rebuilds. Figures are
        refreshed after every rebuild and cached for ten minutes.
      responses:
        '200':
          description: Current statistics.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Statistics'
        '502':
          description: The statistics backend is unreachable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Database offline.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /whoami:
    get:
      tags: [Lookup]
      summary: The caller's own IP address
      operationId: whoami
      description: >
        Returns the address the request arrived from, as seen by the service.
        Convenience endpoint for "check my own address" flows; never cached.
      responses:
        '200':
          description: Caller address.
          content:
            application/json:
              schema:
                type: object
                required: [ip]
                properties:
                  ip:
                    $ref: '#/components/schemas/IPAddress'
              example: {"ip": "203.0.113.42"}

components:
  schemas:
    IPAddress:
      type: string
      description: An IPv4 or IPv6 address in its usual text form.
      example: "8.8.8.8"

    IPAddressList:
      type: array
      description: Between 1 and 100 addresses. Duplicates are checked once.
      minItems: 1
      maxItems: 100
      items:
        $ref: '#/components/schemas/IPAddress'

    Category:
      type: string
      description: Kind of behaviour a source list documents.
      enum:
        - attacks
        - abuse
        - malware
        - spam
        - anonymizers
        - reputation
        - organizations
        - unroutable

    Source:
      type: object
      description: One list the address was found in.
      required: [type, filename, category, maintainer]
      properties:
        type:
          type: string
          description: >
            `direct` — the exact address is listed; `subnet` — the address
            falls inside a listed range.
          enum: [direct, subnet]
        subnet:
          type: string
          description: The matching CIDR range. Present only when `type` is `subnet`.
          example: "192.0.2.0/24"
        filename:
          type: string
          description: Name of the source list as published by its maintainer.
          example: firehol_level1.netset
        category:
          $ref: '#/components/schemas/Category'
        maintainer:
          type: string
          description: Who publishes the list.
          example: FireHOL
        listed_since:
          type: string
          format: date-time
          description: >
            When the entry first appeared in this list as seen by IPGuardian.
            See `listed_since_precision`.
        listed_since_precision:
          type: string
          enum: [exact, floor]
          description: >
            `exact` — first seen at this time; `floor` — the entry predates
            history tracking (October 2026) and was listed on or before this time.

    Network:
      type: object
      description: >
        Autonomous system that announces the address, from the public
        ip2asn dataset (IPv4 only). The network type is a heuristic; see `type_source`.
      properties:
        asn:
          type: integer
          nullable: true
          description: AS number; null when the range is not announced.
          example: 16276
        org:
          type: string
          nullable: true
          example: OVH
        country:
          type: string
          nullable: true
          description: ISO 3166-1 alpha-2 country of the AS registration.
          example: FR
        type:
          type: string
          enum: [datacenter, mobile, isp, unrouted]
        type_source:
          type: string
          description: >
            Where the type comes from: `mobile-list` (curated mobile operators),
            `bad-asn-list` (hosting and datacenter ASNs), `org-name` (keywords in
            the operator name) or `default`.
          enum: [mobile-list, bad-asn-list, org-name, default]

    Delisting:
      type: object
      description: A list the address was removed from recently and is not in any more.
      properties:
        filename:
          type: string
          example: blocklist_de.ipset
        category:
          $ref: '#/components/schemas/Category'
        removed_at:
          type: string
          format: date-time

    Result:
      type: object
      description: Verdict for one address.
      required: [ip, found, sources]
      properties:
        ip:
          $ref: '#/components/schemas/IPAddress'
        found:
          type: boolean
          description: "`true` if the address appears in at least one list."
        sources:
          type: array
          description: >
            Lists the address was found in; empty when `found` is `false`.
            At most 10 matches are returned per address.
          maxItems: 10
          items:
            $ref: '#/components/schemas/Source'
        network:
          nullable: true
          description: Announcing network; null for IPv6 or when unknown.
          allOf:
            - $ref: '#/components/schemas/Network'
        delisted:
          type: array
          description: Lists the address left in the last 14 days (exact-address entries only).
          maxItems: 10
          items:
            $ref: '#/components/schemas/Delisting'

    CheckResponse:
      type: object
      required: [success, timestamp, count, results]
      properties:
        success:
          type: boolean
          description: Always `true` on a 200 response.
        timestamp:
          type: string
          format: date-time
          description: When the lookup was performed (UTC).
        count:
          type: integer
          description: Number of distinct addresses checked.
          minimum: 1
          maximum: 100
        results:
          description: >
            One `Result` object when a single address was submitted; an array
            of `Result` objects, in input order, otherwise.
          oneOf:
            - $ref: '#/components/schemas/Result'
            - type: array
              items:
                $ref: '#/components/schemas/Result'

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: string
          description: Human-readable reason.
        invalid:
          type: array
          description: Entries rejected as not being IP addresses (400 only).
          items:
            type: string

    Statistics:
      type: object
      required: [sources, ips, subnets, addressesCovered, lastSync, lastSyncSeconds, categories, topSources, history]
      properties:
        sources:
          type: integer
          description: Number of source lists in the last successful rebuild.
          example: 162
        ips:
          type: integer
          description: Distinct individual addresses across all lists.
          example: 7694331
        subnets:
          type: integer
          description: Distinct ranges across all lists.
          example: 373439
        addressesCovered:
          type: integer
          format: int64
          description: Addresses covered by individual entries and ranges together.
          example: 2104696498
        lastSync:
          type: string
          format: date-time
          nullable: true
          description: When the last successful rebuild finished (UTC).
          example: "2026-09-07T00:09:16.000Z"
        lastSyncSeconds:
          type: integer
          description: How long that rebuild took.
          example: 554
        categories:
          type: array
          items:
            type: object
            required: [category, sources, ips, subnets]
            properties:
              category:
                $ref: '#/components/schemas/Category'
              sources:
                type: integer
              ips:
                type: integer
              subnets:
                type: integer
        topSources:
          type: array
          description: The ten largest lists by number of entries.
          items:
            type: object
            required: [filename, category, ips, subnets]
            properties:
              filename:
                type: string
                example: firehol_anonymous.netset
              category:
                $ref: '#/components/schemas/Category'
              ips:
                type: integer
              subnets:
                type: integer
        history:
          type: array
          description: The last seven rebuilds, newest first.
          items:
            type: object
            required: [date, status, ips, seconds]
            properties:
              date:
                type: string
                format: date-time
              status:
                type: string
                description: "`success` or the failure state of the rebuild."
                example: success
              ips:
                type: integer
              seconds:
                type: integer
