# Canada Federal Grant Amendment Watch (`nexgenwatch/ca-federal-grant-amendment-watch`) Actor

Amendments to federal grant and contribution agreements as Canada discloses them - which agreement moved, the amendment number and date, and the restated value. Every amendment in this source carries a date; 1,446 of 1,446 sampled did.

- **URL**: https://apify.com/nexgenwatch/ca-federal-grant-amendment-watch.md
- **Developed by:** [NexGen Watch](https://apify.com/nexgenwatch) (community)
- **Categories:** Business, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $67.00 / 1,000 amendment deltas

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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 Federal Grant Amendment Watch

Amendments to federal grant and contribution agreements as Canada discloses them - which agreement moved, the amendment number and date, and the restated value. Every amendment in this source carries a date; 1,446 of 1,446 sampled did. Bounded by your filters.

### Source

Proactive Disclosure - Grants and Contributions, Treasury Board of Canada Secretariat,
published on open.canada.ca (public, logged-out, no key).

- `https://open.canada.ca/data/en/dataset/432527ab-7aac-45b5-81d6-7597107a7013`

**Declared update frequency: `P3M` - QUARTERLY.** Measured 2026-07-28: **1,315,562 rows**
across the whole disclosure.

### Run this MONTHLY, not daily

The source publishes quarterly and departments run behind that - one department's newest
reported quarter was 2025-2026 Q4 while the calendar sat in FY2026-2027 Q2, a **two-quarter
lag**. A daily run would charge a source check about ninety times to observe one publication
event. Monthly is the cadence this source deserves and the one this listing recommends.

### It reads an API, not the 2.29 GB file

The bulk CSV is **2,289,162,586 bytes**. This Actor never downloads it. It reads the CKAN
datastore endpoint, which is bounded, sortable and paginated.

The API offers **exact-match filters only** - no date range, no text search above 100,000 rows,
no SQL. That is why the watch is bounded by **who and what**, not by when.

### Your filters bound the watch, and the cap REFUSES rather than truncates

Supply at least one of: department, agreement type, recipient type, province, city, recipient
legal name, programme name. With none, the run fails and says so - this Actor will not watch
1.3 million agreements.

One run watches at most **25,000 rows**. Over that the run **fails and names the number**. It
does not quietly watch a slice of your own filter, because a truncated window cannot tell a
withdrawal from the cut-off and would report records sliding out of it as though the
government had pulled them.

### Name filters are case-sensitive

Measured at the source: `recipient_legal_name="Carleton University"` returns **232** rows and
`"carleton university"` returns **0**. Same organisation. So a name, city or programme filter
that matches nothing **fails the run and names the case**, rather than reporting an empty
source. An outage you can see beats an emptiness you cannot.

### The arrival clock is inside the reference number

`ref_number` carries the fiscal quarter the award was reported in - `001-2022-2023-Q3-00019`.
Measured across 6,578 rows from two departments: 6,578 parsed a quarter, 0 did not. That is
what gets parsed and signed.

**The datastore `_id` is NOT an arrival clock and is never signed.** The newest 500 rows by
`_id` are all one department and span six fiscal years, because `_id` orders by when a
department last re-uploaded its whole file. Signing it would report a routine republication as
a flood of new awards.

### The key

`ref_number` alone is not unique - measured on a full department read, 2,204 distinct reference
numbers across 2,578 rows, because a number repeats across an agreement's amendments. The key
is **`ref_number` plus `amendment_number`**, both carried verbatim from the source, nothing
inferred and nothing hashed.

### Pricing

Pay-per-event on the ratified four-tier ladder (FREE → GOLD, with Platinum and Diamond floored
at the Gold rate). Apify applies its own plan discount on top.

| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| Actor start (`apify-actor-start`) | $0.02 | $0.02 | $0.02 | $0.02 |
| Source check (`source-check`) | $0.10 | $0.09 | $0.08 | $0.067 |
| Amendment delta (`cafed-disclosure-delta`) | $0.10 | $0.09 | $0.08 | $0.067 |

`source-check` is charged **once per run**, after the source enumeration terminates — seed runs
and no-change runs included. It is **not** charged when the source refused the read, and not when the run is refused for an unbounded or oversized watch set.

`cafed-disclosure-delta` is charged **per emitted delta**, in watch mode only. Seed runs and no-change runs
charge nothing here.

`apify-actor-start` is the platform's reserved event, never charged in this code. The Actor is
clamped to **1024 MB on both settings**, so it is charged exactly **once** per run — the
platform bills it once per gigabyte of run memory.

### Snapshot mode is a PREVIEW

`watch_mode: false` returns at most **25 records**, hard-capped in code, labelled
`output_mode: "preview"`. This Actor sells change detection, not bulk export.

### Watch semantics

The first watch run stores a private baseline and emits **zero** deltas. Later runs emit a
delta for each **new row appearing** in your filtered set. A department restating a figure is a
correction, not a new award, and classifies as nothing; a row withdrawn from the disclosure
likewise. Billed deltas are capped at 500 per run; the overflow is a named PARTIAL withholding,
never billed, and re-detected on the next run.

### One row class per Actor

This Actor emits **amendment** rows and nothing else. Its sibling reads the same source for
the other class, each with its own baseline and its own price.

### Terminal states

`NORMAL` - `SUCCEEDED-0: GENUINE_EMPTY` - `SUCCEEDED-0` (no change) - `PARTIAL` - `BLOCKED`.
A zero with no evidence FAILS loud rather than exiting 0 quietly, and a case-sensitive filter
that matched nothing is never reported as an empty source.

# Actor input Schema

## `owner_org` (type: `string`):

The government's own department code, exact match - e.g. wage, acoa-apeca, nserc-crsng, isc-sac. Measured 2026-07-28: wage 2,578 rows, acoa-apeca 30,296, cihr-irsc 45,887, nserc-crsng 156,594, isc-sac 156,896.

## `agreement_type` (type: `string`):

G for grant, C for contribution. Measured: G 529,552 rows, C 731,431.

## `recipient_type` (type: `string`):

The source's own recipient-type code, exact match - e.g. S 24,148 rows, P 230,270.

## `recipient_province` (type: `string`):

Two-letter code, exact match. Measured: ON 379,375 rows, BC 168,380.

## `recipient_country` (type: `string`):

Two-letter code, exact match. CA 1,292,507 rows, US 8,941.

## `recipient_city` (type: `string`):

EXACT AND CASE-SENSITIVE at the source. 'Ottawa' returns 14,314 rows. A zero result FAILS the run naming the spelling rather than reporting an empty source.

## `recipient_legal_name` (type: `string`):

EXACT AND CASE-SENSITIVE. Measured 2026-07-28: 'Carleton University' returns 232 rows, 'carleton university' returns 0. A zero result FAILS the run naming the case rather than reporting an empty source.

## `prog_name_en` (type: `string`):

EXACT AND CASE-SENSITIVE, the full programme name as the department writes it. A zero result FAILS the run.

## `watch_mode` (type: `boolean`):

On: emit CHANGES against a stored baseline (the product). Off: a labelled PREVIEW of at most 25 records, which is not an export path.

## `baseline_id` (type: `string`):

Names the stored baseline. Use different ids to watch different filter combinations independently without their baselines colliding.

## Actor input object example

```json
{
  "owner_org": "wage",
  "agreement_type": "",
  "recipient_type": "",
  "recipient_province": "",
  "recipient_country": "",
  "recipient_city": "",
  "recipient_legal_name": "",
  "prog_name_en": "",
  "watch_mode": true,
  "baseline_id": "default"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "owner_org": "wage",
    "agreement_type": "",
    "recipient_type": "",
    "recipient_province": "",
    "recipient_country": "",
    "recipient_city": "",
    "recipient_legal_name": "",
    "prog_name_en": "",
    "watch_mode": false,
    "baseline_id": "default"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgenwatch/ca-federal-grant-amendment-watch").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 = {
    "owner_org": "wage",
    "agreement_type": "",
    "recipient_type": "",
    "recipient_province": "",
    "recipient_country": "",
    "recipient_city": "",
    "recipient_legal_name": "",
    "prog_name_en": "",
    "watch_mode": False,
    "baseline_id": "default",
}

# Run the Actor and wait for it to finish
run = client.actor("nexgenwatch/ca-federal-grant-amendment-watch").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "owner_org": "wage",
  "agreement_type": "",
  "recipient_type": "",
  "recipient_province": "",
  "recipient_country": "",
  "recipient_city": "",
  "recipient_legal_name": "",
  "prog_name_en": "",
  "watch_mode": false,
  "baseline_id": "default"
}' |
apify call nexgenwatch/ca-federal-grant-amendment-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgenwatch/ca-federal-grant-amendment-watch"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/szccECMT5ZJCVuvbc/builds/shtz3JGdlmaoE8Oc8/openapi.json
