Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Tender Awards 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: Awards
description: Search award outcomes. **Requires the pro tier** (free keys get the exact count, rows locked).
paths:
/awards:
get:
tags:
- Awards
summary: Search Awards
operationId: search_awards_awards_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). Broader recall: matches BOAMP MAPA awards that have no exact 8-digit CPV.'
title: Cpv Family
description: '2-digit CPV family code(s), e.g. 72 (IT). Broader recall: matches BOAMP MAPA awards 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'. Case-insensitive substring match on descripteur_libelle.
title: Descripteur
description: BOAMP business descripteur(s), e.g. 'couverture'. Case-insensitive substring match on descripteur_libelle.
- name: region
in: query
required: false
schema:
anyOf:
- type: array
items:
type: string
- type: 'null'
description: 'Region slug(s): repeat or comma-separate'
title: Region
description: 'Region slug(s): repeat or comma-separate'
- name: department
in: query
required: false
schema:
anyOf:
- type: array
items:
type: string
- type: 'null'
description: French department code(s), e.g. 60 or 60,75
title: Department
description: French department code(s), e.g. 60 or 60,75
- name: country
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Country
- 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: winner_siret
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: SIRET (14-digit) of the winning establishment
title: Winner Siret
description: SIRET (14-digit) of the winning establishment
- name: winner_siren
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: SIREN (9-digit, company-level) of the winner. Matches every establishment of the company (a SIRET is SIREN + 5-digit NIC). Use winner_siret= to target a single establishment.
title: Winner Siren
description: SIREN (9-digit, company-level) of the winner. Matches every establishment of the company (a SIRET is SIREN + 5-digit NIC). Use winner_siret= to target a single establishment.
- name: winner_name
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Partial name of winner
title: Winner Name
description: Partial name of winner
- name: buyer_siret
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Buyer Siret
- 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. Exact match, returns a list. The id is only unique per source, so combine with source= to disambiguate. Note award and tender ids live in separate namespaces but do overlap (5 cases), so the same value may resolve on both endpoints.
title: Source Id
description: Publisher's own notice id, to reconcile an external export with this API. Exact match, returns a list. The id is only unique per source, so combine with source= to disambiguate. Note award and tender ids live in separate namespaces but do overlap (5 cases), so the same value may resolve on both endpoints.
- name: buyer_keyword
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: 'Partial match on buyer name (case-insensitive). Alias: buyer_name'
title: Buyer Keyword
description: 'Partial match on buyer name (case-insensitive). Alias: buyer_name'
- name: keyword
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: 'Free-text search across winner_name + buyer_name + descripteur (FTS5, accent-insensitive, multi-token AND). Alias: ?q= is accepted (Google/REST convention). For OR search use FTS5 syntax: keyword=foo OR "bar baz" OR qux. Comma- or pipe-separated lists are NOT parsed as OR. Template literals (Jinja/n8n) must be interpolated client-side. A non-blocking `warning` is returned when a suspicious pattern is detected. For finer-grained search use winner_name=, buyer_keyword=, or descripteur=.'
title: Keyword
description: 'Free-text search across winner_name + buyer_name + descripteur (FTS5, accent-insensitive, multi-token AND). Alias: ?q= is accepted (Google/REST convention). For OR search use FTS5 syntax: keyword=foo OR "bar baz" OR qux. Comma- or pipe-separated lists are NOT parsed as OR. Template literals (Jinja/n8n) must be interpolated client-side. A non-blocking `warning` is returned when a suspicious pattern is detected. For finer-grained search use winner_name=, buyer_keyword=, or descripteur=.'
- name: amount_min
in: query
required: false
schema:
anyOf:
- type: number
- type: 'null'
description: 'Minimum award amount (EUR). Note: amounts >= 1,000,000,000 are NULLed during ingest to filter source-side sentinel placeholders (e.g. 9999999999.99) that would otherwise corrupt aggregates. Filters in that range return 0 results. Real megacontracts (RTE/Hitachi-class) require manual whitelisting: contact support.'
title: Amount Min
description: 'Minimum award amount (EUR). Note: amounts >= 1,000,000,000 are NULLed during ingest to filter source-side sentinel placeholders (e.g. 9999999999.99) that would otherwise corrupt aggregates. Filters in that range return 0 results. Real megacontracts (RTE/Hitachi-class) require manual whitelisting: contact support.'
- name: amount_max
in: query
required: false
schema:
anyOf:
- type: number
- type: 'null'
description: Maximum award amount (EUR). Same 1B EUR clamp as amount_min.
title: Amount Max
description: Maximum award amount (EUR). Same 1B EUR clamp as amount_min.
- name: awarded_after
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: 'ISO 8601, or alias: today, yesterday, now, Nd/Nh/Nm'
title: Awarded After
description: 'ISO 8601, or alias: today, yesterday, now, Nd/Nh/Nm'
- name: awarded_before
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Awarded Before
- name: outcome
in: query
required: false
schema:
anyOf:
- type: array
items:
type: string
- type: 'null'
description: 'Filter by outcome: ''awarded'' (default behaviour: winner present), ''cancelled'' (SANS_SUITE), ''unsuccessful'' (INFRUCTUEUX). Repeat or comma-separate. Omit to include all.'
title: Outcome
description: 'Filter by outcome: ''awarded'' (default behaviour: winner present), ''cancelled'' (SANS_SUITE), ''unsuccessful'' (INFRUCTUEUX). Repeat or comma-separate. Omit to include all.'
- 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: include_duplicates
in: query
required: false
schema:
type: boolean
description: Return the BOAMP/TED twins of the same award as separate rows. On FR the same award is usually published on both within 3 days (~16% of the FR rows), so one of the two is hidden by default. Pass true to see every published notice, for instance to reconcile against a source's own export. Naming a single source= also disables the de-duplication.
default: false
title: Include Duplicates
description: Return the BOAMP/TED twins of the same award as separate rows. On FR the same award is usually published on both within 3 days (~16% of the FR rows), so one of the two is hidden by default. Pass true to see every published notice, for instance to reconcile against a source's own export. Naming a single source= also disables the de-duplication.
- name: sort
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: 'Result ordering: ''date'' (default: awarded_at DESC) or ''relevance'' (BM25 full-text ranking, requires keyword=; winner_name matches weigh 8, buyer_name 4, descripteur 2). 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: awarded_at DESC) or ''relevance'' (BM25 full-text ranking, requires keyword=; winner_name matches weigh 8, buyer_name 4, descripteur 2). 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.
- name: has_parent_tender
in: query
required: false
schema:
anyOf:
- type: boolean
- type: 'null'
description: Filter by linkage to the originating tender (AO). true = only awards linked to their tender; false = only standalone awards (negotiated/direct procedures with no published prior notice). Omit for all.
title: Has Parent Tender
description: Filter by linkage to the originating tender (AO). true = only awards linked to their tender; false = only standalone awards (negotiated/direct procedures with no published prior notice). Omit for all.
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AwardListOut'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/awards/winner-intel:
get:
tags:
- Awards
summary: Winner Intelligence
description: 'Aggregate: top winners by contract count and total value. **Requires pro tier.**'
operationId: winner_intelligence_awards_winner_intel_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. 45 (BTP). Broader recall: matches awards that have no exact 8-digit CPV.'
title: Cpv Family
description: '2-digit CPV family code(s), e.g. 45 (BTP). Broader recall: matches awards that have no exact 8-digit CPV.'
- name: region
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Region
- name: country
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
default: FR
title: Country
- name: source
in: query
required: false
schema:
anyOf:
- type: array
items:
type: string
- type: 'null'
description: 'Source(s): boamp and/or ted. Omit for both, which is the de-duplicated view. Naming a single source gives that source''s own figures instead, WITHOUT de-duplication (see include_duplicates).'
title: Source
description: 'Source(s): boamp and/or ted. Omit for both, which is the de-duplicated view. Naming a single source gives that source''s own figures instead, WITHOUT de-duplication (see include_duplicates).'
- name: year
in: query
required: false
schema:
anyOf:
- type: integer
- type: 'null'
title: Year
- name: winner_siret
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Focus on a specific establishment by SIRET (14-digit)
title: Winner Siret
description: Focus on a specific establishment by SIRET (14-digit)
- name: winner_siren
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: 'Focus on a company by SIREN (9-digit): aggregates all its establishments'
title: Winner Siren
description: 'Focus on a company by SIREN (9-digit): aggregates all its establishments'
- name: include_duplicates
in: query
required: false
schema:
type: boolean
description: Count the BOAMP/TED twins of the same award separately. On FR the same award is usually published on both within 3 days, which inflates these aggregates by ~18% in both contract count and value, so they are de-duplicated by default. Pass true for the raw, double-counted figures (e.g. to reconcile with an export built before 2026-09-17).
default: false
title: Include Duplicates
description: Count the BOAMP/TED twins of the same award separately. On FR the same award is usually published on both within 3 days, which inflates these aggregates by ~18% in both contract count and value, so they are de-duplicated by default. Pass true for the raw, double-counted figures (e.g. to reconcile with an export built before 2026-09-17).
- name: limit
in: query
required: false
schema:
type: integer
maximum: 50
minimum: 1
description: Number of top winners to return (1-50, matches the tier page-size cap).
default: 20
title: Limit
description: Number of top winners to return (1-50, matches the tier page-size cap).
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/WinnerIntelOut'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/awards/{award_id}:
get:
tags:
- Awards
summary: Get Award
operationId: get_award_awards__award_id__get
security:
- APIKeyHeader: []
parameters:
- name: award_id
in: path
required: true
schema:
type: integer
title: Award Id
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AwardOut'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
components:
schemas:
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
WinnerIntelOut:
properties:
total:
type: integer
title: Total
results:
items:
$ref: '#/components/schemas/WinnerStat'
type: array
title: Results
deduplicated:
type: boolean
title: Deduplicated
default: true
type: object
required:
- total
- results
title: WinnerIntelOut
WinnerStat:
properties:
winner_name:
anyOf:
- type: string
- type: 'null'
title: Winner Name
winner_siret:
anyOf:
- type: string
- type: 'null'
title: Winner Siret
contract_count:
type: integer
title: Contract Count
total_amount:
anyOf:
- type: number
- type: 'null'
title: Total Amount
avg_amount:
anyOf:
- type: number
- type: 'null'
title: Avg Amount
name_variants:
anyOf:
- items:
type: string
type: array
- type: 'null'
title: Name Variants
type: object
required:
- winner_name
- winner_siret
- contract_count
- total_amount
- avg_amount
title: WinnerStat
AwardListOut:
properties:
total:
type: integer
title: Total
page:
type: integer
title: Page
page_size:
type: integer
title: Page Size
results:
items:
$ref: '#/components/schemas/AwardOut'
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
locked:
anyOf:
- type: boolean
- type: 'null'
title: Locked
upgrade:
anyOf:
- type: string
- type: 'null'
title: Upgrade
deduplicated:
type: boolean
title: Deduplicated
default: true
type: object
required:
- total
- page
- page_size
- results
title: AwardListOut
AwardOut:
properties:
id:
type: integer
title: Id
tender_id:
anyOf:
- type: integer
- type: 'null'
title: Tender Id
source:
type: string
title: Source
source_id:
type: string
title: Source Id
source_url:
anyOf:
- type: string
- type: 'null'
title: Source Url
winner_name:
anyOf:
- type: string
- type: 'null'
title: Winner Name
winner_siret:
anyOf:
- type: string
- type: 'null'
title: Winner Siret
winner_country:
anyOf:
- type: string
- type: 'null'
title: Winner Country
amount:
anyOf:
- type: number
- type: 'null'
title: Amount
currency:
anyOf:
- type: string
- type: 'null'
title: Currency
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: []
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
buyer_name:
anyOf:
- type: string
- type: 'null'
title: Buyer Name
buyer_siret:
anyOf:
- type: string
- type: 'null'
title: Buyer Siret
awarded_at:
anyOf:
- type: string
format: date-time
- type: 'null'
title: Awarded At
awarded_at_source:
anyOf:
- type: string
- type: 'null'
title: Awarded At Source
outcome:
anyOf:
- type: string
- type: 'null'
title: Outcome
published_at:
anyOf:
- type: string
format: date-time
- type: 'null'
title: Published At
relevance_score:
anyOf:
- type: number
- type: 'null'
title: Relevance Score
has_parent_tender:
type: boolean
title: Has Parent Tender
description: 'True when this award is linked to its originating tender (AO).
False for standalone awards: negotiated/direct procedures with no
published prior contract notice. This is normal in public procurement,
not a data gap: a large share of awards never had a separate tender.'
readOnly: true
type: object
required:
- id
- tender_id
- source
- source_id
- source_url
- winner_name
- winner_siret
- winner_country
- amount
- currency
- cpv_codes
- cpv_family
- region
- department
- nuts_code
- country
- buyer_name
- buyer_siret
- awarded_at
- published_at
- has_parent_tender
title: AwardOut
HTTPValidationError:
properties:
detail:
items:
$ref: '#/components/schemas/ValidationError'
type: array
title: Detail
type: object
title: HTTPValidationError
securitySchemes:
APIKeyHeader:
type: apiKey
in: header
name: X-API-Key