OpenMercantil Public Procurement API

Public procurement awards (PLACSP) and grants (BDNS)

OpenAPI Specification

openmercantil-public-procurement-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: OpenMercantil Public Procurement API
  version: 1.9.3
  summary: Versioned public-read, browser-account, billing, support and provider-callback contracts.
  description: 'Public JSON API for Spanish company information derived from BORME and other public sources.
    OpenMercantil is an independent informational service; it is NOT the BOE, BORME or Registro Mercantil
    and does NOT replace official certificates or registry extracts.


    **Rate limits.** Free: 60 req/min y 200 req/día por IP. Planes superiores (Profesional 5.000 req/día,
    MAX 50.000 req/día, Enterprise 500.000+ req/día) según cuenta y API key. Cabeceras `X-RateLimit-Limit`,
    `X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-OpenMercantil-Plan`, `Retry-After`.


    **License and attribution.** Source-specific metadata in each response and the active versioned source
    catalog prevails. OpenMercantil does not relicense upstream content under a blanket license. Unknown,
    review and restricted datasets are omitted or return `503 legal_layer_unavailable`. BOE/BORME material
    is re-used under Ley 37/2007 and its official version remains boe.es. Court judgments are not exposed;
    CENDOJ remains citation-index only under CGPJ Reglamento 3/2010.


    **Machine-readable catalog (DCAT-AP-ES):** https://openmercantil.es/catalog.rdf'
  termsOfService: https://openmercantil.es/terminos-de-uso
  contact:
    name: OpenMercantil
    url: https://openmercantil.es/soporte
    email: social@openmercantil.es
  license:
    name: Source-specific upstream terms; see response catalog metadata
    url: https://openmercantil.es/terminos-de-uso
  x-publisher:
    name: OpenMercantil
    url: https://openmercantil.es/
    email: social@openmercantil.es
  x-spatial: http://publications.europa.eu/resource/authority/country/ESP
  x-temporal: 2009-01-01/..
  x-language: es
  x-dcat-catalog: https://openmercantil.es/catalog.rdf
  x-rate-limit:
    free:
      per_min: 60
      per_day: 200
      kind: anonymous-ip
    profesional:
      per_min: 120
      per_day: 5000
      kind: api-key
    max:
      per_min: 600
      per_day: 50000
      kind: api-key
    enterprise:
      per_min: 1200
      per_day: 500000
      kind: contract
  x-methodology: https://openmercantil.es/metodologia
  x-sources: https://openmercantil.es/fuentes
  x-corrections: https://openmercantil.es/correcciones
  x-contract-status: Public read, browser-account and provider-callback surfaces are explicitly separated
    in this contract. Operator/admin routes are excluded. The public MCP consumes only the allowlisted
    GET read plane.
  x-account-segment-contract:
    projection: company_public_v2 immutable corporate sidecar
    synchronous_row_cap: 500
    bounded_count_cap: 50001
    count_semantics: The segment run response count is the number of rows returned, never a global total.
      Dataset preview uses total_is_lower_bound=true and total_lower_bound when the bounded count reaches
      50001.
    related_web_dataset_surface:
      preview_path: /mi-cuenta/datasets/preview
      export_path: /mi-cuenta/datasets/export.csv
      synchronous_export_max_rows: 500
      overflow_status: 503
      overflow_error: async_export_required
  x-company-identity-contract:
    version: '1.0'
    projection: company_public_v2 immutable generation-bound corporate sidecar
    applies_to: Every /api/v1/company/{slug}*, /api/v1/empresa/{slug}* and /api/v1/grafo/{slug} read before
      any report, cache, graph or dataset lookup. /api/v1/companies/compare resolves both requested subjects
      in one bounded company_public_v2 batch before either row is exposed; MCP company tools inherit these
      preflights through REST.
    resolution:
      published: canonical corporate slug admitted
      safe_alias: internally canonicalized and Content-Location emitted
      withheld: neutral 404; includes absent, personal and ambiguous/quarantined identities
      unavailable: 503 with no-store; clients must not infer absence
    search: Exact corporate CIF, exact canonical/safe-alias slug, or bounded name_prefix2 pool scored
      in application code. DNI/NIE and ambiguous CIFs return zero items.
    public_company_count: company_public_projection_state.row_count
servers:
- url: https://openmercantil.es
  description: Production
tags:
- name: Public Procurement
  description: Public procurement awards (PLACSP) and grants (BDNS)
paths:
  /api/v1/company/{slug}/contracts:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: companies:read
      operationId: getCompanyBySlugContracts
      x-query-contract:
        allowed:
        - limit
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
        range: 422 validation_failed
      tags:
      - Companies
      - Public Procurement
      summary: Get PLACSP procurement notices linked to a legal entity
      description: Requires the legal-first PLACSP v3 projection, including typed budget, estimate and
        award fields plus corporate supplier edges. It never falls back to the legacy untyped table and
        never sums mixed monetary concepts. A CIF link is documentary and does not prove payment or executed
        spend.
      x-rate-limit: plan policy (see info.x-rate-limit)
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          example: banco-santander-s-a
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 30
      responses:
        '200':
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
          description: Contracts list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyProcurementResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/PublicReadUnavailable'
  /api/v1/company/{slug}/procurement:
    get:
      operationId: getCompanyBySlugProcurement
      x-query-contract:
        allowed: []
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
      tags:
      - Companies
      - Public Procurement
      summary: Alias of /contracts
      description: Documentary alias for /contracts endpoint. Same payload and projection requirements;
        `_alias_of` contains the canonical route.
      x-rate-limit: plan policy (see info.x-rate-limit)
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Procurement awards (alias of contracts)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyProcurementResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          description: Legal-first PLACSP projection unavailable
  /api/v1/company/{slug}/grants:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: companies:read
      operationId: getCompanyBySlugGrants
      x-query-contract:
        allowed:
        - limit
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
        range: 422 validation_failed
      tags:
      - Companies
      - Public Procurement
      summary: Get BDNS public grants
      description: Read only company_integrations_public_v1 after company_public_v2 admission. Returns
        up to 200 attested BDNS rows and never queries the canonical grants table. Monetary values are
        awarded amounts in integer cents, never payments; ambiguous raw zero is null. Empty is complete
        bounded-projection coverage, not proof of absence upstream.
      parameters:
      - $ref: '#/components/parameters/CompanySlugPath'
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 100
      - $ref: '#/components/parameters/IfNoneMatchHeader'
      responses:
        '200':
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
            Content-Location:
              $ref: '#/components/headers/CompanyContentLocation'
            ETag:
              $ref: '#/components/headers/EntityTag'
            Cache-Control:
              $ref: '#/components/headers/PrivateRevalidationCacheControl'
          description: Grants list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyGrantsResponse'
        '304':
          description: The admitted company, projection generation and legal envelope have not changed
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
            Content-Location:
              $ref: '#/components/headers/CompanyContentLocation'
            ETag:
              $ref: '#/components/headers/EntityTag'
            Cache-Control:
              $ref: '#/components/headers/PrivateRevalidationCacheControl'
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          $ref: '#/components/responses/PublicReadUnavailable'
  /api/v1/persona/{slug}/contracts:
    get:
      operationId: getPersonaBySlugContracts
      tags:
      - Persons
      - Public Procurement
      summary: Person-to-procurement derivation (unavailable)
      description: Fail-closed derived route. It always returns 503 before reading data because `person_contracts_v1`
        is not authorized. A future implementation requires a new reviewed projection and contract version.
      deprecated: true
      x-rate-limit: plan policy (see info.x-rate-limit)
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
      responses:
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          $ref: '#/components/responses/LegalLayerUnavailable'
  /api/v1/company/{slug}/ted:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: companies:read
      operationId: getCompanyBySlugTed
      x-query-contract:
        allowed:
        - limit
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
        range: 422 validation_failed
      tags:
      - Companies
      - Public Procurement
      summary: Get TED notice records linked to this corporate NIF
      description: 'Read only company_integrations_public_v1 after company_public_v2 admission. Returns
        up to 100 minimized TED notice links: publication number/date, buyer and official notice URL.
        Tenderer, currency and free-form connector fields are excluded. Rows do not prove payment, executed
        spend or current contractual status.'
      x-rate-limit: free 60/min · 200/day
      parameters:
      - $ref: '#/components/parameters/CompanySlugPath'
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 50
      - $ref: '#/components/parameters/IfNoneMatchHeader'
      responses:
        '200':
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
            Content-Location:
              $ref: '#/components/headers/CompanyContentLocation'
            ETag:
              $ref: '#/components/headers/EntityTag'
            Cache-Control:
              $ref: '#/components/headers/PrivateRevalidationCacheControl'
          description: Bounded TED documentary records linked to the admitted corporate NIF
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyTedResponse'
        '304':
          description: The admitted company, projection generation and legal envelope have not changed
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
            Content-Location:
              $ref: '#/components/headers/CompanyContentLocation'
            ETag:
              $ref: '#/components/headers/EntityTag'
            Cache-Control:
              $ref: '#/components/headers/PrivateRevalidationCacheControl'
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          $ref: '#/components/responses/PublicReadUnavailable'
  /api/v1/contracts/top-companies:
    get:
      operationId: getContractsTopCompanies
      x-query-contract:
        allowed:
        - limit
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
        range: 422 validation_failed
      tags:
      - Public Procurement
      - Datasets
      summary: Corporate suppliers ranked by PLACSP award procedures
      description: Compatibility alias of `/api/v1/tenders/suppliers`. Reads only `placsp_public_company_summary`,
        ranks corporate suppliers by award-procedure count and never publishes a monetary ranking or rollup.
        Natural persons are excluded. `province` and `cnae` are rejected until dedicated offline projections
        exist.
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 50
          default: 20
      x-rate-limit: plan policy (see info.x-rate-limit); enforced before projection access
      responses:
        '200':
          description: Sanitized corporate supplier ranking
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenderSupplierResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          description: PLACSP public projection unavailable
  /api/v1/contracts/top-persons:
    get:
      operationId: getContractsTopPersons
      tags:
      - Public Procurement
      - Datasets
      summary: Top persons by PLACSP-signatory companies
      description: Fail-closed derived route. It always returns 503 before reading data because `person_contracts_v1`
        is not authorized. A future implementation requires a new reviewed projection and contract version.
      deprecated: true
      x-rate-limit: plan policy (see info.x-rate-limit)
      responses:
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          $ref: '#/components/responses/LegalLayerUnavailable'
  /api/v1/contracts/top-companies.csv:
    get:
      operationId: getContractsTopCompaniesCsv
      x-query-contract:
        allowed:
        - limit
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
        range: 422 validation_failed
      tags:
      - Public Procurement
      - Datasets
      summary: Corporate suppliers by award procedures (CSV)
      description: Bounded CSV (maximum 100 rows) generated from `placsp_public_company_summary`. Columns
        distinguish notice count from award-procedure count and contain no monetary aggregate.
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 100
      x-rate-limit: plan policy (see info.x-rate-limit); enforced before projection access
      responses:
        '200':
          description: CSV download
          content:
            text/csv:
              schema:
                type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          description: PLACSP public projection unavailable
  /api/v1/contracts/top-persons.csv:
    get:
      operationId: getContractsTopPersonsCsv
      x-query-contract:
        allowed: []
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        lexical: 400 invalid_parameter
      tags:
      - Public Procurement
      - Datasets
      summary: Top persons by PLACSP-signatory companies (CSV)
      description: Fail-closed CSV equivalent of `/api/v1/contracts/top-persons`; it always returns 503
        before reading data.
      deprecated: true
      x-rate-limit: plan policy (see info.x-rate-limit)
      responses:
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          $ref: '#/components/responses/LegalLayerUnavailable'
  /api/v1/tenders:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: tenders:read
      operationId: searchTenders
      tags:
      - Public Procurement
      summary: Search public procurement notices
      description: 'Cursor-paginated PLACSP notice search over the materialized legal-first projection.
        The query contract is closed-world and scalar: unknown names, arrays and lexical type mismatches
        return 400; validly typed values outside documented ranges return 422. Full-text query indexes
        notice object and buyer only; it never indexes supplier names. Full-text plus structured filters
        returns 422 until a compound offline projection exists. CPV accepts an indexed 2-8 digit prefix,
        may combine only with published_from/published_to, and returns 503 rather than falling back when
        its CPV-date projection or exact index is unavailable. supplier_cif is resolved by the generation-bound
        offline 0062 projection and matches either the notice''s top-level corporate adjudicatario or
        any materialized corporate coadjudicator. It may combine with phase, buyer_nif, province and publication
        dates; open_only and every monetary filter require a future compound projection and return 422.
        Because one notice can have several adjudicators, a search summary may display a different admitted
        top-level supplier; tender detail retains the complete materialized result set. Natural-person
        supplier names and identifiers are withheld together. Budget, estimated value and award are separate
        source-reported fields and none proves paid or executed spend. open_only freezes one UTC date
        for SQL filtering, row is_open semantics and cursor binding.'
      x-data-source: PLACSP
      x-privacy: Natural-person and uncertain buyer/supplier identity is withheld. buyer_nif and supplier_cif
        accept entity identifiers only.
      x-performance-budget-ms: 200
      x-query-contract:
        allowed:
        - q
        - cpv
        - phase
        - province
        - buyer_nif
        - supplier_cif
        - open_only
        - amount_kind
        - min_amount_eur
        - max_amount_eur
        - published_from
        - published_to
        - limit
        - cursor
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
        range: 422 validation_failed
        combinations: supplier_cif supports phase, buyer_nif, province and publication dates; supplier_cif
          plus open_only or amount_kind/min_amount_eur/max_amount_eur returns 422 until a compound projection
          exists
      parameters:
      - name: q
        in: query
        schema:
          type: string
          minLength: 3
          maxLength: 200
        description: Object/buyer terms only; supplier column is excluded.
      - name: cpv
        in: query
        schema:
          type: string
          pattern: ^[0-9]{2,8}$
        description: Indexed PLACSP v1.1 CPV prefix matching primary or lot codes. It may combine only
          with published_from/published_to; q or another structured filter returns 422. Missing table
          or exact CPV-date index fails closed with 503; no request-path fallback is executed.
      - name: phase
        in: query
        schema:
          type: string
          enum:
          - PUB
          - PRE
          - EV
          - ADJ
          - RES
          - ANUL
      - name: province
        in: query
        schema:
          type: string
          pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
        description: 'Partial coverage: rows not yet geocoded are excluded.'
      - name: buyer_nif
        in: query
        schema:
          type: string
          pattern: ^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$
        description: Entity identifier only; DNI/NIE is rejected.
      - name: supplier_cif
        in: query
        schema:
          type: string
          pattern: ^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$
        description: Corporate CIF only; DNI/NIE is rejected. Matches the top-level adjudicatario or any
          materialized coadjudicator through the generation-bound offline 0062 projection. A summary item
          may display another supplier; detail retains all materialized results.
      - name: open_only
        in: query
        schema:
          type: boolean
          default: false
        description: Strict boolean. Canonical true/false and compatibility query lexemes 1/0 are accepted;
          every other value is rejected.
      - name: amount_kind
        in: query
        schema:
          type: string
          enum:
          - budget
          - estimated
          - award
        description: Required whenever min_amount_eur or max_amount_eur is used; prevents mixing monetary
          semantics.
      - name: min_amount_eur
        in: query
        schema:
          type: number
          minimum: 0
          maximum: 10000000000
        description: Minimum value for the explicit amount_kind; only EUR projections are currently filterable.
      - name: max_amount_eur
        in: query
        schema:
          type: number
          minimum: 0
          maximum: 10000000000
        description: Maximum value for the explicit amount_kind; only EUR projections are currently filterable.
      - name: published_from
        in: query
        schema:
          type: string
          format: date
        description: Real UTC calendar date; impossible dates are rejected.
      - name: published_to
        in: query
        schema:
          type: string
          format: date
        description: Real UTC calendar date; impossible dates and a value before published_from are rejected.
      - name: limit
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 50
          default: 25
      - name: cursor
        in: query
        schema:
          type: string
          pattern: ^[A-Za-z0-9_-]{8,256}$
        description: Opaque cursor bound to the immutable PLACSP projection generation, current ordering
          mode and complete normalized filter set; a projection swap or filter change invalidates it.
          It is not an authentication credential and clients must never synthesize it.
      responses:
        '200':
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
          description: Sanitized notice page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenderSearchResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          description: A validly typed value is outside its documented range, a lower bound exceeds its
            upper bound, full-text is combined with a structured filter, CPV plus a non-date structured
            filter requires an offline compound projection, or supplier_cif is combined with open_only
            or any monetary filter before its compound offline projection exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          description: PLACSP dataset, public FTS, CPV prefix projection or exact CPV-date index unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/v1/tenders/{key}:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: tenders:read
      operationId: getTender
      tags:
      - Public Procurement
      summary: Get a sanitized procurement notice
      description: Returns an explicit public projection by stable url_key, including materialized CODICE
        v3 lots, CPV codes and results when available. Raw XML, local paths, document binaries and uncertain
        supplier identities are never returned.
      x-data-source: PLACSP
      x-query-contract:
        allowed: []
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
      parameters:
      - name: key
        in: path
        required: true
        schema:
          type: string
          pattern: ^[a-z0-9]{6,48}$
          example: 0d7736fd49044863
      responses:
        '200':
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
          description: Sanitized notice detail
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required:
                - schema_version
                - tender
                - lots
                - results
                - collections
                - coverage
                - attribution
                - disclaimer
                - _source_catalog
                - _data_sources_used
                properties:
                  schema_version:
                    type: string
                  tender:
                    $ref: '#/components/schemas/TenderNotice'
                  lots:
                    type: array
                    maxItems: 100
                    items:
                      $ref: '#/components/schemas/TenderLot'
                  results:
                    type: array
                    maxItems: 100
                    items:
                      $ref: '#/components/schemas/TenderResult'
                  collections:
                    $ref: '#/components/schemas/TenderCollectionMetadata'
                  coverage:
                    $ref: '#/components/schemas/TenderCoverage'
                  attribution:
                    type: string
                  disclaimer:
                    type: string
                  _source_catalog:
                    $ref: '#/components/schemas/SourceCatalogEnvelope'
                  _data_sources_used:
                    type: array
                    minItems: 1
                    items:
                      $ref: '#/components/schemas/PublicSourcePolicyMetadata'
                  _attributions:
                    type: object
                    additionalProperties:
                      type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/PublicReadUnavailable'
  /api/v1/tenders/stats:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: tenders:read
      operationId: getTenderStats
      tags:
      - Public Procurement
      summary: Get non-personal procurement coverage metrics
      description: Publishes O(1) materialized record, freshness, document, geography and CODICE-v3 coverage.
        Monetary rollups are deliberately omitted even though amount semantics are separated.
      x-data-source: PLACSP
      x-query-contract:
        allowed: []
        unknown: 400 invalid_parameter
        non_scalar: 400 invalid_parameter
      responses:
        '200':
          headers:
            X-Data-Sources:
              $ref: '#/components/headers/XDataSources'
            X-Source-Catalog-Version:
              $ref: '#/components/headers/XSourceCatalogVersion'
            X-Attribution-Required:
              $ref: '#/components/headers/XAttributionRequired'
          description: Coverage and quality metrics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenderStats'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/PublicReadUnavailable'
  /api/v1/tenders/suppliers:
    get:
      security:
      - {}
      - apiKey: []
      - bearerAuth: []
      x-api-credential-scope: tenders:read
      operationId: listTenderSuppliers
      tags:
      - Public Procurement
      summary: List corporate suppliers by award count
      description: Only rows joined to an OpenMercantil company with a matching corporate CIF are eligible.
        Natural persons are omitted. Ranking is by documented award count; monetary totals are not published.
      x-data-source: PLACSP+BORME
      x-query-contract:
        allowed:
        - limit
        unknown: 400 invalid

# --- truncated at 32 KB (74 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/openmercantil/refs/heads/main/openapi/openmercantil-public-procurement-api-openapi.yml