Codag · API Governance Rules

Codag API Rules

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

43 Rules error 37 warn 4 info 2
Generated by API Evangelist Written by API Evangelist tooling for Codag's APIs. It is a starting point, not a ruleset Codag publishes or enforces.
View Rules File View on GitHub

Rule Categories

info mediatype operation parameter path property requestbody response schema tag write

Rules

error
operation-has-operationid
Every operation declares an operationId (measured: 100% of this contract)
$.paths[*][get,post,put,patch,delete]
error
operation-has-summary
Every operation has a summary (measured: 100% of this contract)
$.paths[*][get,post,put,patch,delete]
error
operation-has-tags
Every operation is tagged (measured: 100% of this contract)
$.paths[*][get,post,put,patch,delete]
error
operation-has-success-response
Every operation declares a 2xx response (measured: 100% of this contract)
$.paths[*][get,post,put,patch,delete].responses
warn
path-segment-casing-kebab
Path segments are kebab case (measured: 99% of this contract)
$.paths[*]~
error
path-no-trailing-slash
Paths carry no trailing slash (measured: 100% of this contract)
$.paths[*]~
error
path-params-in-braces
Path parameters use {braces}, not :colon (measured: 100% of this contract)
$.paths[*]~
info
write-declares-request-body
POST and PUT declare a request body (measured: 80% of this contract)
$.paths[*][post,put]
error
response-media-type
Responses are served as application/json (measured: 100% of this contract)
$.paths[*][get,post,put,patch,delete].responses[*].content
error
schema-has-description
Every component schema carries a title or description (measured: 100% of this contract)
$.components.schemas[*]
error
property-name-casing-snake
Schema property names are snake case (measured: 100% of this contract)
$.components.schemas[*].properties[*]~
error
info-has-description
The contract's info block carries a description (measured: 100% of this contract)
$.info
error
info-title-present
Info declares title (measured: 100% of this contract)
$.info
error
info-title-min-length
Info.title runs at least 28 characters (measured: 100% of this contract)
$.info.title
error
info-description-present
Info declares description (measured: 100% of this contract)
$.info
error
info-description-min-length
Info.description runs at least 81 characters (measured: 100% of this contract)
$.info.description
error
info-version-present
Info declares version (measured: 100% of this contract)
$.info
error
info-version-semver
info.version is numeric (measured: 100% of this contract)
$.info.version
error
tag-name-present
Tag declares name (measured: 100% of this contract)
$.tags[*]
info
tag-name-casing-pascal
Tag.name is pascal case (measured: 85% of this contract)
$.tags[*].name
error
operation-tags-present
Operation declares tags (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace]
error
operation-summary-present
Operation declares summary (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace]
warn
operation-summary-min-length
Operation.summary runs at least 8 characters (measured: 95% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].summary
warn
operation-description-min-length
Operation.description runs at least 58 characters (measured: 96% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].description
error
operation-operationid-present
Operation declares operationId (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace]
error
operation-responses-present
Operation declares responses (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace]
error
parameter-name-present
Parameter declares name (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
error
parameter-name-casing-snake
Parameter.name is snake case (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*].name
error
parameter-in-present
Parameter declares in (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
error
parameter-in-values
Parameter.in is one of path, query (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*].in
error
parameter-required-present
Parameter declares required (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
error
parameter-schema-present
Parameter declares schema (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
error
requestbody-content-present
RequestBody declares content (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].requestBody
warn
requestbody-required-present
RequestBody declares required (measured: 90% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].requestBody
error
mediatype-schema-present
MediaType declares schema (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].responses[*].content[*]
error
response-description-present
Response declares description (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].responses[*]
error
response-description-min-length
Response.description runs at least 16 characters (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].responses[*].description
error
response-content-present
Response declares content (measured: 100% of this contract)
$.paths[*][get,put,post,delete,patch,options,head,trace].responses[*]
error
schema-title-present
Schema declares title (measured: 100% of this contract)
$.components.schemas[*]
error
schema-type-present
Schema declares type (measured: 100% of this contract)
$.components.schemas[*]
error
schema-type-values
Schema.type is one of object (measured: 100% of this contract)
$.components.schemas[*].type
error
schema-description-min-length
Schema.description runs at least 54 characters (measured: 100% of this contract)
$.components.schemas[*].description
error
schema-properties-present
Schema declares properties (measured: 100% of this contract)
$.components.schemas[*]

Spectral Ruleset

Raw ↑
# authorship: generated by API Evangelist tooling (derive-rules.py, 2026-11-01). x-method: generated
# Every rule below was MEASURED against Codag's own contract before it was written; a rule is present only
# when the contract satisfies it at 80% or more. Severity: 100% -> error, >= 90% -> warn, else info.
# Provenance:
#   - operation-has-operationid: 100%
#   - operation-has-summary: 100%
#   - operation-has-tags: 100%
#   - operation-has-success-response: 100%
#   - path-segment-casing-kebab: 100%
#   - path-no-trailing-slash: 100%
#   - path-params-in-braces: 100%
#   - write-declares-request-body: 80%
#   - response-media-type: 100%
#   - schema-has-description: 100%
#   - property-name-casing-snake: 100%
#   - info-has-description: 100%
#   - info-title-present: 100%
#   - info-title-min-length: 100%
#   - info-description-present: 100%
#   - info-description-min-length: 100%
#   - info-version-present: 100%
#   - info-version-semver: 100%
#   - tag-name-present: 100%
#   - tag-name-casing-pascal: 85%
#   - operation-tags-present: 100%
#   - operation-summary-present: 100%
#   - operation-summary-min-length: 95%
#   - operation-description-min-length: 97%
#   - operation-operationid-present: 100%
#   - operation-responses-present: 100%
#   - parameter-name-present: 100%
#   - parameter-name-casing-snake: 100%
#   - parameter-in-present: 100%
#   - parameter-in-values: 100%
#   - parameter-required-present: 100%
#   - parameter-schema-present: 100%
#   - requestbody-content-present: 100%
#   - requestbody-required-present: 90%
#   - mediatype-schema-present: 100%
#   - response-description-present: 100%
#   - response-description-min-length: 100%
#   - response-content-present: 100%
#   - schema-title-present: 100%
#   - schema-type-present: 100%
#   - schema-type-values: 100%
#   - schema-description-min-length: 100%
#   - schema-properties-present: 100%
x-method: generated
x-generator: derive-rules.py
x-generated: '2026-11-01'
x-source:
- openapi/codag-activate-api-openapi.yml
- openapi/codag-admin-api-openapi.yml
- openapi/codag-agent-cost-api-openapi.yml
- openapi/codag-anonymous-api-openapi.yml
- openapi/codag-auth-api-openapi.yml
x-self-check:
  status: checked
  rules: 43
  dropped: {}
extends:
- - spectral:oas
  - recommended
formats:
- oas3
rules:
  operation-has-operationid:
    description: 'Every operation declares an operationId (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: operationId
      function: truthy
    x-pattern-key: Operation.operationId|present
  operation-has-summary:
    description: 'Every operation has a summary (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: summary
      function: truthy
    x-pattern-key: Operation.summary|present
  operation-has-tags:
    description: 'Every operation is tagged (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: tags
      function: truthy
    x-pattern-key: Operation.tags|present
  operation-has-success-response:
    description: 'Every operation declares a 2xx response (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          patternProperties:
            ^2\d\d$: {}
          minProperties: 1
    x-pattern-key: Operation.responses|schema:07e20b47
  path-segment-casing-kebab:
    description: 'Path segments are kebab case (measured: 99% of this contract)'
    severity: warn
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        match: ^(/[a-z0-9]+(-[a-z0-9]+)*|/\{[^}]+\})+/?$
    x-pattern-key: Paths.{key}|pattern:^(/[a-z0-9]+(-[a-z0-9]+)*|/\{[^}]+\})+/?$
  path-no-trailing-slash:
    description: 'Paths carry no trailing slash (measured: 100% of this contract)'
    severity: error
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: ./$
    x-pattern-key: Paths.{key}|pattern:!./$
  path-params-in-braces:
    description: 'Path parameters use {braces}, not :colon (measured: 100% of this contract)'
    severity: error
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: ':'
    x-pattern-key: 'Paths.{key}|pattern:!:'
  write-declares-request-body:
    description: 'POST and PUT declare a request body (measured: 80% of this contract)'
    severity: info
    given: $.paths[*][post,put]
    then:
      field: requestBody
      function: truthy
    x-pattern-key: Operation.requestBody|present
  response-media-type:
    description: 'Responses are served as application/json (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses[*].content
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          required:
          - application/json
    x-pattern-key: Response.content|schema:2919cf38
  schema-has-description:
    description: 'Every component schema carries a title or description (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*]
    then:
      function: schema
      functionOptions:
        schema:
          anyOf:
          - required:
            - description
          - required:
            - title
    x-pattern-key: Components.schemas|schema:7af42428
  property-name-casing-snake:
    description: 'Schema property names are snake case (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*].properties[*]~
    then:
      function: pattern
      functionOptions:
        match: ^[a-z0-9]+(_[a-z0-9]+)*$
    x-pattern-key: Schema.properties{key}|pattern:^[a-z0-9]+(_[a-z0-9]+)*$
  info-has-description:
    description: 'The contract''s info block carries a description (measured: 100% of this contract)'
    severity: error
    given: $.info
    then:
      field: description
      function: truthy
    x-pattern-key: Info.description|present
  info-title-present:
    description: 'Info declares title (measured: 100% of this contract)'
    severity: error
    given: $.info
    then:
      field: title
      function: defined
    x-pattern-key: Info.title|present
  info-title-min-length:
    description: 'Info.title runs at least 28 characters (measured: 100% of this contract)'
    severity: error
    given: $.info.title
    then:
      function: length
      functionOptions:
        min: 28
    x-pattern-key: Info.title|length
  info-description-present:
    description: 'Info declares description (measured: 100% of this contract)'
    severity: error
    given: $.info
    then:
      field: description
      function: defined
    x-pattern-key: Info.description|present
  info-description-min-length:
    description: 'Info.description runs at least 81 characters (measured: 100% of this contract)'
    severity: error
    given: $.info.description
    then:
      function: length
      functionOptions:
        min: 81
    x-pattern-key: Info.description|length
  info-version-present:
    description: 'Info declares version (measured: 100% of this contract)'
    severity: error
    given: $.info
    then:
      field: version
      function: defined
    x-pattern-key: Info.version|present
  info-version-semver:
    description: 'info.version is numeric (measured: 100% of this contract)'
    severity: error
    given: $.info.version
    then:
      function: pattern
      functionOptions:
        match: ^v?\d+(\.\d+)*
    x-pattern-key: Info.version|pattern:^v?\d+(\.\d+)*
  tag-name-present:
    description: 'Tag declares name (measured: 100% of this contract)'
    severity: error
    given: $.tags[*]
    then:
      field: name
      function: defined
    x-pattern-key: Tag.name|present
  tag-name-casing-pascal:
    description: 'Tag.name is pascal case (measured: 85% of this contract)'
    severity: info
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: ^[A-Z][a-zA-Z0-9]*$
    x-pattern-key: Tag.name|pattern:^[A-Z][a-zA-Z0-9]*$
  operation-tags-present:
    description: 'Operation declares tags (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace]
    then:
      field: tags
      function: defined
    x-pattern-key: Operation.tags|present
  operation-summary-present:
    description: 'Operation declares summary (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace]
    then:
      field: summary
      function: defined
    x-pattern-key: Operation.summary|present
  operation-summary-min-length:
    description: 'Operation.summary runs at least 8 characters (measured: 95% of this contract)'
    severity: warn
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].summary
    then:
      function: length
      functionOptions:
        min: 8
    x-pattern-key: Operation.summary|length
  operation-description-min-length:
    description: 'Operation.description runs at least 58 characters (measured: 96% of this contract)'
    severity: warn
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].description
    then:
      function: length
      functionOptions:
        min: 58
    x-pattern-key: Operation.description|length
  operation-operationid-present:
    description: 'Operation declares operationId (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace]
    then:
      field: operationId
      function: defined
    x-pattern-key: Operation.operationId|present
  operation-responses-present:
    description: 'Operation declares responses (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace]
    then:
      field: responses
      function: defined
    x-pattern-key: Operation.responses|present
  parameter-name-present:
    description: 'Parameter declares name (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
    then:
      field: name
      function: defined
    x-pattern-key: Parameter.name|present
  parameter-name-casing-snake:
    description: 'Parameter.name is snake case (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*].name
    then:
      function: pattern
      functionOptions:
        match: ^[a-z0-9]+(_[a-z0-9]+)*$
    x-pattern-key: Parameter.name|pattern:^[a-z0-9]+(_[a-z0-9]+)*$
  parameter-in-present:
    description: 'Parameter declares in (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
    then:
      field: in
      function: defined
    x-pattern-key: Parameter.in|present
  parameter-in-values:
    description: 'Parameter.in is one of path, query (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*].in
    then:
      function: enumeration
      functionOptions:
        values:
        - path
        - query
    x-pattern-key: Parameter.in|enum:path,query
  parameter-required-present:
    description: 'Parameter declares required (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
    then:
      field: required
      function: defined
    x-pattern-key: Parameter.required|present
  parameter-schema-present:
    description: 'Parameter declares schema (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].parameters[*]
    then:
      field: schema
      function: defined
    x-pattern-key: Parameter.schema|present
  requestbody-content-present:
    description: 'RequestBody declares content (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].requestBody
    then:
      field: content
      function: defined
    x-pattern-key: RequestBody.content|present
  requestbody-required-present:
    description: 'RequestBody declares required (measured: 90% of this contract)'
    severity: warn
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].requestBody
    then:
      field: required
      function: defined
    x-pattern-key: RequestBody.required|present
  mediatype-schema-present:
    description: 'MediaType declares schema (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].responses[*].content[*]
    then:
      field: schema
      function: defined
    x-pattern-key: MediaType.schema|present
  response-description-present:
    description: 'Response declares description (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].responses[*]
    then:
      field: description
      function: defined
    x-pattern-key: Response.description|present
  response-description-min-length:
    description: 'Response.description runs at least 16 characters (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].responses[*].description
    then:
      function: length
      functionOptions:
        min: 16
    x-pattern-key: Response.description|length
  response-content-present:
    description: 'Response declares content (measured: 100% of this contract)'
    severity: error
    given: $.paths[*][get,put,post,delete,patch,options,head,trace].responses[*]
    then:
      field: content
      function: defined
    x-pattern-key: Response.content|present
  schema-title-present:
    description: 'Schema declares title (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*]
    then:
      field: title
      function: defined
    x-pattern-key: Schema.title|present
  schema-type-present:
    description: 'Schema declares type (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*]
    then:
      field: type
      function: defined
    x-pattern-key: Schema.type|present
  schema-type-values:
    description: 'Schema.type is one of object (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*].type
    then:
      function: enumeration
      functionOptions:
        values:
        - object
    x-pattern-key: Schema.type|enum:object
  schema-description-min-length:
    description: 'Schema.description runs at least 54 characters (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*].description
    then:
      function: length
      functionOptions:
        min: 54
    x-pattern-key: Schema.description|length
  schema-properties-present:
    description: 'Schema declares properties (measured: 100% of this contract)'
    severity: error
    given: $.components.schemas[*]
    then:
      field: properties
      function: defined
    x-pattern-key: Schema.properties|present

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/codag-rules"
All spectral rules
curl "https://apis.io/api/v1/rules?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

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.