# Canada Government Tenders - Aggregated & Normalized (`goodland.consulting/canada-government-tenders-scraper`) Actor

Every open Canadian government tender - federal, provincial, and municipal - pulled live and normalized into one schema, with bid documents, amendment tracking, and procurement method. Delta mode turns it into a bid-alert feed.

- **URL**: https://apify.com/goodland.consulting/canada-government-tenders-scraper.md
- **Developed by:** [Goodland Consulting](https://apify.com/goodland.consulting) (community)
- **Categories:** Lead generation, Developer tools, MCP servers
- **Stats:** 1 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Canada Government Tenders — Aggregated & Normalized

The fastest way to track Canadian government tenders as they're published — federal, provincial, and municipal, pulled live on every run and normalized into one clean schema. No 40MB bilingual CSVs, no juggling seven different portal layouts.

Every run hits the source portals directly, so what you get is exactly what's published right now — not a cached snapshot from an intermediary database.

Do you love this Actor? Please leave a review!
Found a bug, or need a source we don't cover yet? Please create an issue!

**Need higher volume, a login-gated source (e.g. your own MERX account), or a delivery pipeline into your CRM/Slack?** See "Need something custom?" below and get in touch — otherwise, read on.

### What you get

- **One schema, every portal.** Federal, provincial, and municipal tenders come out with the same fields (`title`, `category`, `regions`, `closingDate`, `contactEmail`, ...) no matter which source they came from.
- **Built-in filtering.** Keyword, province, and procurement-category filters run before data ever reaches your dataset — see [Filter behaviour by source](#filter-behaviour-by-source) for exactly what each source supports.
- **Delta mode for alerts.** Run it on a schedule and get only tenders you haven't seen before — turn this into an instant bid-alert pipeline via Apify's Slack, email, or webhook integrations.
- **Resilient by design.** Every source fails soft — a broken portal is logged and skipped, never fatal to the run, so one bad day on one site doesn't kill your data.
- **Indigenous procurement flagging.** Federal notices are checked against Canada's Indigenous set-aside program (PSIB/TIPS) and flagged automatically.

### Sources covered

| Source | Coverage |
| --- | --- |
| **CanadaBuys** | All federal tenders — the official Government of Canada open data feed |
| **SEAO** | Quebec public sector, via Données Québec open data |
| **Alberta Purchasing Connection** | Alberta ministries and public entities |
| **CivicInfo BC** | BC local government — municipalities, regional districts, school districts |
| **bids&tenders** | Hundreds of Canadian municipalities, school boards, universities, and agencies — pick your organizations (see below) |
| **SaskTenders** | Saskatchewan ministries, crown corporations, municipalities, school divisions, health authorities |
| **Nova Scotia** | NS public sector including the MASH sector (municipalities, academic, school boards, health) |

### Technical details

**Freshness.** CanadaBuys new-tender notices refresh every 2 hours (06:15–22:15 ET); its full open-tenders file refreshes daily (~07:00–08:30 ET). SEAO publishes weekly. Every other source is fetched live, straight off the portal, on each run.

**Memory.** Alberta, bids&tenders, Nova Scotia, and SaskTenders are more resource-intensive to fetch — give runs that include any of these sources at least **2048 MB**. CanadaBuys, SEAO, and CivicInfo BC run fine on the default memory.

**A source returned nothing — is it broken?** Possibly something changed on the source's end. Sources fail soft (logged and skipped, never fatal to the run) — if a source looks stuck at 0 for a while, open an issue and we'll take a look.

**Run order and `maxItems`.** Sources are fetched in the order you list them in `sources`. Once the run has pushed `maxItems` tenders, remaining sources in the list are skipped entirely for that run — put your highest-priority source first if you're running a tight cap.

**Expired notices.** Dropped by default based on `closingDate` at run time (`includeExpired: true` to keep them). SEAO's weekly dumps in particular carry a lot of already-closed notices.

#### Filter behaviour by source

Not every source carries every field, so filters apply differently depending on where a tender came from:

- **Keywords** — matched case-insensitively against title + description on **every** source.
- **Provinces** — supported on every source. Sources that only ever cover one province (Alberta, CivicInfo BC, SaskTenders, Nova Scotia) are simply included or excluded based on whether that province is in your filter.
- **Categories** (`CNST`/`GD`/`SRV`/`SRVTGD`) — only **CanadaBuys and SEAO** carry a real category code and are filtered by it. On other sources the `categories` filter has no effect — tenders come through regardless of category, and `category` is `null` (or a best-effort value on bids&tenders) in the output.
- **`newSinceHours`** — supported on every source. SEAO's data is published weekly, so short windows round up to the nearest week.

### Choosing bids&tenders organizations

The `bidsandtenders` source works against any organization hosted at `{org}.bidsandtenders.ca`. Set `bidsAndTendersOrgs` to the subdomains you want; leave it empty for a diverse national starter set (Saskatoon, Metro Vancouver, TDSB, Yukon, Halifax, Red Deer).

| Province | Example orgs |
| --- | --- |
| Ontario | `tdsb`, `durham`, `guelph`, `kitchener`, `waterloo`, `barrie`, `london`, `burlington` |
| Alberta | `reddeer`, `ae-ab` |
| Saskatchewan | `saskatoon`, `ae-sk` |
| British Columbia | `metrovancouver`, `bidcentral` |
| Nova Scotia | `halifax` |
| Manitoba | `mwsb` (Manitoba Water Services Board) |
| Yukon | `yukon` |
| National co-ops | `canoe` (Canoe Procurement Group of Canada), `bids` |

To check whether an organization is on the platform, open `https://{org}.bidsandtenders.ca/Module/Tenders/en` — if it loads a listing, the subdomain works.

### Indigenous procurement

Ottawa mandates a minimum 5% of federal contract value go to Indigenous business (the Procurement Strategy for Indigenous Business / Transformative Indigenous Procurement Strategy). This actor detects those set-asides automatically on CanadaBuys notices and flags them `indigenousSetAside: true` (`false` on other CanadaBuys notices; the field is omitted entirely on every other source, since they have no way to determine it). Set `indigenousOnly: true` to keep only flagged notices:

```json
{
  "sources": ["canadabuys"],
  "indigenousOnly": true
}
````

### Example input

Construction tenders in the Prairies, published in the last day:

```json
{
  "sources": ["canadabuys"],
  "categories": ["CNST"],
  "provinces": ["MB", "SK", "AB"],
  "newSinceHours": 24
}
```

### Turn it into a bid-alert pipeline

Set `deltaMode: true` and run this actor on a schedule (hourly, daily — your call). Each run only returns tenders it hasn't emitted before, so you can wire it straight into Apify's Slack, email, or webhook integrations for instant new-tender alerts:

```json
{
  "sources": ["canadabuys", "seao", "bidsandtenders"],
  "keywords": ["paving", "excavation", "snow removal"],
  "deltaMode": true
}
```

### Input parameters

**sources** — array, default `["canadabuys"]`. Which portals to pull from: `canadabuys`, `seao`, `apc`, `civicinfobc`, `bidsandtenders`, `sasktenders`, `novascotia`.

**keywords** — array, default `[]`. Case-insensitive match against title and description, on every source. Empty matches everything.

**provinces** — array, default `[]`. Only tenders deliverable in these provinces; Canada-wide tenders always match regardless of this filter. See [Filter behaviour by source](#filter-behaviour-by-source) for how matching differs by source.

**categories** — array, default `[]`. `CNST` (construction), `GD` (goods), `SRV` (services), `SRVTGD` (services related to goods). Only actually narrows CanadaBuys and SEAO — see the caveat above before relying on it for other sources.

**newSinceHours** — integer, default `0`. Only tenders published in the last N hours; `0` returns all open tenders. Behaviour varies slightly by source (see above) — none of that changes the output shape, just how the window is applied.

**deltaMode** — boolean, default `false`. Skip tenders already emitted by a previous run of this actor (tracked by tender id, persisted between runs). Pair with an Apify schedule for a standing bid-alert feed.

**maxItems** — integer, default `1000`. Hard cap on tenders pushed to the dataset in a single run, across all sources combined. Sources are processed in list order and stop being fetched once this is hit.

**bidsAndTendersOrgs** — array, default `[]` (national starter set). Org subdomains for the `bidsandtenders` source — see [Choosing bids\&tenders organizations](#choosing-bidstenders-organizations).

**includeExpired** — boolean, default `false`. Keep notices whose closing date has already passed.

**includeRaw** — boolean, default `false`. Attach the original source record to each item as `raw`. Useful when a field looks off and you want to see exactly what the source portal sent.

**indigenousOnly** — boolean, default `false`. Keep only CanadaBuys notices detected as Indigenous set-asides. Pair with `"sources": ["canadabuys"]` — other sources produce nothing under this filter.

**enrich** — boolean, default `true`. Emit the deep record: bid documents, amendment tracking, procurement method, selection criteria, trade agreements, bilingual title and description, and the full contact block. Set it to `false` for a leaner, cheaper record — the *tender enriched* event isn't charged when it's off.

### Pricing

Pay-per-event:

| Event | Price | Charged |
| --- | --- | --- |
| Actor start | $0.15 | Once per run |
| Result | $0.004 | Per normalized tender returned |
| Tender enriched | $0.006 | On top of Result, for each record carrying the deep record (bid documents, amendment tracking, procurement method, selection criteria, trade agreements, bilingual text, full contact block). Not charged when `enrich: false` |

An enriched tender costs **$0.01** all-in; a lean one (`enrich: false`) costs $0.004. A daily-scheduled delta feed of the federal source runs about **$11/month** — you only pay for tenders that are new or have changed since your last run.

### Output schema

**Every key is present on every record from every source.** A field a source can't supply is `null` (or `[]`) — never omitted. Ragged records break typed consumers, and in a CSV export an omitted key produces a column where "missing" and "false" look identical.

| Field | Type | Description |
| --- | --- | --- |
| `id` | text | Source-prefixed unique id, e.g. `canadabuys:ws1234` |
| `source` | text | `canadabuys` | `seao` | `apc` | `civicinfobc` | `bidsandtenders` | `sasktenders` | `novascotia` |
| `referenceNumber` | text | null | The source's own notice id |
| `solicitationNumber` | text | null | The number humans quote — distinct from `referenceNumber`. Your join key against email, CRM, and the portal itself |
| `title` / `titleFr` | text | Tender title, English and French |
| `description` / `descriptionFr` | text | Tender description, English and French (see source notes below) |
| `categories` | text\[] | `CNST` / `GD` / `SRV` / `SRVTGD`. Always an array — `[]` where the source has no category |
| `noticeType` | text | null | e.g. `RFP`, `RFI`, `ITT`, `ACAN` |
| `procurementMethod` | text | null | e.g. `Competitive - Open bidding`, sole-source. **The bid/no-bid decision** |
| `selectionCriteria` | text | null | Lowest price vs best value |
| `tradeAgreements` | text\[] | CETA / CFTA / CPTPP / WTO-GPA — determines who is *eligible* to bid |
| `procurementEntity` | text | null | The contracting organization |
| `endUserEntity` | text | null | The end user of the contract, where distinct from the procuring entity |
| `contactName` / `contactEmail` / `contactPhone` | text | null | Full contact block |
| `regions` | text\[] | Provinces where the work is delivered |
| `publicationDate` | timestamp | null | ISO 8601 |
| `closingDate` | timestamp | null | ISO 8601 |
| `expectedContractStartDate` / `expectedContractEndDate` | timestamp | null | For capacity planning |
| `status` | text | null | Normalized to `Open` across sources for active notices |
| `amendmentNumber` | text | null | `"000"` = never amended. See "Amendments" below |
| `amendmentDate` | timestamp | null | When the notice was last amended |
| `gsin` / `gsinDescription` | text | null | Canadian commodity classification |
| `unspsc` | text\[] | null | UNSPSC commodity codes |
| `unspscDescription` | text | null | Human-readable label for those codes |
| `documents` | text\[] | **Links to the bid documents and addenda** — the thing a bidder actually opens. Available on CanadaBuys and SEAO; `[]` elsewhere (see below) |
| `url` | text | null | Link to the notice. Every CanadaBuys item resolves to a working URL — native notices link to a search pre-filled with the solicitation number |
| `indigenousSetAside` | bool | null | `true`/`false` on CanadaBuys notices (detected PSIB/TIPS set-aside). `null` means the source can't determine it — which is not the same as "no" |
| `enriched` | bool | Whether the deep record was populated (see `enrich`) |
| `scrapedAt` | timestamp | When we saw this record. Needed for incremental sync |
| `raw` | json | Original source record, only present when `includeRaw: true` |

SEAO's open data doesn't include full notice body text, so `description` for SEAO items is synthesized from structured fields (notice type, buyer, commodity labels, delivery region) and `url` links to the full notice on seao.gouv.qc.ca instead.

Field coverage varies by source. On CanadaBuys, measured against the live feed: `solicitationNumber`, `amendmentNumber`, `procurementMethod`, `contactName` and the French fields are ~100% populated; `tradeAgreements` 100%; `selectionCriteria` 81%; `amendmentDate` 71%; `expectedContractStartDate` 55%; `contactPhone` 42%; `documents` 41%; `gsin` 5%.

#### Bid documents

`documents` carries links to the actual bid documents and addenda on **CanadaBuys** and **SEAO**. It is `[]` on the other sources, and honestly so: **bids\&tenders keeps its bid documents behind a vendor login** ("a free preview of the bid documents is available" — the rest needs an account). We don't authenticate to portals, so we don't have those files, and we'd rather say that than quietly ship an empty column and let you find out.

### Amendments

Tenders get amended — closing dates move, scope changes, addenda land. **57% of open federal notices carry at least one amendment.**

In `deltaMode`, a tender is re-emitted when it is new *or when it has changed since we last sent it to you*. Change is tracked by content fingerprint (the source's amendment counter where one exists, otherwise the title, closing date, and document set), so an amended notice reaches your alert pipeline instead of being silently swallowed as "already seen." An unchanged notice is never re-emitted.

### Deploy a pre-filtered copy

Every filter can also be set as an actor environment variable (**Actor Settings → Environment variables**). Run input always overrides the environment, so you can deploy a narrowed copy of this actor — e.g. "Manitoba Construction Tenders" — that needs no input at all:

| Variable | Format | Example |
| --- | --- | --- |
| `TENDERS_SOURCES` | comma-separated | `canadabuys,seao` |
| `TENDERS_KEYWORDS` | comma-separated | `paving,excavation,snow removal` |
| `TENDERS_PROVINCES` | comma-separated codes | `MB,SK,AB` |
| `TENDERS_CATEGORIES` | comma-separated | `CNST,SRV` |
| `TENDERS_NEW_SINCE_HOURS` | integer | `24` |
| `TENDERS_MAX_ITEMS` | integer | `500` |
| `TENDERS_DELTA_MODE` | `true`/`false` | `true` |
| `TENDERS_INCLUDE_RAW` | `true`/`false` | `false` |
| `TENDERS_BNT_ORGS` | comma-separated subdomains | `saskatoon,tdsb,halifax,mwsb` |
| `TENDERS_INCLUDE_EXPIRED` | `true`/`false` | `false` |
| `TENDERS_INDIGENOUS_ONLY` | `true`/`false` | `true` |

### FAQ

**Wait, is this actually scraping live, or a pre-built database?**
Live. Every run fetches directly from each source portal you select, in real time. There's no intermediary database or caching layer; what you get is what's on the portal right now.

**Where does the data come from?**
Federal data comes from the Government of Canada's official open data files under the Open Government Licence. Provincial and municipal sources are each portal's own public, unauthenticated data — no login-protected portal is accessed.

**Can I get a province or portal that isn't listed?**
We're regularly expanding coverage. If there's a province or portal you need, get in touch — see "Need something custom?" below.

**Can I access a login-gated source like MERX?**
Not through this public actor — MERX (used by Manitoba's government and Ontario's broader public sector, among others) is login-walled and its terms of service prohibit automated access. If you hold your own MERX credentials and want a private pipeline built against them, that's a custom engagement — see below.

**How do I get a scheduled export as a file I can pull automatically?**

1. Save your configured input as an [Apify task](https://docs.apify.com/platform/actors/running/tasks).
2. Add a [schedule](https://docs.apify.com/platform/schedules) to that task (e.g. hourly).
3. Pull the latest successful run's dataset from:
   `https://api.apify.com/v2/actor-tasks/TASK_ID/runs/last/dataset/items?token=YOUR_API_TOKEN&format=json&status=SUCCEEDED`

   Replace `TASK_ID` with your task's id and `YOUR_API_TOKEN` with your token from **Settings → API & Integrations**. Swap `format=json` for `csv`, `xml`, `xlsx`, or others — see the [dataset items API docs](https://docs.apify.com/api/v2/dataset-items-get).

### Need something custom?

Custom work is available: additional provincial or MERX-account-based feeds, closing-date reminders, CRM/Slack delivery, or tender-to-capability matching against your service catalog. Contact us via Apify to discuss.

### Legal note

Federal data comes from the Government of Canada's open data portal under the Open Government Licence. This actor does not access login-protected portals.

# Actor input Schema

## `sources` (type: `array`):

Tender portals to pull from. Failures on one source are logged and skipped, never fatal to the run.

## `keywords` (type: `array`):

Case-insensitive match against title and description. Empty = all tenders.

## `provinces` (type: `array`):

Only tenders deliverable in these provinces. Tenders deliverable Canada-wide always match. Empty = all provinces.

## `categories` (type: `array`):

CNST=construction, GD=goods, SRV=services, SRVTGD=services related to goods.

## `newSinceHours` (type: `integer`):

0 = all open tenders. 1-24 uses the fast 'new tenders' feed.

## `deltaMode` (type: `boolean`):

Skip tenders already emitted by previous runs. Pair with a schedule for alerts.

## `maxItems` (type: `integer`):

Maximum number of tenders to push to the dataset across all sources.

## `bidsAndTendersOrgs` (type: `array`):

Org subdomains for the 'bidsandtenders' source ({org}.bidsandtenders.ca). Empty = a diverse national starter set (saskatoon, metrovancouver, tdsb, yukon, halifax, reddeer). Examples by province — ON: durham, guelph, kitchener, waterloo, regionofwaterloo, barrie, london, cityofpeterborough, burlington; AB: reddeer, ae-ab; SK: saskatoon, ae-sk; BC: metrovancouver, bidcentral; NS: halifax; MB: mwsb; Indigenous orgs: fnesl; plus national co-ops canoe and bids. See the README for the full list.

## `includeExpired` (type: `boolean`):

Keep notices whose closing date has already passed. Off by default — SEAO's weekly dumps in particular contain many closed notices.

## `includeRaw` (type: `boolean`):

Attach the original source record to each item as 'raw'. Useful for debugging missing fields.

## `indigenousOnly` (type: `boolean`):

Keep only Indigenous-procurement notices: CanadaBuys notices detected as Procurement Strategy for Indigenous Business (PSIB) set-asides. Other sources produce nothing under this filter, so pair it with canadabuys.

## `enrich` (type: `boolean`):

Emit the deep record: bid documents, amendment tracking, procurement method, selection criteria, trade agreements, bilingual title/description, and the full contact block. Turn this off for a leaner, cheaper record — the 'tender enriched' event is not charged when it's off.

## Actor input object example

```json
{
  "sources": [
    "canadabuys"
  ],
  "keywords": [],
  "provinces": [],
  "categories": [],
  "newSinceHours": 0,
  "deltaMode": false,
  "maxItems": 1000,
  "bidsAndTendersOrgs": [],
  "includeExpired": false,
  "includeRaw": false,
  "indigenousOnly": false,
  "enrich": true
}
```

# Actor output Schema

## `tenders` (type: `string`):

Every tender notice this run emitted, one normalized schema across all seven portals. Each record carries the title and description (English and French), procurement method, selection criteria, trade agreements governing bid eligibility, the closing date, the full contact block, links to bid documents where the source publishes them, and amendment tracking. In delta mode this dataset contains only notices that are new or have changed since the previous run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("goodland.consulting/canada-government-tenders-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("goodland.consulting/canada-government-tenders-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call goodland.consulting/canada-government-tenders-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=goodland.consulting/canada-government-tenders-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Canada Government Tenders - Aggregated & Normalized",
        "description": "Every open Canadian government tender - federal, provincial, and municipal - pulled live and normalized into one schema, with bid documents, amendment tracking, and procurement method. Delta mode turns it into a bid-alert feed.",
        "version": "0.2",
        "x-build-id": "TgbNu5EN5tencfjjc"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/goodland.consulting~canada-government-tenders-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-goodland.consulting-canada-government-tenders-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/goodland.consulting~canada-government-tenders-scraper/runs": {
            "post": {
                "operationId": "runs-sync-goodland.consulting-canada-government-tenders-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/goodland.consulting~canada-government-tenders-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-goodland.consulting-canada-government-tenders-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "sources": {
                        "title": "Sources",
                        "type": "array",
                        "description": "Tender portals to pull from. Failures on one source are logged and skipped, never fatal to the run.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "canadabuys",
                                "seao",
                                "apc",
                                "civicinfobc",
                                "sasktenders",
                                "novascotia",
                                "bidsandtenders"
                            ],
                            "enumTitles": [
                                "CanadaBuys (federal, validated)",
                                "SEAO (Quebec open data)",
                                "Alberta Purchasing Connection (working)",
                                "CivicInfo BC - BC local government (RSS)",
                                "SaskTenders (working)",
                                "Nova Scotia incl. MASH sector (working)",
                                "bids&tenders platform - municipalities/school boards (working)"
                            ]
                        },
                        "default": [
                            "canadabuys"
                        ]
                    },
                    "keywords": {
                        "title": "Keywords",
                        "type": "array",
                        "description": "Case-insensitive match against title and description. Empty = all tenders.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "provinces": {
                        "title": "Provinces (delivery region)",
                        "type": "array",
                        "description": "Only tenders deliverable in these provinces. Tenders deliverable Canada-wide always match. Empty = all provinces.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "AB",
                                "BC",
                                "MB",
                                "NB",
                                "NL",
                                "NS",
                                "NT",
                                "NU",
                                "ON",
                                "PE",
                                "QC",
                                "SK",
                                "YT"
                            ],
                            "enumTitles": [
                                "Alberta",
                                "British Columbia",
                                "Manitoba",
                                "New Brunswick",
                                "Newfoundland and Labrador",
                                "Nova Scotia",
                                "Northwest Territories",
                                "Nunavut",
                                "Ontario",
                                "Prince Edward Island",
                                "Quebec",
                                "Saskatchewan",
                                "Yukon"
                            ]
                        },
                        "default": []
                    },
                    "categories": {
                        "title": "Procurement categories",
                        "type": "array",
                        "description": "CNST=construction, GD=goods, SRV=services, SRVTGD=services related to goods.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "CNST",
                                "GD",
                                "SRV",
                                "SRVTGD"
                            ]
                        },
                        "default": []
                    },
                    "newSinceHours": {
                        "title": "Only tenders published in last N hours",
                        "type": "integer",
                        "description": "0 = all open tenders. 1-24 uses the fast 'new tenders' feed.",
                        "default": 0
                    },
                    "deltaMode": {
                        "title": "Delta mode (only new since last run)",
                        "type": "boolean",
                        "description": "Skip tenders already emitted by previous runs. Pair with a schedule for alerts.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Max items",
                        "type": "integer",
                        "description": "Maximum number of tenders to push to the dataset across all sources.",
                        "default": 1000
                    },
                    "bidsAndTendersOrgs": {
                        "title": "bids&tenders org subdomains",
                        "type": "array",
                        "description": "Org subdomains for the 'bidsandtenders' source ({org}.bidsandtenders.ca). Empty = a diverse national starter set (saskatoon, metrovancouver, tdsb, yukon, halifax, reddeer). Examples by province — ON: durham, guelph, kitchener, waterloo, regionofwaterloo, barrie, london, cityofpeterborough, burlington; AB: reddeer, ae-ab; SK: saskatoon, ae-sk; BC: metrovancouver, bidcentral; NS: halifax; MB: mwsb; Indigenous orgs: fnesl; plus national co-ops canoe and bids. See the README for the full list.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "includeExpired": {
                        "title": "Include expired notices",
                        "type": "boolean",
                        "description": "Keep notices whose closing date has already passed. Off by default — SEAO's weekly dumps in particular contain many closed notices.",
                        "default": false
                    },
                    "includeRaw": {
                        "title": "Include raw source row",
                        "type": "boolean",
                        "description": "Attach the original source record to each item as 'raw'. Useful for debugging missing fields.",
                        "default": false
                    },
                    "indigenousOnly": {
                        "title": "Indigenous set-aside only",
                        "type": "boolean",
                        "description": "Keep only Indigenous-procurement notices: CanadaBuys notices detected as Procurement Strategy for Indigenous Business (PSIB) set-asides. Other sources produce nothing under this filter, so pair it with canadabuys.",
                        "default": false
                    },
                    "enrich": {
                        "title": "Enrich (deep record)",
                        "type": "boolean",
                        "description": "Emit the deep record: bid documents, amendment tracking, procurement method, selection criteria, trade agreements, bilingual title/description, and the full contact block. Turn this off for a leaner, cheaper record — the 'tender enriched' event is not charged when it's off.",
                        "default": true
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
