ipify · API Governance Rules

ipify API Rules

Spectral linting rules defining API design standards and conventions for ipify.

37 Rules error 15 warn 17 info 5
Authorship not recorded No authorship marker is recorded for this file. It is not presented as the provider's; it was most likely written by an API Evangelist pass before outputs were stamped.
View Rules File View on GitHub

Rule Categories

deprecation example get info ipify openapi operation parameter paths response schema security servers tag tags

Rules

error
info-title-required
Info object must define a title.
$.info
warn
info-title-prefix-ipify
Spec title should start with `ipify` for consistent provider branding.
$.info.title
error
info-description-required
Info object must include a description of the API.
$.info
warn
info-contact-required
Info object should include a contact for the provider.
$.info
warn
info-license-required
Info object should declare a license (MIT for the free API, Commercial for Geolocation).
$.info
error
openapi-version-3
All ipify specs must declare OpenAPI 3.x.
$.openapi
error
servers-required
A `servers` array must be defined at the document root.
$
error
servers-must-be-https
ipify endpoints are HTTPS-only. No `http://` server URLs allowed.
$.servers[*].url
warn
servers-description-required
Each server entry must explain which surface it points to (IPv4, IPv6, dual-stack, account utility, etc.).
$.servers[*]
error
paths-no-trailing-slash
Paths must not end with a trailing slash (except the root `/`).
$.paths
error
paths-no-query-strings
Paths must not contain query strings — express them as parameters.
$.paths
warn
paths-lowercase-segments
Path segments must be lowercase kebab-case (matches ipify's `/country`, `/country,city`, `/service/account-balance`).
$.paths
error
operation-operationId-required
Every operation must declare an `operationId`.
$.paths[*][get,post,put,patch,delete]
warn
operation-operationId-camelcase
operationId must be camelCase (e.g. `getPublicIp`, `getCountryLocation`, `getAccountBalance`).
$.paths[*][get,post,put,patch,delete].operationId
error
operation-summary-required
Every operation must declare a `summary`.
$.paths[*][get,post,put,patch,delete]
warn
operation-summary-prefix-ipify
Operation summary must start with `ipify ` for consistent provider branding.
$.paths[*][get,post,put,patch,delete].summary
warn
operation-description-required
Every operation must declare a `description`.
$.paths[*][get,post,put,patch,delete]
error
operation-tags-required
Every operation must declare at least one tag.
$.paths[*][get,post,put,patch,delete]
warn
operation-microcks-extension-required
Every operation must declare an `x-microcks-operation` extension for mock-server compatibility.
$.paths[*][get,post,put,patch,delete]
warn
tags-root-defined
A root `tags` array must enumerate every tag with a description.
$
warn
tags-title-case
Tag names must be Title Case (e.g. `IP Address`, `Geolocation`, `Account`).
$.tags[*].name
warn
tag-description-required
Every declared tag must include a description.
$.tags[*]
warn
parameter-description-required
Every parameter must include a description.
#Parameter
warn
parameter-camelcase
Query/path parameter names must be camelCase (matches ipify's `apiKey`, `ipAddress`, `reverseIp`, `escapedUnicode`).
$.paths[*][*].parameters[?(@.in == 'query' || @.in == 'path')].name
error
parameter-schema-required
Every parameter must declare a `schema` with a `type`.
$.paths[*][*].parameters[*]
error
response-2xx-required
Every operation must declare at least one 2xx success response.
$.paths[*][get,post,put,patch,delete].responses
warn
response-description-required
Every response must include a description.
$.paths[*][*].responses[*]
info
response-error-codes-geolocation
Geolocation operations should document 400, 401, 403, 422, and 429 error responses.
$.paths[/country,/country\,city,/country\,city\,vpn][get].responses
warn
schema-camelcase-properties
Schema property names must be camelCase (matches the Geolocation API's `postalCode`, `geonameId`, `escapedUnicode`).
$.components.schemas[*].properties
warn
schema-description-required
Every top-level component schema must include a description.
$.components.schemas[*]
error
schema-type-required
Every top-level component schema must declare a `type`.
$.components.schemas[*]
info
security-scheme-apikey-query
The Geolocation API authenticates with an `apiKey` query parameter (no other schemes are supported).
$.components.securitySchemes[*]
info
security-public-api-no-auth
The free public IP API (`api.ipify.org`) must not declare a security scheme — it is intentionally unauthenticated.
$.paths[/].get
error
get-no-request-body
GET operations must not declare a request body — both ipify APIs are GET-only.
$.paths[*].get
error
ipify-get-only-api
ipify exposes only GET operations. Reject any POST/PUT/PATCH/DELETE.
$.paths[*]
info
deprecation-documented
Deprecated operations and schemas must be marked with `deprecated: true` (e.g. the VPN/proxy block).
$..deprecated
info
example-encouraged
Schema properties should include `example` values to support mock-server scenarios.
$.components.schemas[*].properties[*]

Spectral Ruleset

Raw ↑
rules:

  # ── INFO / METADATA ────────────────────────────────────────────────────
  info-title-required:
    description: Info object must define a title.
    severity: error
    given: $.info
    then:
      field: title
      function: truthy
  info-title-prefix-ipify:
    description: Spec title should start with `ipify` for consistent provider branding.
    severity: warn
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        match: '^ipify'
  info-description-required:
    description: Info object must include a description of the API.
    severity: error
    given: $.info
    then:
      field: description
      function: truthy
  info-contact-required:
    description: Info object should include a contact for the provider.
    severity: warn
    given: $.info
    then:
      field: contact
      function: truthy
  info-license-required:
    description: Info object should declare a license (MIT for the free API, Commercial for Geolocation).
    severity: warn
    given: $.info
    then:
      field: license
      function: truthy

  # ── OPENAPI VERSION ────────────────────────────────────────────────────
  openapi-version-3:
    description: All ipify specs must declare OpenAPI 3.x.
    severity: error
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: '^3\.'

  # ── SERVERS ────────────────────────────────────────────────────────────
  servers-required:
    description: A `servers` array must be defined at the document root.
    severity: error
    given: $
    then:
      field: servers
      function: truthy
  servers-must-be-https:
    description: ipify endpoints are HTTPS-only. No `http://` server URLs allowed.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        notMatch: '^http://'
  servers-description-required:
    description: Each server entry must explain which surface it points to (IPv4, IPv6, dual-stack, account utility, etc.).
    severity: warn
    given: $.servers[*]
    then:
      field: description
      function: truthy

  # ── PATHS — NAMING CONVENTIONS ─────────────────────────────────────────
  paths-no-trailing-slash:
    description: Paths must not end with a trailing slash (except the root `/`).
    severity: error
    given: $.paths
    then:
      function: pattern
      functionOptions:
        match: '^(\/|[^\/]+(\/[^\/]+)*)$'
  paths-no-query-strings:
    description: Paths must not contain query strings — express them as parameters.
    severity: error
    given: $.paths
    then:
      function: pattern
      functionOptions:
        notMatch: '\?'
  paths-lowercase-segments:
    description: Path segments must be lowercase kebab-case (matches ipify's `/country`, `/country,city`, `/service/account-balance`).
    severity: warn
    given: $.paths
    then:
      function: pattern
      functionOptions:
        match: '^/[a-z0-9,_\-\/{}]*$'

  # ── OPERATIONS ─────────────────────────────────────────────────────────
  operation-operationId-required:
    description: Every operation must declare an `operationId`.
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: operationId
      function: truthy
  operation-operationId-camelcase:
    description: operationId must be camelCase (e.g. `getPublicIp`, `getCountryLocation`, `getAccountBalance`).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].operationId
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'
  operation-summary-required:
    description: Every operation must declare a `summary`.
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: summary
      function: truthy
  operation-summary-prefix-ipify:
    description: Operation summary must start with `ipify ` for consistent provider branding.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].summary
    then:
      function: pattern
      functionOptions:
        match: '^ipify '
  operation-description-required:
    description: Every operation must declare a `description`.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: description
      function: truthy
  operation-tags-required:
    description: Every operation must declare at least one tag.
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: tags
      function: truthy
  operation-microcks-extension-required:
    description: Every operation must declare an `x-microcks-operation` extension for mock-server compatibility.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: x-microcks-operation
      function: truthy

  # ── TAGS ───────────────────────────────────────────────────────────────
  tags-root-defined:
    description: A root `tags` array must enumerate every tag with a description.
    severity: warn
    given: $
    then:
      field: tags
      function: truthy
  tags-title-case:
    description: Tag names must be Title Case (e.g. `IP Address`, `Geolocation`, `Account`).
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: '^([A-Z][A-Za-z]*)( [A-Z][A-Za-z]*)*$'
  tag-description-required:
    description: Every declared tag must include a description.
    severity: warn
    given: $.tags[*]
    then:
      field: description
      function: truthy

  # ── PARAMETERS ─────────────────────────────────────────────────────────
  parameter-description-required:
    description: Every parameter must include a description.
    severity: warn
    given: '#Parameter'
    then:
      field: description
      function: truthy
  parameter-camelcase:
    description: Query/path parameter names must be camelCase (matches ipify's `apiKey`, `ipAddress`, `reverseIp`, `escapedUnicode`).
    severity: warn
    given: $.paths[*][*].parameters[?(@.in == 'query' || @.in == 'path')].name
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'
  parameter-schema-required:
    description: Every parameter must declare a `schema` with a `type`.
    severity: error
    given: $.paths[*][*].parameters[*]
    then:
      field: schema
      function: truthy

  # ── RESPONSES ──────────────────────────────────────────────────────────
  response-2xx-required:
    description: Every operation must declare at least one 2xx success response.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          patternProperties:
            '^2\d\d$': {}
          minProperties: 1
  response-description-required:
    description: Every response must include a description.
    severity: warn
    given: $.paths[*][*].responses[*]
    then:
      field: description
      function: truthy
  response-error-codes-geolocation:
    description: Geolocation operations should document 400, 401, 403, 422, and 429 error responses.
    severity: info
    given: $.paths[/country,/country\,city,/country\,city\,vpn][get].responses
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          required: ['400', '401', '403', '422', '429']

  # ── SCHEMAS — PROPERTY NAMING ──────────────────────────────────────────
  schema-camelcase-properties:
    description: Schema property names must be camelCase (matches the Geolocation API's `postalCode`, `geonameId`, `escapedUnicode`).
    severity: warn
    given: $.components.schemas[*].properties
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'
  schema-description-required:
    description: Every top-level component schema must include a description.
    severity: warn
    given: $.components.schemas[*]
    then:
      field: description
      function: truthy
  schema-type-required:
    description: Every top-level component schema must declare a `type`.
    severity: error
    given: $.components.schemas[*]
    then:
      field: type
      function: truthy

  # ── SECURITY ───────────────────────────────────────────────────────────
  security-scheme-apikey-query:
    description: The Geolocation API authenticates with an `apiKey` query parameter (no other schemes are supported).
    severity: info
    given: $.components.securitySchemes[*]
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          properties:
            type: { const: apiKey }
            in: { const: query }
            name: { const: apiKey }
  security-public-api-no-auth:
    description: The free public IP API (`api.ipify.org`) must not declare a security scheme — it is intentionally unauthenticated.
    severity: info
    given: $.paths[/].get
    then:
      field: security
      function: falsy

  # ── HTTP METHOD CONVENTIONS ────────────────────────────────────────────
  get-no-request-body:
    description: GET operations must not declare a request body — both ipify APIs are GET-only.
    severity: error
    given: $.paths[*].get
    then:
      field: requestBody
      function: falsy
  ipify-get-only-api:
    description: ipify exposes only GET operations. Reject any POST/PUT/PATCH/DELETE.
    severity: error
    given: $.paths[*]
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          not:
            anyOf:
              - required: [post]
              - required: [put]
              - required: [patch]
              - required: [delete]

  # ── GENERAL QUALITY ────────────────────────────────────────────────────
  deprecation-documented:
    description: "Deprecated operations and schemas must be marked with `deprecated: true` (e.g. the VPN/proxy block)."
    severity: info
    given: $..deprecated
    then:
      function: truthy
  example-encouraged:
    description: Schema properties should include `example` values to support mock-server scenarios.
    severity: info
    given: $.components.schemas[*].properties[*]
    then:
      field: example
      function: truthy

Work with this as data

Every ruleset here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for spectral rules

4 MCP tools reach this
  • find_rulesBrowse and filter every ruleset in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This ruleset
curl "https://apis.io/api/v1/rules/ipify-rules"
All spectral rules
curl "https://apis.io/api/v1/rules?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.