{"openapi":"3.1.0","info":{"title":"TenderAPI","description":"Unified French (BOAMP) + EU (TED) public procurement intelligence API. Search tenders, track award outcomes, discover winner patterns.","version":"1.0.0"},"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":"string"},{"type":"null"}],"description":"Source: boamp or ted","title":"Source"},"description":"Source: boamp or ted"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"open (deadline future or unknown) | closed (deadline past). 'awarded' currently unsupported (no tender↔award linkage in schema); use /awards endpoint to query attributions directly.","title":"Status"},"description":"open (deadline future or unknown) | closed (deadline past). '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.","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."},{"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":"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). 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). 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","operationId":"get_tender_tenders__tender_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"tender_id","in":"path","required":true,"schema":{"type":"integer","title":"Tender Id"}}],"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"}}}}}}},"/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":"string"},{"type":"null"}],"title":"Source"}},{"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":"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":"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":"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":"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"}}}}}}},"/profiles":{"post":{"tags":["profiles"],"summary":"Create Profile","operationId":"create_profile_profiles_post","security":[{"APIKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["profiles"],"summary":"List Profiles","operationId":"list_profiles_profiles_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"include_inactive","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Inactive"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProfileOut"},"title":"Response List Profiles Profiles Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/{profile_id}":{"get":{"tags":["profiles"],"summary":"Get Profile","operationId":"get_profile_profiles__profile_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"integer","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["profiles"],"summary":"Update Profile","operationId":"update_profile_profiles__profile_id__put","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"integer","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["profiles"],"summary":"Delete Profile","operationId":"delete_profile_profiles__profile_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"integer","title":"Profile Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profiles/{profile_id}/set-active":{"post":{"tags":["profiles"],"summary":"Set Profile Active","description":"Pause (active=false) or resume (active=true) a profile without deleting it.","operationId":"set_profile_active_profiles__profile_id__set_active_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"integer","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_ActiveUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/keys/me":{"get":{"tags":["keys"],"summary":"Get My Key","description":"Return metadata for the authenticated key (tier, quota, features).","operationId":"get_my_key_keys_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeOut"}}}}},"security":[{"APIKeyHeader":[]}]}},"/me":{"get":{"tags":["keys"],"summary":"Get Me","description":"Return the authenticated key's tier, quota and features.","operationId":"get_me_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeOut"}}}}},"security":[{"APIKeyHeader":[]}]}},"/billing/start":{"post":{"tags":["billing"],"summary":"Start Checkout","description":"Open a Stripe Checkout session. Key is created + emailed only after payment confirmation.","operationId":"start_checkout_billing_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout","description":"Create a Stripe Checkout Session for a tier upgrade.","operationId":"create_checkout_billing_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]}]}},"/billing/portal":{"post":{"tags":["billing"],"summary":"Customer Portal","description":"Return a Stripe Customer Portal URL for subscription management.","operationId":"customer_portal_billing_portal_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"return_url","in":"query","required":false,"schema":{"type":"string","default":"https://tenderapi.fr/dashboard","title":"Return Url"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/login":{"post":{"tags":["auth"],"summary":"Login","operationId":"login_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/session":{"get":{"tags":["auth"],"summary":"Session Info","operationId":"session_info_auth_session_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","operationId":"logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"tags":["health"],"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"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"}},"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).\nFalse for standalone awards — negotiated/direct procedures with no\npublished prior contract notice. This is normal in public procurement,\nnot 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"},"CheckoutOut":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"},"session_id":{"type":"string","title":"Session Id"}},"type":"object","required":["checkout_url","session_id"],"title":"CheckoutOut"},"CheckoutRequest":{"properties":{"tier":{"type":"string","title":"Tier"},"success_url":{"type":"string","title":"Success Url","default":"https://tenderapi.fr/dashboard?upgraded=1"},"cancel_url":{"type":"string","title":"Cancel Url","default":"https://tenderapi.fr/pricing"}},"type":"object","required":["tier"],"title":"CheckoutRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LoginIn":{"properties":{"api_key":{"type":"string","title":"Api Key"}},"type":"object","required":["api_key"],"title":"LoginIn"},"MeOut":{"properties":{"id":{"type":"integer","title":"Id"},"key_prefix":{"type":"string","title":"Key Prefix"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"tier":{"type":"string","title":"Tier"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"requests_today":{"type":"integer","title":"Requests Today"},"requests_month":{"type":"integer","title":"Requests Month"},"quota_day_limit":{"type":"integer","title":"Quota Day Limit"},"quota_minute_limit":{"type":"integer","title":"Quota Minute Limit"},"quota_remaining_today":{"type":"integer","title":"Quota Remaining Today"},"max_page_size":{"type":"integer","title":"Max Page Size"},"max_profiles":{"type":"integer","title":"Max Profiles"},"features":{"items":{"type":"string"},"type":"array","title":"Features"}},"type":"object","required":["id","key_prefix","name","email","tier","created_at","last_used_at","requests_today","requests_month","quota_day_limit","quota_minute_limit","quota_remaining_today","max_page_size","max_profiles","features"],"title":"MeOut","description":"Authenticated key metadata enriched with quota + features for dashboards/integrators.\n\nMirrors the contractual limits documented in CGV art.2 — clients can read this\nto verify what their subscription actually grants (grandfather-friendly: a\ncustomer on a legacy tier sees their legacy limits here, not the v2 ones)."},"PortalOut":{"properties":{"portal_url":{"type":"string","title":"Portal Url"}},"type":"object","required":["portal_url"],"title":"PortalOut"},"ProfileCreate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"siret":{"anyOf":[{"type":"string","maxLength":14},{"type":"null"}],"title":"Siret"},"keywords":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Keywords"},"cpv_codes":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Cpv Codes"},"regions":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Regions"},"departments":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Departments"},"budget_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Min"},"budget_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Max"},"channel":{"type":"string","title":"Channel","default":"webhook"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"email_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email To"},"match_cpv_family":{"type":"boolean","title":"Match Cpv Family","default":false},"match_descripteur":{"type":"boolean","title":"Match Descripteur","default":false},"descripteur_keywords":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Descripteur Keywords"},"active":{"type":"boolean","title":"Active","default":true}},"additionalProperties":false,"type":"object","title":"ProfileCreate"},"ProfileOut":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"siret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Siret"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"cpv_codes":{"items":{"type":"string"},"type":"array","title":"Cpv Codes"},"regions":{"items":{"type":"string"},"type":"array","title":"Regions"},"departments":{"items":{"type":"string"},"type":"array","title":"Departments"},"budget_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Min"},"budget_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Max"},"channel":{"type":"string","title":"Channel","default":"webhook"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"email_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email To"},"active":{"type":"boolean","title":"Active"},"match_cpv_family":{"type":"boolean","title":"Match Cpv Family"},"match_descripteur":{"type":"boolean","title":"Match Descripteur","default":false},"descripteur_keywords":{"items":{"type":"string"},"type":"array","title":"Descripteur Keywords","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","siret","keywords","cpv_codes","regions","departments","budget_min","budget_max","webhook_url","active","match_cpv_family","created_at"],"title":"ProfileOut"},"StartRequest":{"properties":{"email":{"type":"string","title":"Email"},"tier":{"type":"string","title":"Tier"}},"type":"object","required":["email","tier"],"title":"StartRequest"},"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"},"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"},"WinnerIntelOut":{"properties":{"total":{"type":"integer","title":"Total"},"results":{"items":{"$ref":"#/components/schemas/WinnerStat"},"type":"array","title":"Results"}},"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"}},"type":"object","required":["winner_name","winner_siret","contract_count","total_amount","avg_amount"],"title":"WinnerStat"},"_ActiveUpdate":{"properties":{"active":{"type":"boolean","title":"Active"}},"type":"object","required":["active"],"title":"_ActiveUpdate"}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"tags":[{"name":"tenders","description":"Search tender notices — **available on all tiers** (free, starter, pro)."},{"name":"awards","description":"Search award outcomes — **requires starter tier or above**."},{"name":"profiles","description":"Webhook matching profiles — **requires starter tier or above**."},{"name":"keys","description":"API key management — **available on all tiers**."},{"name":"billing","description":"Subscription and billing — **available on all tiers**."},{"name":"me","description":"Current key info — **available on all tiers**."},{"name":"health","description":"Service health check."}]}