tenderapi-fr Tenders API

Search tender notices. **Available on all tiers** (free, pro).

Operations 2

GET /tenders Search Tenders #
GET /tenders/{tender_id} Get Tender #

Work with this as data

Every API 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 apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • 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 API
curl "https://apis.io/api/v1/apis/tenderapi-fr:tenderapi-fr-tenders-api"
All apis
curl "https://apis.io/api/v1/apis?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.

OpenAPI Specification

tenderapi-fr-tenders-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Tenders API
  description: Unified French (BOAMP) + EU (TED) public procurement intelligence API. Search tenders, track award outcomes, discover winner patterns.
  version: 1.0.0
tags:
- name: tenders
  description: Search tender notices. **Available on all tiers** (free, pro).
paths:
  /tenders:
    get:
      tags:
      - tenders
      summary: Search Tenders
      operationId: search_tenders_tenders_get
      security:
      - APIKeyHeader: []
      parameters:
      - name: cpv
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          description: 'CPV code(s): repeat or comma-separate'
          title: Cpv
        description: 'CPV code(s): repeat or comma-separate'
      - name: cpv_family
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          description: '2-digit CPV family code(s), e.g. 72 (IT) or 45 (construction). Broader recall: matches BOAMP MAPA notices that have no exact 8-digit CPV.'
          title: Cpv Family
        description: '2-digit CPV family code(s), e.g. 72 (IT) or 45 (construction). Broader recall: matches BOAMP MAPA notices that have no exact 8-digit CPV.'
      - name: descripteur
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          description: BOAMP business descripteur(s), e.g. 'couverture' or 'etude,btp'. Case-insensitive substring match on descripteur_libelle. Targets MAPA notices that lack any CPV.
          title: Descripteur
        description: BOAMP business descripteur(s), e.g. 'couverture' or 'etude,btp'. Case-insensitive substring match on descripteur_libelle. Targets MAPA notices that lack any CPV.
      - name: region
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          description: 'Region slug(s): repeat or comma-separate, e.g. paca,bretagne'
          title: Region
        description: 'Region slug(s): repeat or comma-separate, e.g. paca,bretagne'
      - name: department
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          description: French department code(s), e.g. 60 (Oise) or 60,75. Best coverage on BOAMP source.
          title: Department
        description: French department code(s), e.g. 60 (Oise) or 60,75. Best coverage on BOAMP source.
      - name: country
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: ISO country code, e.g. FR
          title: Country
        description: ISO country code, e.g. FR
      - name: source
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          description: 'Source(s): boamp and/or ted. Combine as source=boamp,ted, or omit for both.'
          title: Source
        description: 'Source(s): boamp and/or ted. Combine as source=boamp,ted, or omit for both.'
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: open (deadline future, or unknown and the BOAMP notice still published or withdrawn less than 60 days ago) | closed (deadline past, or unknown and withdrawn longer ago). 'awarded' currently unsupported (no tender↔award linkage in schema); use /awards endpoint to query attributions directly.
          title: Status
        description: open (deadline future, or unknown and the BOAMP notice still published or withdrawn less than 60 days ago) | closed (deadline past, or unknown and withdrawn longer ago). 'awarded' currently unsupported (no tender↔award linkage in schema); use /awards endpoint to query attributions directly.
      - name: include_planning
        in: query
        required: false
        schema:
          type: boolean
          description: 'When true, include prior-information / planning notices (PINs) that announce upcoming procurements but are not yet biddable (no submission deadline). Default false: PINs are excluded from /tenders, except those used as a call for competition (pin-cfc-*), which are biddable and always included.'
          default: false
          title: Include Planning
        description: 'When true, include prior-information / planning notices (PINs) that announce upcoming procurements but are not yet biddable (no submission deadline). Default false: PINs are excluded from /tenders, except those used as a call for competition (pin-cfc-*), which are biddable and always included.'
      - name: procedure_type
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Procedure Type
      - name: contract_type
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Contract Type
      - name: buyer_siret
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 14-digit SIRET of the buyer
          title: Buyer Siret
        description: 14-digit SIRET of the buyer
      - name: source_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'Publisher''s own notice id, to reconcile an external export with this API (BOAMP ''AA-NNNNNN'' e.g. 26-75464, TED ''NNNNNN-AAAA'' e.g. 000001-2017). Exact match. Returns a list, not a single notice: the id is only unique per source, so combine with source= to disambiguate.'
          title: Source Id
        description: 'Publisher''s own notice id, to reconcile an external export with this API (BOAMP ''AA-NNNNNN'' e.g. 26-75464, TED ''NNNNNN-AAAA'' e.g. 000001-2017). Exact match. Returns a list, not a single notice: the id is only unique per source, so combine with source= to disambiguate.'
      - name: buyer_keyword
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'Partial match on buyer name (case-insensitive, e.g. ''oise'', ''mairie paris''). Alias: buyer_name'
          title: Buyer Keyword
        description: 'Partial match on buyer name (case-insensitive, e.g. ''oise'', ''mairie paris''). Alias: buyer_name'
      - name: keyword
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'Free-text search in title+description (FTS5, accent-insensitive, multi-token AND with prefix matching). Alias: ?q= is accepted (Google/REST convention). For OR search use FTS5 syntax: keyword=BIM OR "maquette numerique" OR IFC. Comma- or pipe-separated lists are NOT parsed as OR. Use the explicit OR keyword. Template literals (Jinja/n8n) must be interpolated client-side before sending. A non-blocking `warning` is returned in the response when a suspicious pattern is detected.'
          title: Keyword
        description: 'Free-text search in title+description (FTS5, accent-insensitive, multi-token AND with prefix matching). Alias: ?q= is accepted (Google/REST convention). For OR search use FTS5 syntax: keyword=BIM OR "maquette numerique" OR IFC. Comma- or pipe-separated lists are NOT parsed as OR. Use the explicit OR keyword. Template literals (Jinja/n8n) must be interpolated client-side before sending. A non-blocking `warning` is returned in the response when a suspicious pattern is detected.'
      - name: budget_min
        in: query
        required: false
        schema:
          anyOf:
          - type: number
          - type: 'null'
          description: 'Minimum budget (EUR). Strict by default: tenders with NULL budget are excluded. Set include_null_budget=true to include them. Note: budget data is sparse: only ~0.6% of tenders carry budget info.'
          title: Budget Min
        description: 'Minimum budget (EUR). Strict by default: tenders with NULL budget are excluded. Set include_null_budget=true to include them. Note: budget data is sparse: only ~0.6% of tenders carry budget info.'
      - name: budget_max
        in: query
        required: false
        schema:
          anyOf:
          - type: number
          - type: 'null'
          description: Maximum budget (EUR). Same NULL semantics as budget_min.
          title: Budget Max
        description: Maximum budget (EUR). Same NULL semantics as budget_min.
      - name: include_null_budget
        in: query
        required: false
        schema:
          type: boolean
          description: When true, tenders with NULL budget fields pass through budget_min/budget_max filters. Default false (strict).
          default: false
          title: Include Null Budget
        description: When true, tenders with NULL budget fields pass through budget_min/budget_max filters. Default false (strict).
      - name: deadline_after
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'ISO 8601, or alias: today, yesterday, now, Nd/Nh/Nm (e.g. 7d, 24h). Strict by default: tenders with NULL deadline are excluded. Set include_null_deadline=true to keep them. Deadline coverage on TED is partial (~70-88% on recent non-FR notices; some notice types carry no submission deadline).'
          title: Deadline After
        description: 'ISO 8601, or alias: today, yesterday, now, Nd/Nh/Nm (e.g. 7d, 24h). Strict by default: tenders with NULL deadline are excluded. Set include_null_deadline=true to keep them. Deadline coverage on TED is partial (~70-88% on recent non-FR notices; some notice types carry no submission deadline).'
      - name: deadline_before
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: ISO 8601, or alias. Same NULL semantics as deadline_after.
          title: Deadline Before
        description: ISO 8601, or alias. Same NULL semantics as deadline_after.
      - name: include_null_deadline
        in: query
        required: false
        schema:
          type: boolean
          description: When true, tenders with NULL deadline pass through deadline_after/deadline_before filters. Default false (strict). Useful on TED where many notices have no parsed submission deadline.
          default: false
          title: Include Null Deadline
        description: When true, tenders with NULL deadline pass through deadline_after/deadline_before filters. Default false (strict). Useful on TED where many notices have no parsed submission deadline.
      - name: published_after
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'ISO 8601, or alias: today, yesterday, now, Nd/Nh/Nm'
          title: Published After
        description: 'ISO 8601, or alias: today, yesterday, now, Nd/Nh/Nm'
      - name: published_before
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Published Before
      - name: sort
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'Result ordering: ''date'' (default: published_at DESC) or ''relevance'' (BM25 full-text ranking, requires keyword=; title matches weigh 5x description matches) or ''deadline'' (soonest submission deadline first, undated notices last; combine with deadline_after=today or status=open to skip expired notices). With sort=relevance each result carries a relevance_score (higher = better match; scores are only comparable within a single query).'
          title: Sort
        description: 'Result ordering: ''date'' (default: published_at DESC) or ''relevance'' (BM25 full-text ranking, requires keyword=; title matches weigh 5x description matches) or ''deadline'' (soonest submission deadline first, undated notices last; combine with deadline_after=today or status=open to skip expired notices). With sort=relevance each result carries a relevance_score (higher = better match; scores are only comparable within a single query).'
      - name: page
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          title: Page
      - name: page_size
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 20
          title: Page Size
      - name: limit
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
            maximum: 100
            minimum: 1
          - type: 'null'
          description: Alias for page_size. If both are passed, limit wins.
          title: Limit
        description: Alias for page_size. If both are passed, limit wins.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenderListOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /tenders/{tender_id}:
    get:
      tags:
      - tenders
      summary: Get Tender
      description: 'Fetch one notice by internal id, or by its publisher reference.


        Accepts both because callers rarely hold the internal id. An LLM agent

        reading a TED notice holds ''510250-2026''; someone reading a BOAMP page

        holds ''26-79926''. Until 2026-08-24 both returned a raw pydantic 422

        (''Input should be a valid integer''), the only uncurated error left on the

        surface, and the one that told the caller the least.


        Dispatch is safe on shape alone: every source_id in the corpus carries a

        hyphen (TED is NNNNNN-YYYY, BOAMP is NN-NNNNNN), so none of the 2.97M is

        purely numeric and none can be mistaken for an internal id.'
      operationId: get_tender_tenders__tender_id__get
      security:
      - APIKeyHeader: []
      parameters:
      - name: tender_id
        in: path
        required: true
        schema:
          type: string
          title: Tender Id
      - name: source
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'Disambiguate a source_id shared by two sources: ''boamp'' or ''ted''.'
          title: Source
        description: 'Disambiguate a source_id shared by two sources: ''boamp'' or ''ted''.'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenderOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    TenderOut:
      properties:
        id:
          type: integer
          title: Id
        source:
          type: string
          title: Source
        source_id:
          type: string
          title: Source Id
        source_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Source Url
        title:
          type: string
          title: Title
        description:
          anyOf:
          - type: string
          - type: 'null'
          title: Description
        cpv_codes:
          items:
            type: string
          type: array
          title: Cpv Codes
        cpv_family:
          items:
            type: string
          type: array
          title: Cpv Family
        descripteur_codes:
          items:
            type: integer
          type: array
          title: Descripteur Codes
          default: []
        descripteur_libelles:
          items:
            type: string
          type: array
          title: Descripteur Libelles
          default: []
        procedure_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Procedure Type
        contract_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Contract Type
        buyer_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Buyer Name
        buyer_siret:
          anyOf:
          - type: string
          - type: 'null'
          title: Buyer Siret
        buyer_country:
          anyOf:
          - type: string
          - type: 'null'
          title: Buyer Country
        region:
          anyOf:
          - type: string
          - type: 'null'
          title: Region
        department:
          anyOf:
          - type: string
          - type: 'null'
          title: Department
        nuts_code:
          anyOf:
          - type: string
          - type: 'null'
          title: Nuts Code
        country:
          anyOf:
          - type: string
          - type: 'null'
          title: Country
        budget_min:
          anyOf:
          - type: number
          - type: 'null'
          title: Budget Min
        budget_max:
          anyOf:
          - type: number
          - type: 'null'
          title: Budget Max
        currency:
          anyOf:
          - type: string
          - type: 'null'
          title: Currency
        published_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Published At
        deadline:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Deadline
        status:
          type: string
          title: Status
        lot_count:
          anyOf:
          - type: integer
          - type: 'null'
          title: Lot Count
        updated_at:
          type: string
          format: date-time
          title: Updated At
        relevance_score:
          anyOf:
          - type: number
          - type: 'null'
          title: Relevance Score
      type: object
      required:
      - id
      - source
      - source_id
      - source_url
      - title
      - description
      - cpv_codes
      - cpv_family
      - procedure_type
      - contract_type
      - buyer_name
      - buyer_siret
      - buyer_country
      - region
      - department
      - nuts_code
      - country
      - budget_min
      - budget_max
      - currency
      - published_at
      - deadline
      - status
      - lot_count
      - updated_at
      title: TenderOut
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    TenderListOut:
      properties:
        total:
          type: integer
          title: Total
        page:
          type: integer
          title: Page
        page_size:
          type: integer
          title: Page Size
        results:
          items:
            $ref: '#/components/schemas/TenderOut'
          type: array
          title: Results
        warning:
          anyOf:
          - type: string
          - type: 'null'
          title: Warning
        hint:
          anyOf:
          - type: string
          - type: 'null'
          title: Hint
        client_update:
          anyOf:
          - type: string
          - type: 'null'
          title: Client Update
      type: object
      required:
      - total
      - page
      - page_size
      - results
      title: TenderListOut
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key