Mindbody · API Governance Rules

Mindbody API Rules

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

53 Rules error 16 warn 32 info 5
View Rules File View on GitHub

Rule Categories

delete error get global info no oas operation parameter path paths post request response schema security servers tags

Rules

error
info-title-mindbody-prefix
API title must begin with "Mindbody".
$.info.title
error
info-description-required
API description must be present and meaningful (>= 60 chars).
$.info
warn
info-description-length
Description should be at least 60 characters.
$.info.description
warn
info-contact-required
Mindbody contact block must be present.
$.info
warn
info-license-required
License must be declared.
$.info
error
oas-version-3
Use OpenAPI 3.0.x.
$.openapi
error
servers-defined
At least one server URL must be defined.
$.servers
error
servers-https
All server URLs must use HTTPS.
$.servers[*].url
warn
servers-mindbody-host
Server URLs must point at api.mindbodyonline.com or push-api.mindbodyonline.com.
$.servers[*].url
warn
paths-version-prefix
Public API paths must include the /public/v6 prefix; Webhooks paths use /api/v1.
$.paths.*~
error
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths.*~
error
paths-no-query-strings
Paths must not contain query strings.
$.paths.*~
warn
paths-lowercase-segments
Path segments must be lowercase (Mindbody convention).
$.paths.*~
error
operation-operationid-required
Every operation must have an operationId.
$.paths.*[get,post,put,patch,delete]
warn
operation-operationid-camelcase
operationId should use camelCase.
$.paths.*[get,post,put,patch,delete].operationId
warn
operation-operationid-verb-prefix
operationId should start with a verb (get, list, add, update, delete, send, check, validate, search, upsert, return).
$.paths.*[get,post,put,patch,delete].operationId
error
operation-summary-required
Every operation must have a summary.
$.paths.*[get,post,put,patch,delete]
warn
operation-summary-mindbody-prefix
Operation summaries must begin with "Mindbody".
$.paths.*[get,post,put,patch,delete].summary
warn
operation-description-required
Every operation must have a description.
$.paths.*[get,post,put,patch,delete]
error
operation-tags-required
Every operation must have at least one tag.
$.paths.*[get,post,put,patch,delete]
warn
tags-defined-globally
Top-level tags array must be defined.
$
warn
tags-name-titlecase
Tag names should use Title Case (e.g. "Cross Site", "User Token").
$.tags[*].name
warn
tags-description-required
Every tag should have a description.
$.tags[*]
warn
parameter-description-required
Every parameter should have a description.
$.paths.*[get,post,put,patch,delete].parameters[*]
warn
parameter-siteid-header
SiteId must travel in the header, not the query.
$.paths.*[get,post,put,patch,delete].parameters[?(@.name=='SiteId' || @.name=='siteId')]
error
parameter-apikey-not-in-query
API-Key must never appear as a query parameter.
$.paths.*[get,post,put,patch,delete].parameters[?(@.name=='API-Key' || @.name=='ApiKey' || @.name=='api_key')]
info
parameter-pagination-naming
Pagination uses `request.limit` and `request.offset` (Mindbody convention).
$.paths.*[get].parameters[?(@.in=='query' && (@.name=='limit' || @.name=='offset'))]
error
request-body-json
Request bodies must offer application/json.
$.paths.*[post,put,patch].requestBody.content
error
response-success-required
Every operation must define a 2xx response.
$.paths.*[get,post,put,patch,delete].responses
warn
response-401-defined
Operations should document 401 Unauthorized.
$.paths.*[get,post,put,patch,delete].responses
info
response-404-defined
Operations should document 404 Not Found.
$.paths.*[get,post,put,patch,delete].responses
warn
response-description-required
Every response must have a description.
$.paths.*[get,post,put,patch,delete].responses.*
warn
schema-property-pascalcase
Mindbody JSON property names are PascalCase (e.g. ClientId, SiteId, Email).
$.components.schemas[*].properties.*~
info
schema-id-property-naming
Identifier properties should follow {Entity}Id PascalCase (ClientId, SiteId, StaffId).
$.components.schemas[*].properties[?(@property.match(/^[Ii]d$|^id_|^Id_/))]~
warn
schema-type-required
Schemas must declare `type`.
$.components.schemas.*
error
security-schemes-defined
At least one security scheme must be defined.
$.components.securitySchemes
error
security-apikey-header
Mindbody API key must travel in the `API-Key` request header.
$.components.securitySchemes[?(@.type=='apiKey')]
warn
security-oauth2-mindbody-urls
OAuth 2 flows must point at Mindbody Identity Service.
$.components.securitySchemes[?(@.type=='oauth2')].flows.authorizationCode
warn
global-security-defined
Global security requirement must be defined.
$
error
get-no-request-body
GET operations must not declare a request body.
$.paths.*.get
warn
delete-no-request-body
DELETE operations should not declare a request body.
$.paths.*.delete
info
post-has-body-or-explicit-query
POST operations should declare a request body when the operation mutates state.
$.paths.*.post
info
operation-microcks-extension
Every operation should carry an x-microcks-operation extension for mock-server compatibility.
$.paths.*[get,post,put,patch,delete]
warn
operation-deprecated-documented
Deprecated operations must explain the replacement in description.
$.paths.*[get,post,put,patch,delete][?(@.deprecated==true)]
warn
servers-expected-domain
Server URLs should be on the mindbodyonline.com domain.
$.servers[*].url
warn
path-params-casing
Path parameters should be camelCase (the dominant convention in this API).
$.paths[*].parameters[?(@.in=='path')].name
warn
schema-names-casing
Component schema names should be PascalCase (the dominant convention in this API).
$.components.schemas
warn
schema-properties-casing
Schema properties should be PascalCase (the dominant convention in this API).
$.components.schemas[*].properties
warn
error-schema-defined
A shared error schema (ApiError) should be defined for error payloads.
$.components.schemas
warn
operation-documents-400
Operations should document a 400 response (documented on 100% of this API's operations).
$.paths[*][get,post,put,patch,delete].responses
warn
operation-documents-403
Operations should document a 403 response (documented on 100% of this API's operations).
$.paths[*][get,post,put,patch,delete].responses
warn
operation-documents-500
Operations should document a 500 response (documented on 100% of this API's operations).
$.paths[*][get,post,put,patch,delete].responses
warn
no-empty-descriptions
Descriptions must not be empty strings.
$..description

Spectral Ruleset

Raw ↑
# mindbody — Spectral ruleset (strengthened)
# Plain Spectral. Existing hand-authored rules preserved; measured rules added
# from this provider's own OpenAPI conventions by strengthen_ruleset.py,
# then self-validated against the spec.
#
# Provenance:
#   - servers-https-only: 100% of servers already https (error)
#   - servers-expected-domain: 2/2 servers on mindbodyonline.com
#   - path-params-casing: camel @ 100% (n=9)
#   - operationid-casing: camel @ 100% (n=154)
#   - schema-names-casing: pascal @ 100% (n=352)
#   - schema-properties-casing: pascal @ 97% (n=2125)
#   - security: global (root) — NOT emitting operation-security-required
#   - error-schema-defined: ApiError
#   - operation-documents-400: 100% adherence
#   - operation-documents-401: 100% adherence
#   - operation-documents-403: 100% adherence
#   - operation-documents-404: 100% adherence
#   - operation-documents-500: 100% adherence
#   - merge: kept 44 existing, added 9 measured, upgraded 0
#   - added: servers-expected-domain, path-params-casing, schema-names-casing, schema-properties-casing, error-schema-defined, operation-documents-400, operation-documents-403, operation-documents-500, no-empty-descriptions
extends:
  - spectral:oas
rules:
  info-title-mindbody-prefix:
    description: API title must begin with "Mindbody".
    message: '{{property}} must start with "Mindbody" (got "{{value}}").'
    given: $.info.title
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^Mindbody\b
  info-description-required:
    description: API description must be present and meaningful (>= 60 chars).
    given: $.info
    severity: error
    then:
      field: description
      function: truthy
  info-description-length:
    description: Description should be at least 60 characters.
    given: $.info.description
    severity: warn
    then:
      function: length
      functionOptions:
        min: 60
  info-contact-required:
    description: Mindbody contact block must be present.
    given: $.info
    severity: warn
    then:
      field: contact
      function: truthy
  info-license-required:
    description: License must be declared.
    given: $.info
    severity: warn
    then:
      field: license
      function: truthy
  oas-version-3:
    description: Use OpenAPI 3.0.x.
    given: $.openapi
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^3\.0\.
  servers-defined:
    description: At least one server URL must be defined.
    given: $.servers
    severity: error
    then:
      function: length
      functionOptions:
        min: 1
  servers-https:
    description: All server URLs must use HTTPS.
    given: $.servers[*].url
    severity: error
    then:
      function: pattern
      functionOptions:
        match: ^https://
  servers-mindbody-host:
    description: Server URLs must point at api.mindbodyonline.com or push-api.mindbodyonline.com.
    given: $.servers[*].url
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^https://(api|push-api)\.mindbodyonline\.com
  paths-version-prefix:
    description: Public API paths must include the /public/v6 prefix; Webhooks paths use /api/v1.
    given: $.paths.*~
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^/(public/v6|api/v1)/
  paths-no-trailing-slash:
    description: Paths must not end with a trailing slash.
    given: $.paths.*~
    severity: error
    then:
      function: pattern
      functionOptions:
        notMatch: .+/$
  paths-no-query-strings:
    description: Paths must not contain query strings.
    given: $.paths.*~
    severity: error
    then:
      function: pattern
      functionOptions:
        notMatch: \?
  paths-lowercase-segments:
    description: Path segments must be lowercase (Mindbody convention).
    given: $.paths.*~
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^[a-z0-9/{}\-_.]+$
  operation-operationid-required:
    description: Every operation must have an operationId.
    given: $.paths.*[get,post,put,patch,delete]
    severity: error
    then:
      field: operationId
      function: truthy
  operation-operationid-camelcase:
    description: operationId should use camelCase.
    given: $.paths.*[get,post,put,patch,delete].operationId
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  operation-operationid-verb-prefix:
    description: operationId should start with a verb (get, list, add, update, delete, send, check, validate,
      search, upsert, return).
    given: $.paths.*[get,post,put,patch,delete].operationId
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^(get|list|add|update|delete|create|remove|send|check|validate|search|upsert|return|cancel|issue)
  operation-summary-required:
    description: Every operation must have a summary.
    given: $.paths.*[get,post,put,patch,delete]
    severity: error
    then:
      field: summary
      function: truthy
  operation-summary-mindbody-prefix:
    description: Operation summaries must begin with "Mindbody".
    given: $.paths.*[get,post,put,patch,delete].summary
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^Mindbody\b
  operation-description-required:
    description: Every operation must have a description.
    given: $.paths.*[get,post,put,patch,delete]
    severity: warn
    then:
      field: description
      function: truthy
  operation-tags-required:
    description: Every operation must have at least one tag.
    given: $.paths.*[get,post,put,patch,delete]
    severity: error
    then:
      field: tags
      function: schema
      functionOptions:
        schema:
          type: array
          minItems: 1
  tags-defined-globally:
    description: Top-level tags array must be defined.
    given: $
    severity: warn
    then:
      field: tags
      function: truthy
  tags-name-titlecase:
    description: Tag names should use Title Case (e.g. "Cross Site", "User Token").
    given: $.tags[*].name
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^[A-Z][A-Za-z0-9]*( [A-Z][A-Za-z0-9]*)*$
  tags-description-required:
    description: Every tag should have a description.
    given: $.tags[*]
    severity: warn
    then:
      field: description
      function: truthy
  parameter-description-required:
    description: Every parameter should have a description.
    given: $.paths.*[get,post,put,patch,delete].parameters[*]
    severity: warn
    then:
      field: description
      function: truthy
  parameter-siteid-header:
    description: SiteId must travel in the header, not the query.
    message: SiteId must be a header parameter on Mindbody Public API operations.
    given: $.paths.*[get,post,put,patch,delete].parameters[?(@.name=='SiteId' || @.name=='siteId')]
    severity: warn
    then:
      field: in
      function: pattern
      functionOptions:
        match: ^header$
  parameter-apikey-not-in-query:
    description: API-Key must never appear as a query parameter.
    given: $.paths.*[get,post,put,patch,delete].parameters[?(@.name=='API-Key' || @.name=='ApiKey' ||
      @.name=='api_key')]
    severity: error
    then:
      field: in
      function: pattern
      functionOptions:
        notMatch: ^query$
  parameter-pagination-naming:
    description: Pagination uses `request.limit` and `request.offset` (Mindbody convention).
    given: $.paths.*[get].parameters[?(@.in=='query' && (@.name=='limit' || @.name=='offset'))]
    severity: info
    message: Prefer `request.limit` / `request.offset` over bare `limit` / `offset` to match Mindbody
      Public API style.
    then:
      function: falsy
  request-body-json:
    description: Request bodies must offer application/json.
    given: $.paths.*[post,put,patch].requestBody.content
    severity: error
    then:
      field: application/json
      function: truthy
  response-success-required:
    description: Every operation must define a 2xx response.
    given: $.paths.*[get,post,put,patch,delete].responses
    severity: error
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          patternProperties:
            ^2[0-9]{2}$: {}
          minProperties: 1
          additionalProperties: true
  response-401-defined:
    description: Operations should document 401 Unauthorized.
    given: $.paths.*[get,post,put,patch,delete].responses
    severity: warn
    then:
      field: '401'
      function: truthy
  response-404-defined:
    description: Operations should document 404 Not Found.
    given: $.paths.*[get,post,put,patch,delete].responses
    severity: info
    then:
      field: '404'
      function: truthy
  response-description-required:
    description: Every response must have a description.
    given: $.paths.*[get,post,put,patch,delete].responses.*
    severity: warn
    then:
      field: description
      function: truthy
  schema-property-pascalcase:
    description: Mindbody JSON property names are PascalCase (e.g. ClientId, SiteId, Email).
    given: $.components.schemas[*].properties.*~
    severity: warn
    then:
      function: pattern
      functionOptions:
        match: ^[A-Z][A-Za-z0-9]*$
  schema-id-property-naming:
    description: Identifier properties should follow {Entity}Id PascalCase (ClientId, SiteId, StaffId).
    given: $.components.schemas[*].properties[?(@property.match(/^[Ii]d$|^id_|^Id_/))]~
    severity: info
    message: Prefer fully-qualified PascalCase identifiers like ClientId, SiteId rather than bare `Id`
      or snake_case.
    then:
      function: falsy
  schema-type-required:
    description: Schemas must declare `type`.
    given: $.components.schemas.*
    severity: warn
    then:
      field: type
      function: truthy
  security-schemes-defined:
    description: At least one security scheme must be defined.
    given: $.components.securitySchemes
    severity: error
    then:
      function: truthy
  security-apikey-header:
    description: Mindbody API key must travel in the `API-Key` request header.
    given: $.components.securitySchemes[?(@.type=='apiKey')]
    severity: error
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          properties:
            in:
              const: header
            name:
              const: API-Key
          required:
          - in
          - name
  security-oauth2-mindbody-urls:
    description: OAuth 2 flows must point at Mindbody Identity Service.
    given: $.components.securitySchemes[?(@.type=='oauth2')].flows.authorizationCode
    severity: warn
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          properties:
            authorizationUrl:
              type: string
              pattern: ^https://signin\.mindbodyonline\.com/connect/authorize$
            tokenUrl:
              type: string
              pattern: ^https://signin\.mindbodyonline\.com/connect/token$
  global-security-defined:
    description: Global security requirement must be defined.
    given: $
    severity: warn
    then:
      field: security
      function: truthy
  get-no-request-body:
    description: GET operations must not declare a request body.
    given: $.paths.*.get
    severity: error
    then:
      field: requestBody
      function: falsy
  delete-no-request-body:
    description: DELETE operations should not declare a request body.
    given: $.paths.*.delete
    severity: warn
    then:
      field: requestBody
      function: falsy
  post-has-body-or-explicit-query:
    description: POST operations should declare a request body when the operation mutates state.
    given: $.paths.*.post
    severity: info
    then:
      field: requestBody
      function: truthy
  operation-microcks-extension:
    description: Every operation should carry an x-microcks-operation extension for mock-server compatibility.
    given: $.paths.*[get,post,put,patch,delete]
    severity: info
    then:
      field: x-microcks-operation
      function: truthy
  operation-deprecated-documented:
    description: Deprecated operations must explain the replacement in description.
    given: $.paths.*[get,post,put,patch,delete][?(@.deprecated==true)]
    severity: warn
    then:
      field: description
      function: pattern
      functionOptions:
        match: (?i)(deprecated|replaced|migrate)
  servers-expected-domain:
    description: Server URLs should be on the mindbodyonline.com domain.
    severity: warn
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: mindbodyonline\.com
  path-params-casing:
    description: Path parameters should be camelCase (the dominant convention in this API).
    severity: warn
    given: $.paths[*].parameters[?(@.in=='path')].name
    then:
      function: casing
      functionOptions:
        type: camel
  schema-names-casing:
    description: Component schema names should be PascalCase (the dominant convention in this API).
    severity: warn
    given: $.components.schemas
    then:
      field: '@key'
      function: pattern
      functionOptions:
        match: ^[A-Z][A-Za-z0-9]*$
  schema-properties-casing:
    description: Schema properties should be PascalCase (the dominant convention in this API).
    severity: warn
    given: $.components.schemas[*].properties
    then:
      field: '@key'
      function: pattern
      functionOptions:
        match: ^[A-Z][A-Za-z0-9]*$
  error-schema-defined:
    description: A shared error schema (ApiError) should be defined for error payloads.
    severity: warn
    given: $.components.schemas
    then:
      field: ApiError
      function: truthy
  operation-documents-400:
    description: Operations should document a 400 response (documented on 100% of this API's operations).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '400'
      function: truthy
  operation-documents-403:
    description: Operations should document a 403 response (documented on 100% of this API's operations).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '403'
      function: truthy
  operation-documents-500:
    description: Operations should document a 500 response (documented on 100% of this API's operations).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '500'
      function: truthy
  no-empty-descriptions:
    description: Descriptions must not be empty strings.
    severity: warn
    given: $..description
    then:
      function: truthy