1.Overview
REST API
Your account's data as JSON, over HTTPS, read-only.
MCP server
The same data for your AI agents (Claude, Cursor, VS Code, Codex…), through the MCP protocol. Read-only tools.
Access
Team plan. Other plans get a 402 plan_required response. The API and the MCP server share the same keys and the same limits.
2.Get started
Create a key
The account owner creates the key in Settings › API and MCP. The full key is shown only once: keep it in a secrets manager. At most 3 active keys per account.
Authenticate every request
Send the key in the
Authorization: Bearer dsk_live_…header. Without a valid key, the API returns 401.Call the API
All endpoints are under
https://api.discer.ca/api/v1. For example, search open tenders that contain “pavage” (paving):
export DISCER_API_KEY="dsk_live_YOUR_KEY"
curl "https://api.discer.ca/api/v1/tenders?q=pavage®ion=5&limit=20" \
-H "Authorization: Bearer $DISCER_API_KEY"import os
import requests
response = requests.get(
"https://api.discer.ca/api/v1/tenders",
params={"q": "pavage", "region": 5, "limit": 20},
headers={"Authorization": f"Bearer {os.environ['DISCER_API_KEY']}"},
timeout=30,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
for tender in body["data"]:
print(tender["id"], tender["closes_at"], tender["title"])const params = new URLSearchParams({ q: "pavage", region: "5", limit: "20" });
const response = await fetch(`https://api.discer.ca/api/v1/tenders?${params}`, {
headers: { Authorization: `Bearer ${process.env.DISCER_API_KEY}` },
});
const body = await response.json();
if (!response.ok) {
throw new Error(`${response.status} ${body.error.code}: ${body.error.message}`);
}
for (const tender of body.data) {
console.log(tender.id, tender.closes_at, tender.title);
}{
"data": [
{
"id": "1234567",
"source": "seao",
"title": "Réfection de pavage, rue des Exemples",
"buyer": "Ville de Exempleville",
"buyer_city": "Exempleville",
"region_code": 5,
"region": "Estrie",
"province": "QC",
"published_at": "2026-10-01T09:00:00-04:00",
"closes_at": "2026-10-22T14:00:00-04:00",
"days_left": 19,
"estimated_value": 850000,
"unspsc": "72141100",
"language": "fr",
"relevance": null
}
],
"pagination": {
"next_cursor": "eyJvIjoyMCwiZiI6ImFiYzEyMyJ9",
"has_more": true,
"total": 37
}
}Key scope: lecture (read). The API and the MCP server are read-only.
3.Conventions
- JSON responses:
{"data": …}; lists addpagination. - Timestamps: ISO 8601 with UTC offset, e.g.
2026-10-22T14:00:00-04:00. - Date filters (
published_after,closing_before…): calendar days in Québec time (America/Toronto);_afteris inclusive,_beforeis exclusive. - Amounts: Canadian dollars, as published. Fields ending in
_2026_dollarsare indexed to 2026 dollars. - Statistics: figures
{value, n, period: {from, to}, source}, wherenis the sample size. Quote them withnand the period. - Explanatory notes (
note,definition), labels and some enumerated values are in French. - No personal contact data is returned: only public bodies and bidding companies, as published on SEAO, are named.
4.Pagination
Paginated lists return pagination.next_cursor, pagination.has_more and pagination.total. Send the cursor back in the cursor parameter, with the same filters: a cursor issued for other filters is refused (422 invalid_cursor).
limit is 1 to 100 (50 by default). A filtered query stops at 1,000 results (422 pagination_limit): narrow the filters to go further. Tender search and renewals require at least one filter.
url = "https://api.discer.ca/api/v1/tenders"
headers = {"Authorization": f"Bearer {os.environ['DISCER_API_KEY']}"}
params = {"q": "pavage", "region": 5, "limit": 100}
tenders = []
while True:
body = requests.get(url, params=params, headers=headers, timeout=30).json()
tenders.extend(body["data"])
if not body["pagination"]["has_more"]:
break
params["cursor"] = body["pagination"]["next_cursor"]5.Endpoints
The 19 operations of version 1.2.0, taken from the API's OpenAPI definition. Every endpoint requires a key; possible statuses are listed under each endpoint.
Account
/meYour account, plan and API key
The account the key belongs to, its plan and the key's scopes. Use it to test a key.
Success: 200 · Possible errors: 401, 402, 403, 422, 429
Tenders
/tendersPaginatedSearch open tenders
Tenders open today. At least one filter is required. _after dates are inclusive and _before dates exclusive. Each returned row counts toward the account's list rows.
Parameters
qstringqueryoptionalWords in the title or buyer name, e.g.
pavage.At most 200 characters
sourcestringqueryoptionalSource of the tender.
Values:
seao,canadabuys,torontoprovincestring[]queryoptionalrepeatableISO province code (QC, ON…), repeatable. Canada-wide tenders are included.
regioninteger[]queryoptionalrepeatableQuébec administrative region code (1-17), repeatable.
unspscstringqueryoptionalUNSPSC code prefix, 2 to 8 digits, e.g.
7214.Pattern:
^\d{2,8}$buyerstringqueryoptionalPart of the buyer name, e.g.
Ville de Lévis.At most 200 characters
published_afterdatequeryoptionalCalendar date YYYY-MM-DD, Québec time (America/Toronto).
published_beforedatequeryoptionalCalendar date YYYY-MM-DD, Québec time (America/Toronto).
closing_afterdatequeryoptionalCalendar date YYYY-MM-DD, Québec time (America/Toronto).
closing_beforedatequeryoptionalCalendar date YYYY-MM-DD, Québec time (America/Toronto).
profilestringqueryoptionalWatch profile id (
principalor an id from /watch-profiles): addsrelevanceand ranks by score;sortis then ignored.At most 40 characters
sortstringqueryoptionalclosing_asc: closing soonest first;published_desc: newest first.Default:
closing_ascValues:closing_asc,published_desclimitintegerqueryoptionalPage size, 1 to 100.
Default:
50From 1 to 100cursorstringqueryoptionalpagination.next_cursorfrom the previous page. Send the same filters with it.At most 200 characters
Success: 200 · Possible errors: 401, 402, 403, 404, 409, 422, 429
/tenders/{tender_id}Tender detail with its intelligence
Tender facts and, for SEAO tenders, its intelligence: key facts, win probability (when calibrated), winning price range (same sub-category when available), expected bidders and their bid probability, competitiveness and price position (open tenders), buyer history for this UNSPSC category, amendments. Counts as one distinct tender record for the account's daily and monthly limits.
Parameters
tender_idstringpathrequiredTender
idfrom /tenders: SEAO number, or CB-…, TOR-… for other sources.At most 40 characters
intelligencebooleanqueryoptionalInclude the intelligence block (SEAO tenders).
Default:
true
Success: 200 · Possible errors: 401, 402, 403, 404, 422, 429
Your data
/bidsPaginatedYour Pipeline (tenders by stage)
Cards of the account's Pipeline, discarded cards excluded: stage, bid price, relevance, followed tenders and their news (addenda, closing changes, published result). Does not count toward list rows.
Parameters
statusstringqueryoptionalPipeline stage.
Values:
to_evaluate,preparing,submitted,won,lostlimitintegerqueryoptionalPage size, 1 to 100.
Default:
50From 1 to 100cursorstringqueryoptionalpagination.next_cursorfrom the previous page. Send the same filters with it.At most 200 characters
Success: 200 · Possible errors: 401, 402, 403, 422, 429
/watch-profilesWatch profiles (use their id in /tenders?profile=)
The account's watch profiles: UNSPSC categories, keywords, regions, value range.
Success: 200 · Possible errors: 401, 402, 403, 422, 429
Market
- GET /renewals
- GET /companies
- GET /companies/{neq}
- GET /buyers
- GET /buyers/{buyer_id}
- GET /market
- GET /market/competitors
- GET /market/portrait
/renewalsPaginatedUpcoming renewals (contracts ending soon, with incumbents)
Contracts from past tenders (not sole-source) whose expected end falls within the horizon, with their incumbents; your company's contracts first (is_you). A new call for tenders is not confirmed. At least one of family, region, buyer_id or for_me is required. Each returned row counts toward the account's list rows.
Parameters
familystringqueryoptionalUNSPSC prefix, 2 or 4 digits, e.g.
7214.Pattern:
^\d{2,4}$regionintegerqueryoptionalQuébec administrative region code (1-17).
From 1 to 17
buyer_idintegerqueryoptionalBuyer id from /buyers.
At least 1
horizon_monthsintegerqueryoptionalContracts whose expected end falls within N months.
Default:
12From 1 to 24for_mebooleanqueryoptionalOnly your niche (watch profile categories, keywords and regions), as on the Renewals page.
Default:
falseall_regionsbooleanqueryoptionalWith
for_meand an all-Québec profile with priority regions: all of Québec instead of the priority regions.Default:
falselimitintegerqueryoptionalPage size, 1 to 100.
Default:
50From 1 to 100cursorstringqueryoptionalpagination.next_cursorfrom the previous page. Send the same filters with it.At most 200 characters
Success: 200 · Possible errors: 401, 402, 403, 409, 422, 429, 503
/companiesFind companies by name or NEQ
Companies that bid on SEAO, matched by name (accents, case and legal suffixes ignored) or NEQ, at most 10. Each match counts toward the account's list rows.
Parameters
qstringqueryrequiredPart of the company name, or the start of its NEQ (3 to 10 digits).
2 to 80 characters
Success: 200 · Possible errors: 401, 402, 403, 422, 429
/companies/{neq}Company profile (SEAO bidding history)
Bids, wins, win rate, top buyers, UNSPSC categories, regions, main opponents with head-to-head, recent bids with prices, strength in its market, amendments of its contracts. Counts as one distinct company profile.
Parameters
neqstringpathrequiredQuébec enterprise number, 10 digits.
Success: 200 · Possible errors: 401, 402, 403, 404, 422, 429
/buyersFind public buyers by name
Public buyers (cities, ministries, school boards…), most active first, at most 10. Each match counts toward the account's list rows.
Parameters
qstringqueryrequiredPart of the buyer name, e.g.
Ville de Québec.2 to 120 characters
Success: 200 · Possible errors: 401, 402, 403, 422, 429
/buyers/{buyer_id}Buyer profile (purchases, winners, prices, sole-source, amendments)
Purchases by UNSPSC category over 5 years, top winners, price ranges, market presence, sole-source contracts and amendments. Counts as one distinct buyer profile.
Parameters
buyer_idintegerpathrequiredBuyer id from /buyers.
Success: 200 · Possible errors: 401, 402, 403, 404, 422, 429
/marketYour market report (your company's SEAO record, competitors, lost tenders)
Market report of the account's company: niche, figures, competitors, lost tenders. report is null when the account has no company NEQ; an unverified NEQ gets the public-level report.
Success: 200 · Possible errors: 401, 402, 403, 422, 429
/market/competitorsCompanies that win the most in your niche
Companies that won the most contracts in your niche over 36 months (your bids, otherwise your watch profile): contracts won, bids, win rate, last bid, and the median win rate of active companies. Works for a company that rarely bids or never did; yours is never listed.
Success: 200 · Possible errors: 401, 402, 403, 422, 429
/market/portraitMarket figures for your niche
For the first 3 UNSPSC categories of your niche (your bids, otherwise your watch profile): tenders published, open tenders, bidders per tender, amounts awarded, main buyers, tenders per month. Your region when the profile has only one, otherwise all of Québec.
Success: 200 · Possible errors: 401, 402, 403, 422, 429
Concluded tenders
/concluded-tendersPaginatedSearch concluded tenders (winners, amounts, bidders)
SEAO tenders concluded since 2015, as on the History page: winner, winning amount, number of bidders, gap between the two lowest submitted prices, your own result. At least one filter is required. _after dates are inclusive and _before dates exclusive (conclusion date, otherwise publication date). Each returned row counts toward the account's list rows.
Parameters
qstringqueryoptionalWords in the title, e.g.
pavage.At most 200 characters
unspscstringqueryoptionalUNSPSC category (4 digits) or segment (2 digits), e.g.
7214.Pattern:
^\d{2}(\d{2})?$buyer_idintegerqueryoptionalBuyer id from /buyers.
At least 1
regionintegerqueryoptionalQuébec administrative region code (1-17).
From 1 to 17
concluded_afterdatequeryoptionalCalendar date YYYY-MM-DD, Québec time (America/Toronto).
concluded_beforedatequeryoptionalCalendar date YYYY-MM-DD, Québec time (America/Toronto).
min_amountnumberqueryoptionalMinimum winning amount. Canadian dollars.
At least 0
max_amountnumberqueryoptionalMaximum winning amount. Canadian dollars.
At least 0
companystringqueryoptionalNEQ of a company that bid (or won, with
role=won).Pattern:
^\d{10}$rolestringqueryoptionalWith
company: tenders it bid on, or won.Default:
bidValues:bid,wonminebooleanqueryoptionalOnly tenders your company bid on (verified NEQ).
Default:
falsemin_biddersintegerqueryoptionalMinimum number of bidders.
From 1 to 500
max_biddersintegerqueryoptionalMaximum number of bidders.
From 1 to 500
pricesstringqueryoptionalwith: all prices published;without: prices not published.Values:
with,withoutsortstringqueryoptionalrecentfirst, highestamountfirst, or largestgapbetween the two lowest submitted prices first.Default:
recentValues:recent,amount,gaplimitintegerqueryoptionalPage size, 1 to 50.
Default:
25From 1 to 50cursorstringqueryoptionalpagination.next_cursorfrom the previous page. Send the same filters with it.At most 200 characters
Success: 200 · Possible errors: 401, 402, 403, 422, 429, 503
/concluded-tenders/{tender_id}A concluded tender: every bid and its price
Every bidder with its price, rank and gap to the winner, second-lowest price, price dispersion, amendments of the contract, similar concluded tenders. Counts as one distinct tender record.
Parameters
tender_idstringpathrequiredSEAO number from /concluded-tenders.
Pattern:
^\d{1,12}$
Success: 200 · Possible errors: 401, 402, 403, 404, 422, 429, 503
Subcontracting
/subcontracting/openPaginatedOpen tenders where one of your trades may be needed
Open tenders where one of the trades of your Subcontracting settings may be needed (RBQ licence in construction, analysis of the documents elsewhere), as on the Subcontracting page. Empty when the account has no trade. Each returned row counts toward the account's list rows.
Parameters
tradestringqueryoptionalOne of your trades (a code from
trade_codes: RBQ sub-category such as4.1, service code orlibre:…).At most 90 characters
regionintegerqueryoptionalQuébec administrative region code (1-17).
From 1 to 17
min_amountnumberqueryoptionalMinimum estimated value. Canadian dollars.
At least 0
max_amountnumberqueryoptionalMaximum estimated value. Canadian dollars.
At least 0
since_daysintegerqueryoptionalPublished within N days.
From 1 to 365
limitintegerqueryoptionalPage size, 1 to 50.
Default:
25From 1 to 50cursorstringqueryoptionalpagination.next_cursorfrom the previous page. Send the same filters with it.At most 200 characters
Success: 200 · Possible errors: 401, 402, 403, 422, 429, 503
/subcontracting/awardedPaginatedAwarded tenders in your trades: winners to contact
Tenders awarded in your trades, region and value range: the winning company to contact for subcontracting (name, NEQ, city), amount, trades. The contact published by SEAO is read in Discer only. Each returned row counts toward the account's list rows.
Parameters
tradestringqueryoptionalOne of your trades (a code from
trade_codes: RBQ sub-category such as4.1, service code orlibre:…).At most 90 characters
regionintegerqueryoptionalQuébec administrative region code (1-17).
From 1 to 17
min_amountnumberqueryoptionalMinimum winning amount. Canadian dollars.
At least 0
max_amountnumberqueryoptionalMaximum winning amount. Canadian dollars.
At least 0
since_daysintegerqueryoptionalConcluded within 30, 90 or 365 days.
Default:
90From 30 to 365winnerstringqueryoptionalOnly the tenders won by this NEQ (all trades).
Pattern:
^\d{10}$buyer_idintegerqueryoptionalOnly this buyer's tenders (all trades).
At least 1
limitintegerqueryoptionalPage size, 1 to 50.
Default:
25From 1 to 50cursorstringqueryoptionalpagination.next_cursorfrom the previous page. Send the same filters with it.At most 200 characters
Success: 200 · Possible errors: 401, 402, 403, 422, 429
Private tenders
/private-tendersPrivate tenders sent to your organization
Private tenders published on Discer by public and private buyers. Read-only: interest, questions and bids are given in Discer. Each returned row counts toward the account's list rows.
Parameters
viewstringqueryoptionalfor_you: the private tenders your organization was invited to or matched;all: every open one.Default:
for_youValues:for_you,all
Success: 200 · Possible errors: 401, 402, 403, 404, 422, 429
/private-tenders/{private_tender_id}A private tender
The private tender as your organization sees it. Reading it here registers no interest and no view (opening it in Discer does). Counts as one distinct tender record.
Parameters
private_tender_idstringpathrequiredidfrom /private-tenders.At most 40 characters
Success: 200 · Possible errors: 401, 402, 403, 404, 422, 429
6.Errors
Every error returns an error object with code, message and, when useful, details. The code is stable; the message, in English, may change.
{
"error": {
"code": "invalid_parameter",
"message": "Invalid parameters.",
"details": {
"errors": [
{
"parameter": "limit",
"message": "Input should be less than or equal to 100"
}
]
}
}
}- 401
missing_api_keyNoAuthorization: Bearerheader. - 401
invalid_api_keyUnknown or malformed key. - 401
revoked_api_keyThe key was revoked in Settings. - 402
plan_requiredThe account is not on the Team plan, or its subscription is inactive. - 402
subscription_pausedThe subscription is paused: access resumes with it. - 402
first_payment_requiredTrial period: the API and MCP server open with the first payment. - 403
api_key_suspendedThe key is suspended pending review after unusual usage. - 403
account_under_reviewAPI, MCP, assistant and exports are paused pending review. - 403
account_disabledThe account is disabled. - 404
not_foundUnknown tender, company, buyer, watch profile or path. - 405
method_not_allowedHTTP method not supported on this path. - 409
profile_inactiveThis watch profile is inactive on the current plan. - 409
profile_incompletefor_meneeds a watch profile with categories or keywords. - 422
invalid_parameterA parameter is missing or invalid (details.errorslists them). - 422
invalid_cursorThe cursor is malformed or was issued for other filters. - 422
filter_required/tendersand/renewalsneed at least one filter. - 422
pagination_limitPaging stops after the result cap of a filtered query: narrow the filters. - 429
rate_limitedToo many requests in the last minute. - 429
quota_exceededDaily or monthly request cap reached. - 429
entity_quota_exceededDaily or monthly cap of distinct records reached. - 429
row_quota_exceededDaily or monthly cap of list rows reached. - 429
temporarily_blockedAccess paused for 24 hours after unusual usage. - 500
internal_errorUnexpected server error: try again; write to thomas@contact.discer.ca if it persists. - 503
not_readyRenewals are being computed: try again later.
429 responses carry the Retry-After header, in seconds.
7.Limits and safeguards
Discer is built for teams that prepare their own bids, not for copying its database. Limits per account, all keys and the MCP server combined; days and months follow Québec time.
| Measure | Per day | Per month |
|---|---|---|
| Requests (API and MCP)and 60 per minute | 2,000 | 30,000 |
| Distinct tender records | 300 | 3,000 |
| Distinct company profiles | 200 | 2,000 |
| Distinct buyer profiles | 100 | 600 |
| List rows returned | 5,000 | 60,000 |
- A record already viewed this month does not count twice.
- At most 3 active keys per account; at most 1,000 results per filtered query.
- Over a limit: 429 with the
Retry-Afterheader. - Systematic use (records requested in sequence, deep paging) slows the account down, then pauses it, then suspends its keys pending review (403
api_key_suspended). - Systematic extraction, resale, rebuilding a database and training models with Discer data are prohibited: see the terms of use. You accept these rules when you create a key.
8.MCP server
The MCP server gives Discer data to an AI agent, with the same key and the same limits as the API.
- URL
https://api.discer.ca/mcp- Header
Authorization: Bearer dsk_live_…- Transport
- Streamable HTTP, stateless, JSON responses. Both
/mcpand/mcp/answer.
Set up your client
One command in the terminal. Add --scope user to have it in all your projects.
claude mcp add --transport http discer https://api.discer.ca/mcp \
--header "Authorization: Bearer dsk_live_YOUR_KEY"In claude_desktop_config.json (Settings › Developer › Edit Config), then restart Claude Desktop. Requires Node.js: mcp-remote relays the remote server. The header goes through an environment variable because Claude Desktop on Windows does not escape spaces in arguments.
{
"mcpServers": {
"discer": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.discer.ca/mcp",
"--header",
"Authorization:${AUTH_HEADER}"
],
"env": {
"AUTH_HEADER": "Bearer dsk_live_YOUR_KEY"
}
}
}
}In ~/.cursor/mcp.json (all your projects) or .cursor/mcp.json (one project). Cursor reads the key from the DISCER_API_KEY environment variable.
{
"mcpServers": {
"discer": {
"url": "https://api.discer.ca/mcp",
"headers": {
"Authorization": "Bearer ${env:DISCER_API_KEY}"
}
}
}
}In .vscode/mcp.json. VS Code asks for the key the first time the server starts and stores it securely.
{
"inputs": [
{
"type": "promptString",
"id": "discer-api-key",
"description": "Discer API key",
"password": true
}
],
"servers": {
"discer": {
"type": "http",
"url": "https://api.discer.ca/mcp",
"headers": {
"Authorization": "Bearer ${input:discer-api-key}"
}
}
}
}In ~/.codex/config.toml. Codex reads the key from the DISCER_API_KEY environment variable.
[mcp_servers.discer]
url = "https://api.discer.ca/mcp"
bearer_token_env_var = "DISCER_API_KEY"With the official mcp SDK for Python, version 2: list the tools, then call one.
# pip install "mcp>=2.2"
import asyncio
import os
import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
async def main() -> None:
headers = {"Authorization": f"Bearer {os.environ['DISCER_API_KEY']}"}
async with httpx2.AsyncClient(headers=headers, timeout=60) as http:
transport = streamable_http_client("https://api.discer.ca/mcp", http_client=http)
async with Client(transport) as client:
tools = await client.list_tools()
print([tool.name for tool in tools.tools])
result = await client.call_tool("search_open_tenders", {"query": "pavage", "limit": 5})
print(result.content[0].text)
asyncio.run(main())Never commit a key: use an environment variable or your client's secret storage. Revoke an exposed key in Settings › API and MCP; it takes effect immediately.
9.MCP tools
14 read-only tools. Each tool returns compact JSON; the API limits apply.
search_open_tendersRead-onlySearch tenders OPEN today (SEAO and other Canadian sources): id, title, buyer, closing date (ISO 8601), days left, estimated value (Canadian dollars), link, and the total number of matches. Never reveals who is preparing a bid on an open tender.
Arguments
querystringoptionalWords in the title or buyer name (French gives more matches), e.g. 'pavage'
unspscstringoptionalUNSPSC code prefix, 2 to 8 digits, e.g. '7214' (heavy construction)
Pattern:
^\d{2,8}$regionstringoptionalQuébec administrative region: code 1-17 or name, e.g. 'Montérégie'
buyerstringoptionalPart of the public buyer name, e.g. 'Ville de Lévis'
sourcestringoptionalseao, canadabuys or toronto
closing_within_daysintegeroptionalOnly tenders closing within N calendar days (Québec time)
From 1 to 365
use_watch_profilebooleanoptionalRank by relevance (score 0-100) to the account's main watch profile
Default:
falselimitintegeroptionalTenders to return, 1 to 25
Default:
10From 1 to 25
get_tender_intelligenceRead-onlyFull intelligence for one tender: key facts (French), Discer's calibrated win probability for your company (only when the segment is calibrated; report it as given), winning price range observed at this buyer and UNSPSC category (2026 dollars, with n and period), expected gap between the two lowest submitted prices, competitiveness and price position (open tenders), expected bidders with their bid probability, buyer history. Information, not a recommendation. Counts as one distinct tender record.
Arguments
tender_idstringrequiredTender id from search_open_tenders (SEAO number, e.g. '20158453')
get_winning_priceRead-onlyObserved winning prices relevant to a tender: P10-P90 of comparable winning bids (same sub-category when available; Canadian dollars indexed to 2026, with n and period), price per 12 months for recurring services, expected gap between the lowest and second-lowest bid, buyer's winning-price-to-estimate ratio, and the price position of past bids (open tenders). Information calculated from past tenders, never a recommendation or a guarantee.
Arguments
tender_idstringrequiredSEAO tender number, e.g. '20158453'
get_likely_biddersRead-onlyCompanies that may bid on a tender: bidders of the most similar concluded tenders (or 36 months of SEAO history at this buyer and in this UNSPSC category and region), with their bid probability when Discer's model computed it, bids and wins with the buyer, and head-to-head record with your company.
Arguments
tender_idstringrequiredSEAO tender number, e.g. '20158453'
get_buyer_profileRead-onlyPublic buyer profile: purchases by UNSPSC category (5 years), top winners, price ranges (Canadian dollars), sole-source contracts and amendments. Give buyer_id, or a name: several matches return candidates with their buyer_id.
Arguments
buyer_idintegeroptionalDiscer buyer id (from a previous result)
namestringoptionalBuyer name to look up, e.g. 'Ville de Québec'
get_company_profileRead-onlyA company's SEAO bidding record: bids, wins, win rate, top buyers, UNSPSC categories, regions, main opponents with head-to-head, recent bids with prices (Canadian dollars). Give a NEQ, or a name: several matches return candidates with their NEQ.
Arguments
neqstringoptionalQuébec enterprise number (10 digits)
Pattern:
^\d{10}$namestringoptionalCompany name to look up
list_my_bidsRead-onlyThe account's Pipeline (tenders by stage, discarded cards excluded): tender, buyer, status, bid price, closing date, notes, relevance, followed tenders and their news (addenda titles, closing date changes, published result and winner, cancellation).
Arguments
statusstringoptionalPipeline stage: to_evaluate, preparing, submitted, won or lost
Values:
to_evaluate,preparing,submitted,won,lostlimitintegeroptionalCards to return, 1 to 100
Default:
50From 1 to 100
list_upcoming_renewalsRead-onlyContracts from past tenders whose expected end falls within the horizon, with the incumbent: possible re-tenders (not confirmed). Buyer, title, expected end (YYYY-MM-DD), amount (Canadian dollars), incumbents; the account's own contracts first (is_you). Without family, region or buyer_id: the account's niche (for_me).
Arguments
familystringoptionalUNSPSC prefix, 2 or 4 digits, e.g. '7214'
Pattern:
^\d{2,4}$regionstringoptionalQuébec region code 1-17 or name, e.g. 'Laurentides'
buyer_idintegeroptionalDiscer buyer id (from get_buyer_profile)
At least 1
horizon_monthsintegeroptionalExpected end within N months
Default:
12From 1 to 24for_mebooleanoptionalOnly the account's niche (watch profile), as on the Renewals page
Default:
falselimitintegeroptionalContracts to return, 1 to 50
Default:
20From 1 to 50
search_concluded_tendersRead-onlySearch SEAO tenders concluded since 2015: winner, winning amount (Canadian dollars), number of bidders, gap between the two lowest submitted prices, the account's own result, and the total number of matches. Give at least one filter.
Arguments
querystringoptionalWords in the title (French gives more matches), e.g. 'pavage'
unspscstringoptionalUNSPSC category (4 digits) or segment (2 digits), e.g. '7214'
Pattern:
^\d{2}(\d{2})?$regionstringoptionalQuébec administrative region: code 1-17 or name, e.g. 'Montérégie'
buyer_idintegeroptionalDiscer buyer id (from get_buyer_profile)
At least 1
company_neqstringoptionalOnly tenders this company bid on
Pattern:
^\d{10}$won_onlybooleanoptionalWith company_neq: only the tenders it won
Default:
falseminebooleanoptionalOnly tenders the account's company bid on
Default:
falseconcluded_within_monthsintegeroptionalConcluded within N months
From 1 to 144
sortstringoptionalrecent, amount (highest first) or gap (largest gap between the two lowest submitted prices first)
Default:
recentValues:recent,amount,gaplimitintegeroptionalTenders to return, 1 to 25
Default:
10From 1 to 25
get_concluded_tenderRead-onlyOne concluded tender: every bidder with its price (Canadian dollars), rank and gap to the winner, second-lowest price, amendments of the contract. Counts as one distinct tender record.
Arguments
tender_idstringrequiredSEAO number of a concluded tender
Pattern:
^\d{1,12}$
list_subcontracting_opportunitiesRead-onlySubcontracting, from the trades of the account's Subcontracting settings: open tenders where a trade may be needed, or awarded tenders with the winning company to contact (name, NEQ, city; its published contact is read in Discer only).
Arguments
kindstringoptionalopen: open tenders where one of the account's trades may be needed; awarded: awarded tenders in its trades, with the winner to contact
Default:
openValues:open,awardedtradestringoptionalOne of the account's trade codes (see trade_codes in a previous result)
regionstringoptionalQuébec region code 1-17 or name
since_daysintegeroptionalopen: published within N days; awarded: 30, 90 or 365 (default 90)
From 1 to 365
limitintegeroptionalTenders to return, 1 to 25
Default:
10From 1 to 25
get_niche_marketRead-onlyThe account's niche (its bids, otherwise its watch profile): companies that win the most there over 36 months (contracts won, bids, win rate) and market figures for its first 3 UNSPSC categories (tenders published, bidders per tender, amounts, main buyers). Useful even for a company that rarely bids or never did.
list_private_tendersRead-onlyPrivate tenders published on Discer by buyers (public or private): title, buyer, city, closing date, status, whether the account's organization was invited and has bid. Read-only.
Arguments
viewstringoptionalfor_you: invited or matched; all: every open private tender
Default:
for_youValues:for_you,all
get_private_tenderRead-onlyOne private tender as the account's organization sees it: scope, constraints, dates, document names, addenda, published questions and answers, Discer's analysis of the documents; after the opening, the account's result and, with the Team plan, bidders, prices and winner. Reading it here registers no interest (opening it in Discer does).
Arguments
private_tender_idstringrequiredid from list_private_tenders
10.Version and changes
Current version: 1.2.0.
- October 3, 2026
/mcp/(trailing slash) accepted without a redirect; date filters in Québec time;sourceparameter limited to sources that publish tenders (seao,canadabuys,toronto); 405, 500 and NUL-character errors in theerrorformat; detailed response schemas in the OpenAPI. - September 29, 2026 · 1.0.0First version: 12 paths, 8 MCP tools.