Entur · API Governance Rules

Entur API Rules

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

48 Rules error 33 warn 14 info 1
Published by Entur Served by the provider at https://github.com/entur/api-guidelines/blob/f92bec1065e08092b8c5ee62677ff9345ed1a174/.spectral.yml; the copy below was fetched from there.
View Rules File View on GitHub

Rule Categories

entur

Rules

error
entur-info-title
$
warn
entur-info-title-no-api
$.info.title
warn
entur-operation-standard-methods
$.paths[*]
warn
entur-example-parameter
$.paths.*.*.parameters.*
warn
entur-parameter-description
$.paths.*.*.parameters.*
warn
entur-example-schema-property
$.components.schemas.*.properties[?(@.type != 'array' || !@.items.$ref)]
warn
entur-request-body-examples
$.paths.*.*.requestBody.content.*
warn
entur-request-body-description
$.paths.*.*.requestBody
warn
entur-response-body-examples
$.paths.*.*.responses.*.content.*
warn
entur-operation-summary
$.paths.*[get,post,put,patch,delete,options,head,trace]
error
entur-openapi-version-3
$
error
entur-hosts-https-only
$.servers[*].url
warn
entur-hosts-not-localhost
$.servers[*].url
error
entur-permissions
$.paths.*[get,post,put,patch,delete,options,head,trace].x-entur-permissions
error
entur-info-metadata-id
$
error
entur-info-metadata-id-kebab-case
$.info.x-entur-metadata.id
error
entur-info-metadata-audience
$
error
entur-info-metadata-audience-valid
$.info.x-entur-metadata.audience
error
entur-info-metadata-owner
$
error
entur-info-metadata-owner-valid
$.info.x-entur-metadata.owner
error
entur-info-metadata-parent-id-kebab-case
$.info.x-entur-metadata.parentId
error
entur-info-metadata-devExtensions
$.info.x-entur-metadata.devExtensions
error
entur-stability-level-api
$.info.x-stability-level
error
entur-deprecation-api
$.info.x-deprecated
error
entur-sunset-api
$.info
error
entur-sunset-format-api
$.info.x-sunset
error
entur-stability-level-operation
$.paths.*[get,post,put,patch,delete,options,head,trace].x-stability-level
info
entur-sunset-operation
$.paths.*[get,post,put,patch,delete,options,head,trace]
error
entur-sunset-format-operation
$.paths.*[get,post,put,patch,delete,options,head,trace].x-sunset
error
entur-paths-format
$.paths.*~
error
entur-query-parameters-lower-camel-case
$.paths.*.*.parameters[?(@.in=='query')].name
error
entur-path-parameters-camelCase-alphanumeric
$..parameters[?(@.in == 'path')].name
error
entur-body-fields-lower-camel-case
$..[?(@property === 'properties')]
error
entur-server-urls-lowercase
$.servers[*].url
warn
entur-paths-with-api
$.paths.*~
error
entur-request-body-allowed-methods
$.paths[*].get.requestBody$.paths[*].delete.requestBody$.paths[*].options.requestBody$.paths[*].head.requestBody$.paths[*].trace.requestBody
error
entur-get-responses-validation
$.paths.*.get.responses
error
entur-delete-responses-validation
$.paths.*.delete.responses
error
entur-post-responses-validation
$.paths.*.post.responses
error
entur-put-responses-validation
$.paths.*.put.responses
error
entur-patch-responses-validation
$.paths.*.patch.responses
warn
entur-rfc-9457-content-type
$.paths.*.*.responses[?(@property.match(/^(4|5)/))]
error
entur-rfc-9457-body-title
$.paths.*.*.responses[?(@property.match(/^(4|5)/))].content.*.schema.properties
error
entur-rfc-9457-body-status
$.paths.*.*.responses[?(@property.match(/^(4|5)/))].content.*.schema.properties
warn
entur-rfc-9457-body-detail
$.paths.*.*.responses[?(@property.match(/^(4|5)/))].content.*.schema.properties
error
entur-language-headers
$..parameters[?(@.in=='header' && @.name=='Accept-Language')].example$..parameters[?(@.in=='header' && @.name=='Accept-Language')].schema.example$..parameters[?(@.in=='header' && @.name=='Accept-Language')].schema.default$..parameters[?(@.in=='header' && @.name=='Content-Language')].example$..parameters[?(@.in=='header' && @.name=='Content-Language')].schema.example$..parameters[?(@.in=='header' && @.name=='Content-Language')].schema.default
warn
entur-not-et-client-name-header
$.paths[*]..parameters[?(@.in == 'header' && @.name == 'ET-Client-Name')].name
error
entur-headers-hyphenated-pascal-case
$..parameters[?(@.in == 'header' && @.name != 'ET-Client-Name' && @.name != 'Entur-POS')].name

Spectral Ruleset

Raw ↑
# harvested from https://github.com/entur/api-guidelines/blob/f92bec1065e08092b8c5ee62677ff9345ed1a174/.spectral.yml on 2026-10-09 — a Spectral ruleset published in the provider's own GitHub repository (entur/api-guidelines); found by GitHub code search, fetched verbatim
x-method: harvested
x-stamped: 2026-10-09
x-source-url: https://github.com/entur/api-guidelines/blob/f92bec1065e08092b8c5ee62677ff9345ed1a174/.spectral.yml
# API Guidelines Ruleset
# This ruleset enforces the API design standards described in our API Guidelines document.
# Structure follows the same organization as the main guidelines document for easy reference.

# OpenAPI Specification version 3.x
extends: [spectral:oas]

functions:
  - date
  - conditionallyDefined
  - requireExampleOrRef
  - requireRequestBodyDescription
  - xEnturPermissions

rules:
  # =============================================================================
  # 1. Introduction - Not lintable
  # =============================================================================

  # =============================================================================
  # 2. Core Principles
  # =============================================================================

  # -------------------------------------------------------------------------
  # 2.1 General Design Principles
  # -------------------------------------------------------------------------

  entur-info-title:
    message: "The OpenAPI info section MUST include a non-empty \"title\"."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: error
    given: $
    then:
      field: info.title
      function: truthy

  entur-info-title-no-api:
    message: "API titles SHOULD NOT contain the word 'api'."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        notMatch: "/\\bapi\\b/i"

  info-description: error
  info-contact: off

  # HTTP Methods
  entur-operation-standard-methods:
    message: "Operations SHOULD use standard HTTP methods (`get`, `post`, `put`, `patch`, `delete`). Invalid operation: {{property}}."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    given: $.paths[*]
    severity: warn
    then:
      field: "@key"
      function: pattern
      functionOptions:
        notMatch: "^(options|head|trace)$"

  # Documentation with examples
  entur-example-parameter:
    message: "Parameters SHOULD have example values."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    recommended: false
    given: $.paths.*.*.parameters.*
    then:
      field: example
      function: defined

  entur-parameter-description:
    message: "Parameters SHOULD have a description."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.paths.*.*.parameters.*
    then:
      field: description
      function: truthy

  entur-example-schema-property:
    message: "Properties in components schema SHOULD have example values."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    recommended: false
    #For schema properties where type is not array, or items is not a ref. (Array with ref to other schema does not need an example)
    given: $.components.schemas.*.properties[?(@.type != 'array' || !@.items.$ref)]
    then:
      field: example
      function: defined

  entur-request-body-examples:
    message: "Request bodies SHOULD include at least one example."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.paths.*.*.requestBody.content.*
    then:
      function: requireExampleOrRef

  entur-request-body-description:
    message: "Request bodies SHOULD have a description, either directly or on the referenced schema."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.paths.*.*.requestBody
    then:
      function: requireRequestBodyDescription

  entur-response-body-examples:
    message: "Response bodies SHOULD include at least one example."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.paths.*.*.responses.*.content.*
    then:
      function: requireExampleOrRef


  entur-operation-summary:
    message: "Operations SHOULD have a non-empty summary field."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.paths.*[get,post,put,patch,delete,options,head,trace]
    then:
      field: summary
      function: truthy

  # openapi spec version 3
  entur-openapi-version-3:
    message: "OpenAPI specification must use version 3.x"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: error
    given: "$"
    then:
      - field: openapi
        function: pattern
        functionOptions:
          match: "^3\\.\\d+\\.\\d+$"
      - field: swagger
        function: falsy

  # Security - HTTPS requirement
  entur-hosts-https-only:
    message: "Servers MUST use HTTPS. Invalid URL: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: ^(https:)

  entur-hosts-not-localhost:
    message: "Server URLs SHOULD NOT use localhost or 127.0.0.1 as hostname. Invalid URL: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#21-general-design-principles"
    severity: warn
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        notMatch: "https?://(localhost|127\\.0\\.0\\.1)(/|$)"
      invert: true
  
  # -------------------------------------------------------------------------
  # 2.3 Authentication and authorization
  # -------------------------------------------------------------------------

  entur-permissions:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#233-documenting-permissions-for-partner-endpoints"
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head,trace].x-entur-permissions
    then:
      function: xEnturPermissions

  # -------------------------------------------------------------------------
  # 2.4 Entur Metadata
  # -------------------------------------------------------------------------

  entur-info-metadata-id:
    message: "The OpenAPI info section MUST include \"x-entur-metadata.id\"."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#241-identifying-a-specification"
    severity: error
    given: $
    then:
      field: info.x-entur-metadata.id
      function: truthy

  entur-info-metadata-id-kebab-case:
    message: "The \"x-entur-metadata.id\" MUST be in lower-kebab-case format. Invalid value: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#241-identifying-a-specification"
    severity: error
    given: $.info.x-entur-metadata.id
    then:
      function: pattern
      functionOptions:
        match: ^[a-z0-9]+(-[a-z0-9]+)*$

  entur-info-metadata-audience:
    message: "The OpenAPI info section MUST include \"x-entur-metadata.audience\"."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#24-entur-metadata"
    severity: error
    given: $
    then:
      field: info.x-entur-metadata.audience
      function: truthy

  entur-info-metadata-audience-valid:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#24-entur-metadata"
    severity: error
    given: $.info.x-entur-metadata.audience
    then:
      function: enumeration
      functionOptions:
        values:
          - open
          - partner
          - internal
          - private

  entur-info-metadata-owner:
    message: "The OpenAPI info section MUST include \"x-entur-metadata.owner\"."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#242-specification-owner"
    severity: error
    given: $
    then:
      field: info.x-entur-metadata.owner
      function: truthy

  entur-info-metadata-owner-valid:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#242-specification-owner"
    severity: error
    given: $.info.x-entur-metadata.owner
    then:
      function: pattern
      functionOptions:
        match: ^team-[a-z0-9]+(-[a-z0-9]+)*$

  entur-info-metadata-parent-id-kebab-case:
    message: "The \"x-entur-metadata.parentId\" MUST be in lower-kebab-case format. Invalid value: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#243-merging-specifications"
    severity: error
    given: $.info.x-entur-metadata.parentId
    then:
      function: pattern
      functionOptions:
        match: ^[a-z0-9]+(-[a-z0-9]+)*$

  entur-info-metadata-devExtensions:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#244-development-only-openapi-extensions"
    severity: error
    given: $.info.x-entur-metadata.devExtensions
    then:
      function: schema
      functionOptions:
        schema:
          type: array
          items:
            type: string
            pattern: ^x-.*$

  # -------------------------------------------------------------------------
  # 2.5 Lifecycle
  # -------------------------------------------------------------------------

  ## On API level
  entur-stability-level-api:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#25-lifecycle"
    severity: error
    given: $.info.x-stability-level
    then:
      function: enumeration
      functionOptions:
        values: [draft, beta, stable]

  entur-deprecation-api:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#254-deprecation"
    severity: error
    given: $.info.x-deprecated
    then:
      function: schema
      functionOptions:
        schema:
          type: boolean

  entur-sunset-api:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#254-deprecation"
    severity: error
    given: $.info
    then:
      function: conditionallyDefined
      functionOptions:
        field: x-sunset
        conditionalField: x-deprecated
        havingValue: true

  entur-sunset-format-api:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#254-deprecation"
    severity: error
    given: $.info.x-sunset
    then:
      function: date

  # On individual operation level
  entur-stability-level-operation:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#25-lifecycle"
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head,trace].x-stability-level
    then:
      function: enumeration
      functionOptions:
        values: [draft, beta, stable]

  entur-sunset-operation:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#254-deprecation"
    severity: info # This one should be an error, but for an introduction period, make it just info.
    given: $.paths.*[get,post,put,patch,delete,options,head,trace]
    then:
      function: conditionallyDefined
      functionOptions:
        field: x-sunset
        conditionalField: deprecated
        havingValue: true

  entur-sunset-format-operation:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#254-deprecation"
    severity: error
    given: $.paths.*[get,post,put,patch,delete,options,head,trace].x-sunset
    then:
      function: date


  # =============================================================================
  # 3. Naming & Structure Conventions
  # =============================================================================

  # -------------------------------------------------------------------------
  # 3.1 Resource Naming
  # -------------------------------------------------------------------------

  # URL format requirements
  entur-paths-format:
    message: "Paths MUST be in kebab-case (lower case and separated with hyphens), with single slashes, and no trailing slash at end of path. Invalid path: {{property}}."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#31-resource-naming"
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        #Match leading slash followed by kebab casing, and then optional trailing kebab with url params allowed. No trailing slash.
        #Double slashes now allowed.
        #Custom functions not allowed in path for now (e.g. /ecards/{mediaSerialNumberId}:block)
        match: ^(\/[a-z0-9]+(-[a-z0-9]+)*)(\/[a-z0-9]+(-[a-z0-9]+)*|\/{.+})*$

  # Field naming conventions
  entur-query-parameters-lower-camel-case:
    message: "Query parameter names MUST be lowerCamelCase. Invalid name: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#31-resource-naming"
    severity: error
    given: $.paths.*.*.parameters[?(@.in=='query')].name
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$

  entur-path-parameters-camelCase-alphanumeric:
    message: "Path parameter names MUST be lowerCamelCase. Invalid name: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#31-resource-naming"
    severity: error
    given: $..parameters[?(@.in == 'path')].name
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$

  entur-body-fields-lower-camel-case:
    message: "Request and Response body field names MUST be lowerCamelCase."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#31-resource-naming"
    severity: error
    given: $..[?(@property === 'properties')]
    then:
      field: "@key"
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$

# Server URL case requirements
  entur-server-urls-lowercase:
    message: "Server URLs MUST be in lowercase. Invalid URL: {{value}}"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#31-resource-naming"
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: ^[^A-Z]*$

  # Avoid 'api' in paths
  entur-paths-with-api:
    message: "Paths SHOULD NOT contain 'api'."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#31-resource-naming"
    severity: warn
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: "^(?!\/api-docs$).*\\bapi\\b.*$"

  # -------------------------------------------------------------------------
  # 3.2 Versioning
  # -------------------------------------------------------------------------

  # =============================================================================
  # 4. Communication Standards
  # =============================================================================


  # -------------------------------------------------------------------------
  # 4.1 HTTP Status Codes
  # -------------------------------------------------------------------------

  # Request body allowed methods
  entur-request-body-allowed-methods:
    message: "Request body is allowed only for PUT, POST, and PATCH."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#41-http-status-codes"
    severity: error
    given:
      - "$.paths[*].get.requestBody"
      - "$.paths[*].delete.requestBody"
      - "$.paths[*].options.requestBody"
      - "$.paths[*].head.requestBody"
      - "$.paths[*].trace.requestBody"
    then:
      function: falsy

  # HTTP method responses validation
  entur-get-responses-validation:
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#41-http-status-codes"
    severity: error
    given: $.paths.*.get.responses
    then:
      field: "@key"
      function: enumeration
      functionOptions:
        values: ["200", "302", "304", "400", "401", "403", "404", "500", "503", "default"]

  entur-delete-responses-validation:
    message: "Invalid response code: {{value}}. DELETE responses MUST use one of these response codes: 200, 204, 400, 401, 403, 404, 409, 500, 503"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#41-http-status-codes"
    severity: error
    given: $.paths.*.delete.responses
    then:
      field: "@key"
      function: enumeration
      functionOptions:
        values: ["200", "204", "400", "401", "403", "404", "409", "500", "503", "default"]

  entur-post-responses-validation:
    message: "Invalid response code: {{value}}. POST responses MUST use one of these response codes: 200, 201, 202, 204, 303, 400, 401, 403, 404, 409, 500, 503"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#41-http-status-codes"
    severity: error
    given: $.paths.*.post.responses
    then:
      field: "@key"
      function: enumeration
      functionOptions:
        values: ["200", "201", "202", "204", "303", "400", "401", "403", "404", "409", "500", "503", "default"]

  entur-put-responses-validation:
    message: "Invalid response code: {{value}}. PUT responses MUST use one of these response codes: 200, 204, 400, 401, 403, 404, 409, 500, 503"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#41-http-status-codes"
    severity: error
    given: $.paths.*.put.responses
    then:
      field: "@key"
      function: enumeration
      functionOptions:
        values: ["200", "201", "204", "400", "401", "403", "404", "409", "500", "503", "default"]

  entur-patch-responses-validation:
    message: "Invalid response code: {{value}}. PATCH responses MUST use one of these response codes: 200, 204, 400, 401, 403, 404, 409, 500, 503"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#41-http-status-codes"
    severity: error
    given: $.paths.*.patch.responses
    then:
      field: "@key"
      function: enumeration
      functionOptions:
        values: ["200", "204", "400", "401", "403", "404", "409", "500", "503", "default"]


  # -------------------------------------------------------------------------
  # 4.2 Error Handling - RFC 9457 compliance
  # -------------------------------------------------------------------------

  # Error response format validation
  entur-rfc-9457-content-type:
    message: "Error responses MUST have content type application/problem+json or application/problem+xml"
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#42-error-handling"
    severity: warn
    given: $.paths.*.*.responses[?(@property.match(/^(4|5)/))]
    then:
      - field: content
        function: truthy
      - field: content
        function: schema
        functionOptions:
          # JSON Schema to require either the JSON or XML problem media-type
          schema:
            type: object
            anyOf:
              - required: ["application/problem+json"]
              - required: ["application/problem+xml"]

  entur-rfc-9457-body-title:
    message: "Error responses MUST have property 'title'."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#42-error-handling"
    severity: error
    given: $.paths.*.*.responses[?(@property.match(/^(4|5)/))].content.*.schema.properties
    then:
      field: title
      function: defined

  entur-rfc-9457-body-status:
    message: "Error responses MUST have property 'status'."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#42-error-handling"
    severity: error
    given: $.paths.*.*.responses[?(@property.match(/^(4|5)/))].content.*.schema.properties
    then:
      field: status
      function: defined

  entur-rfc-9457-body-detail:
    message: "Error responses SHOULD have property 'detail' to provide additional context."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#42-error-handling"
    severity: warn
    given: $.paths.*.*.responses[?(@property.match(/^(4|5)/))].content.*.schema.properties
    then:
      field: detail
      function: defined


  # =============================================================================
  # 5. Data Formatting Standards
  # =============================================================================


  # -------------------------------------------------------------------------
  # 5.1 Language & Spelling
  # -------------------------------------------------------------------------

  entur-language-headers:
    message: "Accept-Language and Content-Language should follow IETF BCP 47. And macrolanguages like 'no' should not be used - use 'nb' or 'nn'."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#51-language--spelling"
    severity: error
    given:
      - $..parameters[?(@.in=='header' && @.name=='Accept-Language')].example
      - $..parameters[?(@.in=='header' && @.name=='Accept-Language')].schema.example
      - $..parameters[?(@.in=='header' && @.name=='Accept-Language')].schema.default
      - $..parameters[?(@.in=='header' && @.name=='Content-Language')].example
      - $..parameters[?(@.in=='header' && @.name=='Content-Language')].schema.example
      - $..parameters[?(@.in=='header' && @.name=='Content-Language')].schema.default
    then:
      function: pattern
      functionOptions:
        notMatch: "^(nob|nno|eng|nor|no)\\b"

  # -------------------------------------------------------------------------
  # 5.2 Date & Time - Requires runtime validation
  # -------------------------------------------------------------------------


  # -------------------------------------------------------------------------
  # 5.3 Currency Representation - Requires runtime validation
  # -------------------------------------------------------------------------


  # -------------------------------------------------------------------------
  # 5.4 Character Encoding - Not directly lintable for UTF-8
  # -------------------------------------------------------------------------


  # -------------------------------------------------------------------------
  # 5.5 HTTP Headers
  # -------------------------------------------------------------------------

  # ET-Client-Name header not necessary
  entur-not-et-client-name-header:
    message: "Declaring header \"ET-Client-Name\" is not necessary."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#55-http-headers"
    severity: warn
    given: "$.paths[*]..parameters[?(@.in == 'header' && @.name == 'ET-Client-Name')].name"
    then:
      function: falsy

  # Header naming conventions
  entur-headers-hyphenated-pascal-case:
    message: "HTTP header names MUST be in Hyphenated-Pascal-Case. Invalid name: \"{{value}}\"."
    documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#55-http-headers"
    severity: error
    given: "$..parameters[?(@.in == 'header' && @.name != 'ET-Client-Name' && @.name != 'Entur-POS')].name"
    then:
      function: pattern
      functionOptions:
        match: ^([A-Z][a-z0-9]*)(-[A-Z][a-z0-9]*)*$


  # =============================================================================
  # 6. Advanced Design Patterns
  # =============================================================================

  # Most advanced design patterns require runtime validation or manual review
  # The rules here focus on aspects that can be statically verified


  # -------------------------------------------------------------------------
  # 6.5 Import & Export Formats - Accept header validation handled at runtime
  # -------------------------------------------------------------------------


  # -------------------------------------------------------------------------
  # 6.6 Validation - Error response format covered in section 4.2
  # -------------------------------------------------------------------------


  # -------------------------------------------------------------------------
  # 6.7 HATEOAS - Not directly lintable, requires manual review
  # -------------------------------------------------------------------------

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/entur-api-guidelines-spectral-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.