Yawplet · API Governance Rules

Yawplet API Rules

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

25 Rules error 19 warn 4 info 2
Published by Yawplet Served by the provider at https://yawplet.com/governance/spectral.yml; the copy below was fetched from there.
View Rules File View on GitHub

Rule Categories

agentic create error headers info money needs no operation parameters paths post problem read request security servers success tags webhooks

Rules

error
operation-operationid-camel-case
Every operation has an operationId in camelCase. MCP tools, the Postman collection and the API reference are all keyed on it.
$.paths[*][get,put,post,delete,patch,options,head,trace]$.webhooks[*][get,put,post,delete,patch,options,head,trace]
error
operation-summary-and-description
Every operation has both a summary (one line, used as the tool title) and a description (what it does, what it costs, what comes back).
$.paths[*][get,put,post,delete,patch,options,head,trace]$.webhooks[*][get,put,post,delete,patch,options,head,trace]
error
operation-single-declared-tag
Every operation has exactly one tag, and it is one of the tags declared at the root (operation-tag-defined from spectral:oas checks the declaration). One tag means one folder in the Postman collection and one section in the reference.
$.paths[*][get,put,post,delete,patch,options,head,trace]$.webhooks[*][get,put,post,delete,patch,options,head,trace]
info
tags-described
Every root tag has a description, so a reader knows what the group is for.
$.tags[*]
error
info-contact-complete
info.contact names the operator with a name, an email and a url.
$.info
warn
info-terms-of-service
info.termsOfService is an https URL. Each site serves the same terms at /terms/.
$.info
error
servers-https-only
Every server URL is https. The sites are served only over TLS.
$.servers[*]
error
paths-versioned-lowercase
Every path starts with /v1 and is made of lowercase segments (a-z, 0-9, hyphen) or {snake_case} parameters, with no trailing slash and no query string.
$.paths
error
error-responses-problem-json
Every 4xx and 5xx response offers application/problem+json (RFC 9457). Agents can rely on type, title, status, detail and a stable code.
$.paths[*][*].responses[?(@property.match(/^[45]/))]
error
problem-schema-is-error
Every application/problem+json body is the shared Error schema, by reference, so there is one problem shape across the API.
$.components.responses[*].content['application/problem+json'].schema$.paths[*][*].responses[?(@property.match(/^[45]/))].content['application/problem+json'].schema
error
success-response-example
Every 2xx response returns application/json with an example (or named examples). Agents learn the shape from the example before they spend anything.
$.paths[*][*].responses[?(@property.match(/^2/))]
error
request-body-example
Every JSON request body has an example (or named examples), and the Postman collection sends it as the default body.
$.paths[*][*].requestBody.content['application/json']
error
create-post-safe-to-retry-and-try
createPost declares the Idempotency-Key header (a retry is never charged twice) and the dry_run query parameter (every check, nothing charged). Posting costs money, so both are part of the contract.
$.paths['/v1/posts'].post
error
no-credentials-in-query
No query parameter carries a credential. Keys travel in the Authorization header, never in a URL that ends up in logs.
$.paths[*][*].parameters[?(@.in == 'query')]$.paths[*].parameters[?(@.in == 'query')]$.components.parameters[?(@.in == 'query')]
error
security-scheme-bearer-header
Every security scheme is HTTP bearer, so the API key is sent as Authorization Bearer and nowhere else.
$.components.securitySchemes[*]
error
webhooks-signed-delivery
The contract has a webhooks section, and every outbound delivery declares the Standard Webhooks headers: webhook-id, webhook-timestamp and webhook-signature, all required.
$
error
agentic-access-declared
Every operation carries x-agentic-access: action-class (read, acting, connected), consequence (read, write, financial, irreversible), human-in-the-loop (none, recommended, required), reversible, and notes. Defined in x-agentic-access-schema.
$.paths[*][get,put,post,delete,patch,options,head,trace]$.webhooks[*][get,put,post,delete,patch,options,head,trace]
error
agentic-access-irreversible-not-reversible
An operation whose consequence is irreversible cannot also say reversible true.
$.paths[*][?(@ && @['x-agentic-access'] && @['x-agentic-access'].consequence == 'irreversible')]
error
agentic-access-402-is-financial
An operation that can answer 402 (the owner must pay) moves money, so its x-agentic-access consequence is financial.
$.paths[*][?(@ && @.responses && @.responses['402'])]
error
read-is-read
An operation whose action-class is read has no write consequence. It either changes nothing (read) or, like search past its free allowance, costs money (financial).
$.paths[*][?(@ && @['x-agentic-access'] && @['x-agentic-access']['action-class'] == 'read')]
warn
needs-human-carries-account-url
The NeedsHuman problem shows account_url and for_human: true, the hand-off every agent must recognise.
$.components.responses.NeedsHuman.content['application/problem+json'].example
error
post-content-untrusted
A published Post declares content_trust: untrusted-user-content as a constant, so every reader is told not to follow what a post says.
$.components.schemas.Post.properties.content_trust
warn
money-integer-micro-dollars
An integer money field (price, balance, amount, charged, refunded, penalty_if_abuse, threshold, price_each) says in its description that it is micro-dollars (1 USD = 1,000,000).
$..properties[?(@property.match(/^(price|balance|amount|charged|refunded|penalty_if_abuse|threshold|price_each)$/) && @.type == 'integer')]
warn
parameters-described
Every parameter has a description.
$.paths[*][*].parameters[*]$.paths[*].parameters[*]$.webhooks[*][*].parameters[*]$.components.parameters[*]
info
headers-no-x-prefix
Header names do not use the X- prefix (RFC 6648); we use registered or draft names such as RateLimit and Idempotency-Key.
$.paths[*][*].responses[*].headers$.components.headers

Spectral Ruleset

Raw ↑
# harvested from https://yawplet.com/governance/spectral.yml on 2026-10-05 — authored and served by the provider
x-method: harvested
x-source: https://yawplet.com/governance/spectral.yml
x-fetched: '2026-10-05'
extends:
- - spectral:oas
  - recommended
formats:
- oas3
documentationUrl: https://yawplet.com/governance/
rules:
  license-url: 'off'
  operation-operationid-camel-case:
    description: Every operation has an operationId in camelCase. MCP tools, the Postman collection and the API
      reference are all keyed on it.
    message: '{{path}} needs a camelCase operationId: {{error}}'
    severity: error
    given:
    - $.paths[*][get,put,post,delete,patch,options,head,trace]
    - $.webhooks[*][get,put,post,delete,patch,options,head,trace]
    then:
    - field: operationId
      function: truthy
    - field: operationId
      function: casing
      functionOptions:
        type: camel
  operation-summary-and-description:
    description: Every operation has both a summary (one line, used as the tool title) and a description (what it
      does, what it costs, what comes back).
    message: '{{path}} is missing a summary or a description.'
    severity: error
    given:
    - $.paths[*][get,put,post,delete,patch,options,head,trace]
    - $.webhooks[*][get,put,post,delete,patch,options,head,trace]
    then:
    - field: summary
      function: truthy
    - field: description
      function: truthy
  operation-single-declared-tag:
    description: Every operation has exactly one tag, and it is one of the tags declared at the root (operation-tag-defined
      from spectral:oas checks the declaration). One tag means one folder in the Postman collection and one section
      in the reference.
    message: '{{path}} must have exactly one declared tag.'
    severity: error
    given:
    - $.paths[*][get,put,post,delete,patch,options,head,trace]
    - $.webhooks[*][get,put,post,delete,patch,options,head,trace]
    then:
      field: tags
      function: schema
      functionOptions:
        schema:
          type: array
          minItems: 1
          maxItems: 1
          items:
            type: string
  tags-described:
    description: Every root tag has a description, so a reader knows what the group is for.
    message: Tag {{path}} has no description.
    severity: info
    given: $.tags[*]
    then:
      field: description
      function: truthy
  info-contact-complete:
    description: info.contact names the operator with a name, an email and a url.
    message: 'info.contact needs name, email and url: {{error}}'
    severity: error
    given: $.info
    then:
      field: contact
      function: schema
      functionOptions:
        schema:
          type: object
          required:
          - name
          - email
          - url
  info-terms-of-service:
    description: info.termsOfService is an https URL. Each site serves the same terms at /terms/.
    message: info.termsOfService must be an https URL.
    severity: warn
    given: $.info
    then:
      field: termsOfService
      function: pattern
      functionOptions:
        match: ^https://
  servers-https-only:
    description: Every server URL is https. The sites are served only over TLS.
    message: Server {{value}} is not https.
    severity: error
    given: $.servers[*]
    then:
      field: url
      function: pattern
      functionOptions:
        match: ^https://
  paths-versioned-lowercase:
    description: Every path starts with /v1 and is made of lowercase segments (a-z, 0-9, hyphen) or {snake_case}
      parameters, with no trailing slash and no query string.
    message: Path {{property}} is not /v1 plus lowercase segments without a trailing slash.
    severity: error
    given: $.paths
    then:
      field: '@key'
      function: pattern
      functionOptions:
        match: ^/v1(/([a-z][a-z0-9-]*|\{[a-z_]+\}))+$
  error-responses-problem-json:
    description: Every 4xx and 5xx response offers application/problem+json (RFC 9457). Agents can rely on type,
      title, status, detail and a stable code.
    message: '{{path}} does not offer application/problem+json.'
    severity: error
    given: $.paths[*][*].responses[?(@property.match(/^[45]/))]
    then:
      field: content
      function: schema
      functionOptions:
        schema:
          type: object
          required:
          - application/problem+json
  problem-schema-is-error:
    description: Every application/problem+json body is the shared Error schema, by reference, so there is one problem
      shape across the API.
    message: '{{path}} must be $ref: #/components/schemas/Error'
    severity: error
    resolved: false
    given:
    - $.components.responses[*].content['application/problem+json'].schema
    - $.paths[*][*].responses[?(@property.match(/^[45]/))].content['application/problem+json'].schema
    then:
      field: $ref
      function: pattern
      functionOptions:
        match: ^#/components/schemas/Error$
  success-response-example:
    description: Every 2xx response returns application/json with an example (or named examples). Agents learn the
      shape from the example before they spend anything.
    message: '{{path}} needs application/json with an example.'
    severity: error
    given: $.paths[*][*].responses[?(@property.match(/^2/))]
    then:
      field: content
      function: schema
      functionOptions:
        schema:
          type: object
          required:
          - application/json
          properties:
            application/json:
              anyOf:
              - required:
                - example
              - required:
                - examples
  request-body-example:
    description: Every JSON request body has an example (or named examples), and the Postman collection sends it
      as the default body.
    message: '{{path}} needs a request example.'
    severity: error
    given: $.paths[*][*].requestBody.content['application/json']
    then:
      function: schema
      functionOptions:
        schema:
          anyOf:
          - required:
            - example
          - required:
            - examples
  create-post-safe-to-retry-and-try:
    description: createPost declares the Idempotency-Key header (a retry is never charged twice) and the dry_run
      query parameter (every check, nothing charged). Posting costs money, so both are part of the contract.
    message: createPost must declare Idempotency-Key (header) and dry_run (query).
    severity: error
    given: $.paths['/v1/posts'].post
    then:
      field: parameters
      function: schema
      functionOptions:
        schema:
          type: array
          allOf:
          - contains:
              type: object
              required:
              - name
              - in
              properties:
                name:
                  const: Idempotency-Key
                in:
                  const: header
          - contains:
              type: object
              required:
              - name
              - in
              properties:
                name:
                  const: dry_run
                in:
                  const: query
  no-credentials-in-query:
    description: No query parameter carries a credential. Keys travel in the Authorization header, never in a URL
      that ends up in logs.
    message: Query parameter {{value}} looks like a credential.
    severity: error
    given:
    - $.paths[*][*].parameters[?(@.in == 'query')]
    - $.paths[*].parameters[?(@.in == 'query')]
    - $.components.parameters[?(@.in == 'query')]
    then:
      field: name
      function: pattern
      functionOptions:
        notMatch: /^(api[_-]?key|key|token|access[_-]?token|secret|password|auth|authorization|session)$/i
  security-scheme-bearer-header:
    description: Every security scheme is HTTP bearer, so the API key is sent as Authorization Bearer and nowhere
      else.
    message: '{{path}} must be type http, scheme bearer.'
    severity: error
    given: $.components.securitySchemes[*]
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          required:
          - type
          - scheme
          properties:
            type:
              const: http
            scheme:
              const: bearer
  webhooks-signed-delivery:
    description: 'The contract has a webhooks section, and every outbound delivery declares the Standard Webhooks
      headers: webhook-id, webhook-timestamp and webhook-signature, all required.'
    message: 'webhooks must exist and each delivery must declare required webhook-id, webhook-timestamp and webhook-signature
      headers: {{error}}'
    severity: error
    given: $
    then:
      field: webhooks
      function: schema
      functionOptions:
        schema:
          type: object
          minProperties: 1
          additionalProperties:
            type: object
            required:
            - post
            properties:
              post:
                type: object
                required:
                - parameters
                properties:
                  parameters:
                    type: array
                    allOf:
                    - contains:
                        type: object
                        required:
                        - name
                        - in
                        - required
                        properties:
                          name:
                            const: webhook-id
                          in:
                            const: header
                          required:
                            const: true
                    - contains:
                        type: object
                        required:
                        - name
                        - in
                        - required
                        properties:
                          name:
                            const: webhook-timestamp
                          in:
                            const: header
                          required:
                            const: true
                    - contains:
                        type: object
                        required:
                        - name
                        - in
                        - required
                        properties:
                          name:
                            const: webhook-signature
                          in:
                            const: header
                          required:
                            const: true
  agentic-access-declared:
    description: 'Every operation carries x-agentic-access: action-class (read, acting, connected), consequence
      (read, write, financial, irreversible), human-in-the-loop (none, recommended, required), reversible, and notes.
      Defined in x-agentic-access-schema.'
    message: '{{path}} needs a complete x-agentic-access: {{error}}'
    severity: error
    given:
    - $.paths[*][get,put,post,delete,patch,options,head,trace]
    - $.webhooks[*][get,put,post,delete,patch,options,head,trace]
    then:
      field: x-agentic-access
      function: schema
      functionOptions:
        schema:
          type: object
          additionalProperties: false
          required:
          - action-class
          - consequence
          - human-in-the-loop
          - reversible
          - notes
          properties:
            action-class:
              enum:
              - read
              - acting
              - connected
            consequence:
              enum:
              - read
              - write
              - financial
              - irreversible
            human-in-the-loop:
              enum:
              - none
              - recommended
              - required
            reversible:
              type: boolean
            notes:
              type: string
              minLength: 20
  agentic-access-irreversible-not-reversible:
    description: An operation whose consequence is irreversible cannot also say reversible true.
    message: '{{path}} says irreversible but reversible is not false.'
    severity: error
    given: $.paths[*][?(@ && @['x-agentic-access'] && @['x-agentic-access'].consequence == 'irreversible')]
    then:
      field: x-agentic-access.reversible
      function: schema
      functionOptions:
        schema:
          const: false
  agentic-access-402-is-financial:
    description: An operation that can answer 402 (the owner must pay) moves money, so its x-agentic-access consequence
      is financial.
    message: '{{path}} can answer 402, so its consequence must be financial.'
    severity: error
    given: $.paths[*][?(@ && @.responses && @.responses['402'])]
    then:
      field: x-agentic-access.consequence
      function: pattern
      functionOptions:
        match: ^financial$
  read-is-read:
    description: An operation whose action-class is read has no write consequence. It either changes nothing (read)
      or, like search past its free allowance, costs money (financial).
    message: '{{path}} is a read, so its consequence must be read or financial.'
    severity: error
    given: $.paths[*][?(@ && @['x-agentic-access'] && @['x-agentic-access']['action-class'] == 'read')]
    then:
      field: x-agentic-access.consequence
      function: pattern
      functionOptions:
        match: ^(read|financial)$
  needs-human-carries-account-url:
    description: 'The NeedsHuman problem shows account_url and for_human: true, the hand-off every agent must recognise.'
    message: 'The NeedsHuman example must carry account_url and for_human: true.'
    severity: warn
    given: $.components.responses.NeedsHuman.content['application/problem+json'].example
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          required:
          - account_url
          - for_human
          properties:
            for_human:
              const: true
  post-content-untrusted:
    description: 'A published Post declares content_trust: untrusted-user-content as a constant, so every reader
      is told not to follow what a post says.'
    message: Post.content_trust must be const untrusted-user-content.
    severity: error
    given: $.components.schemas.Post.properties.content_trust
    then:
      field: const
      function: pattern
      functionOptions:
        match: ^untrusted-user-content$
  money-integer-micro-dollars:
    description: An integer money field (price, balance, amount, charged, refunded, penalty_if_abuse, threshold,
      price_each) says in its description that it is micro-dollars (1 USD = 1,000,000).
    message: '{{path}} is money: say micro-dollars in its description.'
    severity: warn
    given: $..properties[?(@property.match(/^(price|balance|amount|charged|refunded|penalty_if_abuse|threshold|price_each)$/)
      && @.type == 'integer')]
    then:
      field: description
      function: pattern
      functionOptions:
        match: micro-dollars
  parameters-described:
    description: Every parameter has a description.
    message: Parameter {{path}} has no description.
    severity: warn
    given:
    - $.paths[*][*].parameters[*]
    - $.paths[*].parameters[*]
    - $.webhooks[*][*].parameters[*]
    - $.components.parameters[*]
    then:
      field: description
      function: truthy
  headers-no-x-prefix:
    description: Header names do not use the X- prefix (RFC 6648); we use registered or draft names such as RateLimit
      and Idempotency-Key.
    message: Header {{property}} uses the X- prefix.
    severity: info
    given:
    - $.paths[*][*].responses[*].headers
    - $.components.headers
    then:
      field: '@key'
      function: pattern
      functionOptions:
        notMatch: ^[Xx]-

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/yawplet-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.