Stotles · OpenAPI Overlay 1.0.0

API Evangelist enhancements for the Stotles Public API

9 actions 9 updates update extends openapi/stotles-public-api-openapi.yml
Derived by API Evangelist Built from the contracts Stotles publishes. Stotles did not publish this file.
View Overlay File View on GitHub Overlay Specification

What the actions change

x-shape-warningx-apievangelistx-issuancex-key-propertiesx-graph-hubx-double-counting-hazardx-pagination-hazardx-cost-hint

Targets 9

$.info
$.servers
$.components.securitySchemes.apiKey
$.paths['/v1/notices/search'].get
$.paths['/v1/buyers/search'].get.parameters[?(@.name=='query')]
$.paths['/v1/suppliers/search'].get.parameters[?(@.name=='query')]
$.components.schemas.ProblemDetails
$.components.responses.RateLimited
$.tags

OpenAPI Overlay

Raw ↑
# authorship: generated by API Evangelist tooling. Stamped 2026-08-18
# on the file's own generator header (roadmap#64). An unmarked file is
# NOT assumed to be ours -- absence of evidence was never stamped.
x-method: generated
overlay: 1.0.0
info:
  title: API Evangelist enhancements for the Stotles Public API
  version: 1.0.0
x-generated: '2026-08-14'
x-method: generated
x-source: >-
  Generated by the API Evangelist enrichment pipeline against
  openapi/stotles-public-api-openapi.yml (harvested verbatim from
  https://api.stotles.com/v1/openapi.json, HTTP 200, 2026-08-14). This overlay carries OUR
  annotations only; the original spec is never mutated.
extends: openapi/stotles-public-api-openapi.yml

x-notes: >-
  The Stotles spec is already well-annotated by its author — it documents pagination, RFC 9457
  errors, casing, money handling and versioning in info.description, and every enum carries
  x-enumDescriptions. This overlay therefore adds only what the provider does NOT state: the
  undocumented runtime signals we observed on live responses, the traversal semantics that make the
  entity graph navigable, the double-counting hazard on framework values, and links to the derived
  artifacts in this repo.

actions:
  - target: $.info
    description: Attach API Evangelist provenance and cross-links to the derived artifact set.
    update:
      x-apievangelist:
        profile: https://apis.io/provider/stotles
        harvested: '2026-08-14'
        harvested_from: https://api.stotles.com/v1/openapi.json
        artifacts:
          authentication: authentication/stotles-authentication.yml
          conventions: conventions/stotles-conventions.yml
          errors: errors/stotles-problem-types.yml
          data_model: data-model/stotles-data-model.yml
          lifecycle: lifecycle/stotles-lifecycle.yml
          rate_limits: rate-limits/stotles-rate-limits.yml
          mcp: mcp/stotles-mcp.yml
          tool_crosswalk: mcp/stotles-tool-crosswalk.yml
          skills: skills/_index.yml

  - target: $.servers
    description: >-
      Record the observed edge and CORS posture of the production server. Stotles pins
      Access-Control-Allow-Origin to https://app.stotles.com, which means this API cannot be called
      from a third-party browser client — an integration-shaping fact the spec does not state.
    update:
      - url: https://api.stotles.com
        description: Production
        x-observed:
          probed: '2026-08-14'
          edge: Amazon CloudFront
          http_versions: [h2, h3]
          cors_allow_origin: https://app.stotles.com
          browser_callable_by_third_parties: false
          hsts: false
          request_id_header: request-id
          note: >-
            `request-id` is returned on every response including 401s and is the identifier to quote
            to Stotles support. It is undocumented.

  - target: $.components.securitySchemes.apiKey
    description: Record how keys are obtained and the operational constraints on them.
    update:
      x-issuance:
        self_serve: false
        channel: Customer Success Manager
        statement: 'Keys are issued by Stotles — ask your Customer Success Manager.'
      x-key-properties:
        identity_granularity: organization
        prefix_published: false
        test_mode: false
        rotation_endpoint: false
        note: >-
          One long-lived static key per organization. No documented prefix, so the key is not
          recognizable by shape to secret scanners; no test key, so all development runs against
          production data; no self-service rotation.

  - target: $.paths['/v1/notices/search'].get
    description: >-
      Flag the two highest-consequence behaviours of the hub operation: it is the only way to
      traverse buyer/supplier/framework relationships, and unfiltered results double-count framework
      value.
    update:
      x-graph-hub: >-
        This API has no sub-resource paths. buyer -> notices, supplier -> notices and
        framework -> notices are ALL performed by re-calling this operation with buyer_id,
        supplier_id or framework_id. Expect it to dominate call volume, and budget it against the
        3 requests/second ceiling.
      x-double-counting-hazard: >-
        A framework-establishing notice and every call-off made under it both appear in unfiltered
        results, and both carry a `value`. Summing `value` across an unfiltered result set therefore
        overstates market size. Use framework_activity=only_call_offs or
        framework_activity=exclude_framework_agreements when totalling spend.
      x-pagination-hazard: >-
        A page shorter than `limit` is NOT the last page. Terminate only on next_cursor == null.
      x-cost-hint: >-
        limit defaults to 20 but accepts up to 50. Paging at 50 cuts request count by 60% against
        the 1,000/hour allowance.

  - target: $.paths['/v1/buyers/search'].get.parameters[?(@.name=='query')]
    description: >-
      Highlight the surface's sharpest inconsistency — `query` is a required single string here but
      an optional array on the notices search.
    update:
      x-shape-warning: >-
        On this operation `query` is a REQUIRED single string (2-200 chars). On
        /v1/notices/search the same parameter name is an OPTIONAL ARRAY of terms combined by
        `query_operator`. Same name, different type and requiredness. This is the most likely cause
        of a 400 for a client that generalizes one call pattern across the API.

  - target: $.paths['/v1/suppliers/search'].get.parameters[?(@.name=='query')]
    description: Mirror the required-single-string warning onto the supplier search.
    update:
      x-shape-warning: >-
        REQUIRED single string (2-200 chars), unlike the optional array `query` on
        /v1/notices/search.

  - target: $.components.schemas.ProblemDetails
    description: Bind the error envelope to the derived problem-type catalog and its handling matrix.
    update:
      x-catalog: errors/stotles-problem-types.yml
      x-type-uris-dereferenceable: false
      x-type-uris-note: >-
        The `type` URIs under https://api.stotles.com/problems/ are stable identifiers but return
        404 — no documentation is served at them. RFC 9457 permits this; the catalog in errors/
        substitutes for it.
      x-retry-matrix:
        '400': never — fix the request using errors[].parameter
        '401': never — credentials problem, escalate to a human
        '404': never — treat as absent, not as failure
        '429': yes — sleep exactly Retry-After seconds
        '500': yes — exponential backoff, log request-id

  - target: $.components.responses.RateLimited
    description: Record that Retry-After is the only rate-limit signal the API emits.
    update:
      x-signal-gap: >-
        No X-RateLimit-* or RFC 9239 RateLimit-* headers are emitted on successful responses. A
        client cannot see remaining budget; it can only discover the limit by crossing it. Documented
        limits are 1,000 requests/hour and 3 requests/second, both per API key.
      x-limits: {per_hour: 1000, per_second: 3, scope: per-api-key}

  - target: $.tags
    description: >-
      Note that the four tags map 1:1 onto the four addressable entities, and that no write
      operations exist on any of them.
    update:
      - name: Notices
        description: Public sector procurement notices.
        x-entity: Notice
        x-operations: {read: 2, write: 0}
      - name: Buyers
        description: Public sector buyers and their procurement activity.
        x-entity: Buyer
        x-operations: {read: 2, write: 0}
      - name: Suppliers
        description: Suppliers bidding for and winning public sector contracts.
        x-entity: Supplier
        x-operations: {read: 2, write: 0}
      - name: Frameworks
        description: Framework agreements and dynamic purchasing systems.
        x-entity: Framework
        x-operations: {read: 2, write: 0}
      - name: x-surface-summary
        description: >-
          8 operations, all GET, all read-only. No write path exists, which is why no idempotency
          mechanism is offered or needed — every request is safely retryable by HTTP method.

Work with this as data

Every overlay 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 openapi overlays

4 MCP tools reach this
  • find_overlaysBrowse and filter every overlay 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 overlay
curl "https://apis.io/api/v1/overlays/stotles-public-api-overlay"
All openapi overlays
curl "https://apis.io/api/v1/overlays?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.