{"examples":["SELECT source, count(*) FROM tenders GROUP BY source","SELECT strftime('%Y', current_published_at, 'unixepoch') AS year, count(*) AS tenders FROM tenders WHERE current_published_at IS NOT NULL GROUP BY year ORDER BY year","SELECT t.id, t.current_title AS title, v.publication_id, v.published_at FROM tenders t JOIN tender_versions v ON v.tender_id = t.id AND v.seq = t.current_seq WHERE t.id = 93601"],"notes":["Read-only: only a single SELECT is accepted.","Queryable surface is a positive allow-list: only the tables and views listed above are readable. Account, webhook and operator tables (users, api_tokens, sessions, webhook_endpoints, job_queue, …) and the raw-fetch registry (fetches, which holds server filesystem paths) are not queryable.","Time columns are Unix epoch seconds, NOT ISO — the REST API returns ISO, so the two disagree. Put the FORMAT FIRST: strftime('%Y', published_at, 'unixepoch'). The reversed order, strftime(col,'unixepoch'), returns NULL for every row without erroring. Every timestamp column carries this note (currency_rates.rate_date is the one exception and says so). WHERE published_at LIKE '2012%' silently matches nothing.","The canonical v_* layer covers the full imported history (1993 onward), not just recent years. A v_* query that returns nothing for a year the coverage grid shows as held is a finding worth reporting, not an artefact of an unfinished backfill.","The v_* views are NOT FILTERABLE: turso applies a WHERE or a JOIN predicate only after building the whole view, so even `WHERE id = ?` scans the corpus (issue 239). A SELECT that filters or joins a view — directly, through a derived table, or through a CTE that reads one — is refused as 400 up front, naming the base-table join to use instead. Unfiltered, unjoined reads (`… FROM v_tenders LIMIT 5`, `SELECT source, COUNT(*) FROM v_tenders GROUP BY source`) are accepted. v_fetches is small and exempt.","Turso SQL dialect gaps: no WITH RECURSIVE; window functions are partial (row_number and aggregate OVER work; rank/lead/lag and custom frames do not).","Results are capped at 10000 rows / 10MB; a capped response carries \"truncated\": true.","Limits: 2 concurrent queries and 300 queries per hour per token; each query may run 10s (a query past the cap — including a slow aggregate — is 408)."],"tables":[{"columns":[{"name":"notice_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"section_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"withheld_field","notnull":false,"pk":false,"type":"TEXT"},{"name":"reason_code","notnull":false,"pk":false,"type":"TEXT"},{"name":"reason_text","notnull":false,"pk":false,"type":"TEXT"},{"name":"publish_after","notnull":false,"pk":false,"type":"TEXT"}],"name":"notice_withheld_fields","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"notice_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"result_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"decision","note":"eForms winner-selection-status code, e.g. 'selec-w' (a winner was selected), 'clos-nw' (closed, no award).","notnull":false,"pk":false,"type":"TEXT"},{"name":"reason","notnull":false,"pk":false,"type":"TEXT"},{"name":"awarded_cents","notnull":false,"pk":false,"type":"TEXT"},{"name":"awarded_currency","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_utc","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_offset","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_has_time","notnull":false,"pk":false,"type":"TEXT"},{"name":"winner_organization_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"winner_name","notnull":false,"pk":false,"type":"TEXT"},{"name":"buyer_organization_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"buyer_name","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_awards","note":"Current award decisions with their winner and a representative buyer — keeps v_lot_results' one-row-per-winner grain (does not multiply by buyer count). NOT FILTERABLE (issue 239); join `lot_results` to `tender_version_lot_results` and `tender_version_result_winners` on `(tender_id, seq = tenders.current_seq)`, and `tender_version_parties` (role LIKE '%uyer%') for the buyer.","type":"view"},{"columns":[{"name":"id","notnull":false,"pk":false,"type":"TEXT"},{"name":"source","notnull":false,"pk":false,"type":"TEXT"},{"name":"kind","notnull":false,"pk":false,"type":"TEXT"},{"name":"period","notnull":false,"pk":false,"type":"TEXT"},{"name":"url","notnull":false,"pk":false,"type":"TEXT"},{"name":"sha256","notnull":false,"pk":false,"type":"TEXT"},{"name":"bytes","notnull":false,"pk":false,"type":"TEXT"},{"name":"fetched_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_fetches","note":"Path-free fetch provenance: which source package/period a notice came from. Small (one row per fetched package), so a filtered read is fine — the one v_* view exempt from the issue-239 refusal.","type":"view"},{"columns":[{"name":"id","notnull":false,"pk":false,"type":"TEXT"},{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"notice_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"result_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"decision","note":"eForms winner-selection-status code, e.g. 'selec-w' (a winner was selected), 'clos-nw' (closed, no award).","notnull":false,"pk":false,"type":"TEXT"},{"name":"reason","notnull":false,"pk":false,"type":"TEXT"},{"name":"awarded_cents","notnull":false,"pk":false,"type":"TEXT"},{"name":"awarded_currency","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_utc","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_offset","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_has_time","notnull":false,"pk":false,"type":"TEXT"},{"name":"winner_organization_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"winner_name","notnull":false,"pk":false,"type":"TEXT"},{"name":"winner_provisional","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_lot_results","note":"Current award decisions: one row per (result, winning organization); winner_* is NULL for an unresolved or withheld award. NOT FILTERABLE, like every `v_*` view — a WHERE is applied after the view is built, so a filtered query reads the whole corpus (issue 239); join `lot_results` to `tender_version_result_winners` instead.","type":"view"},{"columns":[{"name":"id","notnull":false,"pk":false,"type":"TEXT"},{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"kind","notnull":false,"pk":false,"type":"TEXT"},{"name":"seq","notnull":false,"pk":false,"type":"TEXT"},{"name":"title","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_lots","note":"Current Lots — subdivisions of a Tender. NOT FILTERABLE, same as v_tenders (measured: `WHERE tender_id = ?` exceeds the time limit); join `lots` to `tender_version_lots` instead.","type":"view"},{"columns":[{"name":"id","notnull":false,"pk":false,"type":"TEXT"},{"name":"name","notnull":false,"pk":false,"type":"TEXT"},{"name":"country","notnull":false,"pk":false,"type":"TEXT"},{"name":"identifier_kind","notnull":false,"pk":false,"type":"TEXT"},{"name":"identifier","notnull":false,"pk":false,"type":"TEXT"},{"name":"provisional","note":"1 = no official identifier. Identity is then NAME-scoped: mentions carrying the same normalised name and country resolve to one provisional row, so such a row can hold many mentions (issues 234, 351). It is not a promise of one mention, and a later identifier can still canonicalise or split it (issue 370).","notnull":false,"pk":false,"type":"TEXT"},{"name":"mentions","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_organizations","note":"Canonical Organizations (buyers, bidders, winners) with a mention count. NOT FILTERABLE, like every `v_*` view — a WHERE is applied after the view is built, so a filtered query reads the whole corpus (issue 239); join `organizations` (and `organization_mentions` for the count) instead.","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"field","notnull":false,"pk":false,"type":"TEXT"},{"name":"cents","notnull":false,"pk":false,"type":"TEXT"},{"name":"currency","notnull":false,"pk":false,"type":"TEXT"},{"name":"tax_basis","notnull":false,"pk":false,"type":"TEXT"},{"name":"eur_cents","note":"Derived EUR at the version's publication date (ADR-0014), beside the published cents+currency — never replacing them. NULL = no official rate resolves (pre-1999 until the ECU series lands, unknown codes) or the row predates the backfill refold.","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tender_amounts","note":"Money amounts of each current Tender (field, cents, currency, tax_basis, eur_cents). tax_basis is 'incl', 'excl' or NULL when the source did not say — and NULL is most of the corpus, so a total over mixed rows is not comparable (issue 251). eur_cents is the derived EUR at publication date (ADR-0014), NULL where no official rate resolves or the row predates the backfill refold. NOT FILTERABLE (issue 239); join `tenders` to `tender_version_amounts` on `(tender_id, seq = current_seq)`.","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"buyer_organization_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"buyer_name","notnull":false,"pk":false,"type":"TEXT"},{"name":"buyer_country","notnull":false,"pk":false,"type":"TEXT"},{"name":"buyer_provisional","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tender_buyers","note":"Buyers of each current Tender (one row per buyer party). NOT FILTERABLE (issue 239); join `tenders` to `tender_version_parties` on `(tender_id, seq = current_seq)` with `role LIKE '%uyer%'`, then `organizations`.","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"field","notnull":false,"pk":false,"type":"TEXT"},{"name":"scheme","notnull":false,"pk":false,"type":"TEXT"},{"name":"code","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tender_classifications","note":"CPV and NUTS codes of each current Tender (see scheme). NOT FILTERABLE (issue 239); join `tenders` to `tender_version_classifications` on `(tender_id, seq = current_seq)`.","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"seq","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tender_current","note":"The (tender_id, seq) current-version pointer — not cheap to JOIN either, turso rebuilds it whole per outer row. NOT FILTERABLE (issue 239); read `tenders.current_seq` directly: `JOIN tender_versions v ON v.tender_id = t.id AND v.seq = t.current_seq`, and the same `(tender_id, seq = current_seq)` pair for any version satellite.","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"lot_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"field","notnull":false,"pk":false,"type":"TEXT"},{"name":"utc_seconds","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"TEXT"},{"name":"offset_minutes","notnull":false,"pk":false,"type":"TEXT"},{"name":"has_time","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tender_dates","note":"Dates of each current Tender (utc_seconds epoch + offset_minutes). NOT FILTERABLE (issue 239); join `tenders` to `tender_version_dates` on `(tender_id, seq = current_seq)`.","type":"view"},{"columns":[{"name":"tender_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"seq","notnull":false,"pk":false,"type":"TEXT"},{"name":"notice_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"notice_subtype","note":"eForms notice subtype id, e.g. '16' (contract notice), '29' (contract award).","notnull":false,"pk":false,"type":"TEXT"},{"name":"original_lang","note":"The causing notice's ORIGINAL language (ISO 639-2/T, e.g. 'DEU'), as the era published it — TED LG_ORIG, eForms BT-702, text-era OL. NULL where the notice did not say. The ?lang= fallback's third leg (ADR-0013 D3). The eForms era is served in this language: TED's per-language renderings are machine translations outside the bulk feed and are not ingested, so ?lang= picks only among languages the publisher wrote (issue 341).","notnull":false,"pk":false,"type":"TEXT"},{"name":"published_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"TEXT"},{"name":"source","notnull":false,"pk":false,"type":"TEXT"},{"name":"publication_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"profile","notnull":false,"pk":false,"type":"TEXT"},{"name":"parse_state","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tender_notices","note":"The notices that caused each Tender version — the ADR-0001 chain, across all versions. NOT FILTERABLE (issue 239); join `tender_versions` to `notices` on `caused_by_notice_id`.","type":"view"},{"columns":[{"name":"id","notnull":false,"pk":false,"type":"TEXT"},{"name":"source","notnull":false,"pk":false,"type":"TEXT"},{"name":"procedure_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"kind","notnull":false,"pk":false,"type":"TEXT"},{"name":"seq","notnull":false,"pk":false,"type":"TEXT"},{"name":"published_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"TEXT"},{"name":"caused_by_notice_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"notice_subtype","note":"eForms notice subtype id, e.g. '16' (contract notice), '29' (contract award).","notnull":false,"pk":false,"type":"TEXT"},{"name":"original_lang","note":"The causing notice's ORIGINAL language (ISO 639-2/T, e.g. 'DEU'), as the era published it — TED LG_ORIG, eForms BT-702, text-era OL. NULL where the notice did not say. The ?lang= fallback's third leg (ADR-0013 D3). The eForms era is served in this language: TED's per-language renderings are machine translations outside the bulk feed and are not ingested, so ?lang= picks only among languages the publisher wrote (issue 341).","notnull":false,"pk":false,"type":"TEXT"},{"name":"publication_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"title","notnull":false,"pk":false,"type":"TEXT"}],"name":"v_tenders","note":"Current version of each Tender (one row per Tender). NOT FILTERABLE: a WHERE on a view is applied AFTER the whole view is built, so even `WHERE id = ?` scans the corpus and exceeds the time limit (issue 239, measured). Use it for small unfiltered peeks; for anything filtered, join `tenders` to `tender_versions` on `(tender_id, seq = current_seq)` — 17ms for the same point read.","type":"view"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"notice_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"bid_key","notnull":true,"pk":false,"type":"TEXT"}],"name":"bids","type":"table"},{"columns":[{"name":"cursor","notnull":false,"pk":true,"type":"INTEGER"},{"name":"entity_kind","notnull":true,"pk":false,"type":"TEXT"},{"name":"entity_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"version_seq","notnull":false,"pk":false,"type":"INTEGER"},{"name":"op","notnull":true,"pk":false,"type":"TEXT"},{"name":"changed_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"}],"name":"changes","note":"The change-cursor log behind /v1/changes: ingestion order, never renumbered.","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"notice_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"contract_key","notnull":true,"pk":false,"type":"TEXT"}],"name":"contracts","type":"table"},{"columns":[{"name":"currency","notnull":true,"pk":true,"type":"TEXT"},{"name":"rate_date","note":"An ISO date STRING (`1993-01-04`), not epoch seconds — the one time column in this schema that is text. `LIKE '2012%'` works here and nowhere else; do NOT wrap it in strftime(…, 'unixepoch').","notnull":true,"pk":true,"type":"TEXT"},{"name":"rate_to_eur","notnull":true,"pk":false,"type":"REAL"},{"name":"source","notnull":true,"pk":false,"type":"TEXT"}],"name":"currency_rates","note":"The EUR-pivot rate series behind eur_cents (ADR-0014/0015): rate_to_eur = units of `currency` per 1 EUR on `rate_date`. source = 'ecb' (daily reference rates, 1999→), 'eurostat-ecu' (the Commission's daily ECU series 1993-1998, 1:1 EUR by law; data CC BY 4.0 — Source: Eurostat), or 'irrevocable' (the fixed euro conversion rates, valid from each adoption date forever). The derivation resolves the nearest row at-or-before a date — within 7 days for daily sources, unbounded for irrevocable — and pre-1997 TED legacy codes (UKL, LIT, DKR, …) alias to their ISO series.","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"notice_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"result_key","notnull":true,"pk":false,"type":"TEXT"}],"name":"lot_results","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_key","notnull":true,"pk":false,"type":"TEXT"}],"name":"lots","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"cents","notnull":true,"pk":false,"type":"INTEGER"},{"name":"currency","notnull":true,"pk":false,"type":"TEXT"}],"name":"notice_amounts","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"scheme","notnull":true,"pk":false,"type":"TEXT"},{"name":"code","notnull":true,"pk":false,"type":"TEXT"}],"name":"notice_classifications","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"list_name","notnull":false,"pk":false,"type":"TEXT"},{"name":"code","notnull":true,"pk":false,"type":"TEXT"}],"name":"notice_codes","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"utc_seconds","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"offset_minutes","notnull":true,"pk":false,"type":"INTEGER"},{"name":"has_time","notnull":true,"pk":false,"type":"INTEGER"}],"name":"notice_dates","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"scheme","notnull":false,"pk":false,"type":"TEXT"},{"name":"value","notnull":true,"pk":false,"type":"TEXT"},{"name":"is_ref","notnull":true,"pk":false,"type":"INTEGER"}],"name":"notice_ids","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"value","notnull":true,"pk":false,"type":"INTEGER"}],"name":"notice_integers","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"value","notnull":true,"pk":false,"type":"REAL"},{"name":"unit","notnull":false,"pk":false,"type":"TEXT"}],"name":"notice_numbers","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"kind","notnull":true,"pk":false,"type":"TEXT"},{"name":"parent_section_id","notnull":false,"pk":false,"type":"TEXT"}],"name":"notice_sections","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"field_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"ordinal","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lang","notnull":false,"pk":false,"type":"TEXT"},{"name":"value","notnull":true,"pk":false,"type":"TEXT"}],"name":"notice_texts","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"source","notnull":true,"pk":false,"type":"TEXT"},{"name":"publication_id","notnull":true,"pk":false,"type":"TEXT"},{"name":"content_hash","notnull":true,"pk":false,"type":"TEXT"},{"name":"profile","notnull":true,"pk":false,"type":"TEXT"},{"name":"declared_version","notnull":false,"pk":false,"type":"TEXT"},{"name":"fetch_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"member_path","notnull":true,"pk":false,"type":"TEXT"},{"name":"ingested_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"parse_state","note":"One of: pending, parsed, quarantined (ADR-0004).","notnull":true,"pk":false,"type":"TEXT"},{"name":"published_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"dispatched_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"projected","notnull":true,"pk":false,"type":"INTEGER"}],"name":"notices","note":"One row per raw publication event. The parsed payload is in the notice_* tables; the canonical layer is projected from it (ADR-0001).","type":"table"},{"columns":[{"name":"notice_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"section_id","notnull":true,"pk":true,"type":"TEXT"},{"name":"organization_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"name","notnull":false,"pk":false,"type":"TEXT"},{"name":"country","notnull":false,"pk":false,"type":"TEXT"},{"name":"raw_identifier","notnull":false,"pk":false,"type":"TEXT"},{"name":"scheme","notnull":false,"pk":false,"type":"TEXT"}],"name":"organization_mentions","type":"table"},{"columns":[{"name":"org_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lang","notnull":true,"pk":true,"type":"TEXT"},{"name":"name","notnull":true,"pk":false,"type":"TEXT"},{"name":"name_norm","notnull":true,"pk":false,"type":"TEXT"}],"name":"organization_names","note":"Language variants of an Organization's name (ADR-0013 D4): one row per (org_id, lang), lang in ISO 639-2/T uppercase, name_norm Unicode-lowercased. `organizations.name` stays the designated single head; this satellite carries the labelled variants multilingual notices publish (populated for newly ingested notices from 2026-08-28; the standing corpus backfills later). Join organizations on org_id.","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"country","notnull":false,"pk":false,"type":"TEXT"},{"name":"identifier_kind","notnull":false,"pk":false,"type":"TEXT"},{"name":"identifier","notnull":false,"pk":false,"type":"TEXT"},{"name":"name","notnull":true,"pk":false,"type":"TEXT"},{"name":"provisional","note":"1 = no official identifier. Identity is then NAME-scoped: mentions carrying the same normalised name and country resolve to one provisional row, so such a row can hold many mentions (issues 234, 351). It is not a promise of one mention, and a later identifier can still canonicalise or split it (issue 370).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"created_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"name_norm","notnull":false,"pk":false,"type":"TEXT"}],"name":"organizations","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"notice_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"fetch_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"member_path","notnull":true,"pk":false,"type":"TEXT"},{"name":"content_hash","notnull":true,"pk":false,"type":"TEXT"},{"name":"profile","notnull":false,"pk":false,"type":"TEXT"},{"name":"reason","notnull":true,"pk":false,"type":"TEXT"},{"name":"detail","notnull":false,"pk":false,"type":"TEXT"},{"name":"first_seen","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"reprocessed_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"skipped_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"skipped_reason","notnull":false,"pk":false,"type":"TEXT"},{"name":"last_attempt_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"attempts","notnull":false,"pk":false,"type":"INTEGER"},{"name":"first_reason","notnull":false,"pk":false,"type":"TEXT"},{"name":"first_detail","notnull":false,"pk":false,"type":"TEXT"}],"name":"quarantine","note":"Whole notices whose content could not be mapped — public raw payloads kept for reprocessing.","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"field","notnull":true,"pk":false,"type":"TEXT"},{"name":"cents","notnull":true,"pk":false,"type":"INTEGER"},{"name":"currency","notnull":true,"pk":false,"type":"TEXT"},{"name":"tax_basis","notnull":false,"pk":false,"type":"TEXT"},{"name":"eur_cents","note":"Derived EUR at the version's publication date (ADR-0014), beside the published cents+currency — never replacing them. NULL = no official rate resolves (pre-1999 until the ECU series lands, unknown codes) or the row predates the backfill refold.","notnull":false,"pk":false,"type":"INTEGER"},{"name":"quality","notnull":false,"pk":false,"type":"TEXT"}],"name":"tender_version_amounts","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"bid_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"role","notnull":true,"pk":false,"type":"TEXT"},{"name":"organization_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"mention_notice_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"mention_section_id","notnull":true,"pk":false,"type":"TEXT"}],"name":"tender_version_bid_parties","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"bid_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"cents","notnull":false,"pk":false,"type":"INTEGER"},{"name":"currency","notnull":false,"pk":false,"type":"TEXT"},{"name":"eur_cents","note":"Derived EUR at the version's publication date (ADR-0014), beside the published cents+currency — never replacing them. NULL = no official rate resolves (pre-1999 until the ECU series lands, unknown codes) or the row predates the backfill refold.","notnull":false,"pk":false,"type":"INTEGER"},{"name":"quality","notnull":false,"pk":false,"type":"TEXT"}],"name":"tender_version_bids","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"field","notnull":true,"pk":false,"type":"TEXT"},{"name":"scheme","note":"One of: cpv, nuts.","notnull":true,"pk":false,"type":"TEXT"},{"name":"code","notnull":true,"pk":false,"type":"TEXT"}],"name":"tender_version_classifications","note":"CPV and NUTS codes of a Tender version (see scheme).","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"contract_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"buyer_contract_id","notnull":false,"pk":false,"type":"TEXT"},{"name":"concluded_utc","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"concluded_offset","notnull":false,"pk":false,"type":"INTEGER"},{"name":"concluded_has_time","notnull":false,"pk":false,"type":"INTEGER"},{"name":"cents","notnull":false,"pk":false,"type":"INTEGER"},{"name":"currency","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_utc","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"decided_offset","notnull":false,"pk":false,"type":"INTEGER"},{"name":"decided_has_time","notnull":false,"pk":false,"type":"INTEGER"},{"name":"eur_cents","note":"Derived EUR at the version's publication date (ADR-0014), beside the published cents+currency — never replacing them. NULL = no official rate resolves (pre-1999 until the ECU series lands, unknown codes) or the row predates the backfill refold.","notnull":false,"pk":false,"type":"INTEGER"}],"name":"tender_version_contracts","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"field","notnull":true,"pk":false,"type":"TEXT"},{"name":"utc_seconds","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"offset_minutes","notnull":true,"pk":false,"type":"INTEGER"},{"name":"has_time","notnull":true,"pk":false,"type":"INTEGER"}],"name":"tender_version_dates","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"group_lot_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"member_lot_id","notnull":true,"pk":true,"type":"INTEGER"}],"name":"tender_version_lot_group_members","note":"Which lots each LotsGroup contains, per version (issue 237). eForms gives a Bid ONE lot reference, to a Lot or to a LotsGroup, so a bid covering several lots names the GROUP — join through here to attribute it to member lots. Both columns are `lots.id`; the group end is the lot whose `tender_version_lots.kind` is 'LotsGroup'.","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lot_result_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"decision","note":"eForms winner-selection-status code, e.g. 'selec-w' (a winner was selected), 'clos-nw' (closed, no award).","notnull":false,"pk":false,"type":"TEXT"},{"name":"reason","notnull":false,"pk":false,"type":"TEXT"},{"name":"awarded_cents","notnull":false,"pk":false,"type":"INTEGER"},{"name":"awarded_currency","notnull":false,"pk":false,"type":"TEXT"},{"name":"decided_utc","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"decided_offset","notnull":false,"pk":false,"type":"INTEGER"},{"name":"decided_has_time","notnull":false,"pk":false,"type":"INTEGER"},{"name":"awarded_eur_cents","note":"Derived EUR at the version's publication date (ADR-0014) for awarded_cents — same contract as eur_cents: beside the published value, NULL where no rate resolves.","notnull":false,"pk":false,"type":"INTEGER"}],"name":"tender_version_lot_results","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lot_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"kind","notnull":true,"pk":false,"type":"TEXT"}],"name":"tender_version_lots","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"role","note":"TWO vocabularies, deliberately (issue 393). The LEGACY eras fold onto canonical roles: 'buyer', 'purchasing-body', 'winner', 'review-body', 'mediation-body', 'tender-receipt', 'further-information', 'specifications-provider', 'appeal-information' and the three '*-legislation-information' bodies. eForms is served AS PUBLISHED ('Procedure-Buyer', 'Tenderer', 'Lot-ReviewOrg'), because the suffix carries lot/procedure SCOPE the canonical name would lose. So buyers are 'buyer' OR 'Procedure-Buyer' — match with role LIKE '%uyer%' — and winners are 'winner' OR 'Tenderer'. Rows written before the issue-393 re-projection may still carry the raw legacy element name, e.g. 'ECONOMIC_OPERATOR_NAME_ADDRESS' for a winner.","notnull":true,"pk":false,"type":"TEXT"},{"name":"organization_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"mention_notice_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"mention_section_id","notnull":true,"pk":false,"type":"TEXT"}],"name":"tender_version_parties","note":"Organizations linked to a Tender version by role (see role).","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_result_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"kind","notnull":true,"pk":false,"type":"TEXT"},{"name":"count","notnull":true,"pk":false,"type":"INTEGER"},{"name":"quality","notnull":false,"pk":false,"type":"TEXT"}],"name":"tender_version_result_stats","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"lot_result_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"organization_id","notnull":true,"pk":true,"type":"INTEGER"}],"name":"tender_version_result_winners","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":false,"type":"INTEGER"},{"name":"lot_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"field","notnull":true,"pk":false,"type":"TEXT"},{"name":"lang","notnull":false,"pk":false,"type":"TEXT"},{"name":"value","notnull":true,"pk":false,"type":"TEXT"}],"name":"tender_version_texts","type":"table"},{"columns":[{"name":"tender_id","notnull":true,"pk":true,"type":"INTEGER"},{"name":"seq","notnull":true,"pk":true,"type":"INTEGER"},{"name":"caused_by_notice_id","notnull":true,"pk":false,"type":"INTEGER"},{"name":"published_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"notice_subtype","note":"eForms notice subtype id, e.g. '16' (contract notice), '29' (contract award).","notnull":false,"pk":false,"type":"TEXT"},{"name":"publication_id","notnull":true,"pk":false,"type":"TEXT"},{"name":"dispatched_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"original_lang","note":"The causing notice's ORIGINAL language (ISO 639-2/T, e.g. 'DEU'), as the era published it — TED LG_ORIG, eForms BT-702, text-era OL. NULL where the notice did not say. The ?lang= fallback's third leg (ADR-0013 D3). The eForms era is served in this language: TED's per-language renderings are machine translations outside the bulk feed and are not ingested, so ?lang= picks only among languages the publisher wrote (issue 341).","notnull":false,"pk":false,"type":"TEXT"}],"name":"tender_versions","type":"table"},{"columns":[{"name":"id","notnull":false,"pk":true,"type":"INTEGER"},{"name":"source","notnull":true,"pk":false,"type":"TEXT"},{"name":"procedure_key","notnull":false,"pk":false,"type":"TEXT"},{"name":"island_notice_id","notnull":false,"pk":false,"type":"INTEGER"},{"name":"kind","notnull":true,"pk":false,"type":"TEXT"},{"name":"created_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":true,"pk":false,"type":"INTEGER"},{"name":"current_seq","notnull":false,"pk":false,"type":"INTEGER"},{"name":"current_published_at","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"projection_epoch","notnull":true,"pk":false,"type":"INTEGER"},{"name":"current_deadline","note":"Unix epoch seconds — NOT ISO (the REST API returns ISO). Format with the FORMAT FIRST and 'unixepoch' after the column: strftime('%Y', published_at, 'unixepoch'). The reversed order returns NULL for every row without erroring — measured on prod, one NULL bucket holding all 7,924,659 Tenders (issue 239).","notnull":false,"pk":false,"type":"INTEGER"},{"name":"current_title","notnull":false,"pk":false,"type":"TEXT"},{"name":"current_value_eur_cents","note":"The head version's highest amount as derived EUR cents (ADR-0014 D5) — what min_value/max_value compare against. NULL = no amount converts (or the row predates the backfill).","notnull":false,"pk":false,"type":"INTEGER"}],"name":"tenders","type":"table"}]}