# ANZ Tender Monitor — AusTender & NZ GETS Alerts (`datadeltas/anz-tender-monitor`) Actor

Monitor Australian and New Zealand government tenders in ONE feed. AusTender approaches to market, AusTender contract awards (who won, for how much) and NZ GETS opportunities, with keyword, category and value filters. Emits only NEW notices each run — schedule it and feed your bid pipeline.

- **URL**: https://apify.com/datadeltas/anz-tender-monitor.md
- **Developed by:** [Daniel Matthee](https://apify.com/datadeltas) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.50 / 1,000 new tender detecteds

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/actors/running/actors-in-store.md#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

## ANZ Tender Monitor — AusTender & NZ GETS Alerts

Bid teams working both sides of the Tasman watch two portals by hand. This
monitor watches them for you and emits **only what is new since your last
run**:

- **AusTender** (tenders.gov.au) — Australian Government **approaches to
  market** (open opportunities) *and* **contract notices** (who won, for how
  much, for how long).
- **NZ GETS** (gets.govt.nz) — **New Zealand tender opportunities** from
  every publishing agency: ministries, councils, CCOs, DHBs, schools.

Filter by your keywords, your categories, your deal size. Schedule it hourly
or daily and pipe the dataset into Slack, email, Sheets or your CRM with any
Apify integration. The first run backfills the last 14 days (configurable);
every run after that is a clean delta — no duplicates, deduplicated by the
portals' own notice references.

Official public data only: AusTender's OCDS contract API plus both portals'
public notice boards. No login, no scraped contact details.

### Example output records

An open New Zealand tender:

```json
{
  "source": "gets",
  "tenderId": "24350869",
  "title": "Duvauchelle Water Supply Treatment Plant",
  "buyer": "Christchurch City Council",
  "valueAUD": null,
  "supplier": null,
  "categories": ["47100000 - Water and wastewater treatment supply and disposal"],
  "publishedDate": "2026-06-22T16:30:00+12:00",
  "closeDate": "2026-09-01T12:00:00+12:00",
  "stage": "tender",
  "region": "Canterbury",
  "url": "https://www.gets.govt.nz/CCC/ExternalTenderDetails.htm?id=24350869",
  "detectedAt": "2026-08-31T11:05:12Z"
}
```

An Australian contract award — incumbent intelligence, with the winner and
the contract value:

```json
{
  "source": "austender",
  "tenderId": "CN4272937",
  "title": "BMAC Member",
  "buyer": "Bureau of Meteorology",
  "valueAUD": 154901.41,
  "supplier": "McBeath Pty Ltd atf Knuckey Family Trust",
  "categories": ["80100000"],
  "publishedDate": "2026-08-31T09:02:44Z",
  "closeDate": "2030-06-29T14:00:00Z",
  "stage": "award",
  "region": "ACT",
  "url": "https://www.tenders.gov.au/cn/search?KeywordTypeSearch=AllWord&Keyword=CN4272937",
  "detectedAt": "2026-08-31T10:20:12Z"
}
```

#### Reading the fields

| Field | Notes |
|---|---|
| `tenderId` | The portal's own reference — AusTender ATM ID, AusTender CN number, or GETS RFx ID. Unique within its portal; `source` + `tenderId` is the dedupe key. |
| `stage` | `tender` = open opportunity. `award` = Australian contract notice (GETS publishes no award notices). |
| `valueAUD` | Only **AusTender awards** publish a value. Open tenders (AU or NZ) come through as `null` — that is the portals, not the monitor. Non-AUD amounts are dropped rather than converted. |
| `supplier` | The winning supplier on `award` records; `null` on open tenders. |
| `categories` | UNSPSC `code - name` strings, e.g. `"86000000 - Education and Training Services"`. AusTender awards carry the bare code; if an AusTender detail page cannot be read the category falls back to the name alone. |
| `closeDate` | Submission deadline for tenders; contract end date for awards. GETS timestamps carry the published NZ offset (`+12:00`); AusTender publishes no offset, so its ATM times are local (ACT). |
| `publishedDate` | When the portal published the notice. AusTender ATMs publish a date only, no time. |
| `region` | GETS: the delivery region(s), e.g. `"Canterbury"`. AusTender ATM: the delivery locations. AusTender awards: the **supplier's state** (`ACT`, `QLD`, …) — the OCDS feed publishes no delivery region. |
| `url` | Link to the notice. AusTender contract notices have no public per-notice page, so the link is AusTender's contract search with the CN number pre-filled. |

### Input options

| Field | Type | Default | What it does |
|---|---|---|---|
| `sources` | array | `["austender","gets"]` | Which portals to watch |
| `keywords` | array | `[]` (all) | Case-insensitive match against title, description and buyer name, e.g. `["road resurfacing","cyber security"]` |
| `categories` | array | `[]` (all) | UNSPSC code prefix (`"81"`, `"43"`) or part of a category name (`"construction"`) |
| `minValueAUD` / `maxValueAUD` | integer | — | Value band. Only AusTender awards publish a value, so any bound restricts the feed to awards |
| `stages` | array | `["tender","award"]` | `tender` = open opportunities (both countries), `award` = AU contract awards |
| `sinceDays` | integer | `14` | Backfill window on the first run; scan window on every run |
| `maxItems` | integer | `500` | Cap on new notices per run (cost control) — the rest emit next run |
| `stateStoreName` | string | `anz-tender-monitor-state` | Change it to reset the monitor and re-run the backfill |

`keywords` and `categories` are combined with AND: a notice must match a
keyword *and* a category when both are set.

**Tip for the first run.** Open tenders stay listed for months, so a notice
published 60 days ago may still be accepting bids. `sinceDays` filters on the
*published* date, so raise it (up to 90) on your first run to sweep in
everything currently open, then leave it at the default for the daily delta.

### Use cases

1. **One bid pipeline for both countries** — `keywords: ["civil
   construction"]`, both sources, scheduled every morning. Australian ATMs
   and New Zealand RFTs land in the same sheet with their deadlines
   attached, instead of two people checking two portals.
2. **Who won, and when is it up again** — `stages: ["award"]` plus
   `minValueAUD: 250000`. Every substantial Australian Government contract
   award, with the winning supplier and the contract end date, so you know
   the incumbent and the re-compete date before the market does.
3. **Category radar for a specialist firm** — `categories: ["81"]`
   (engineering and research services) or `["Software"]`, no keywords. Every
   new opportunity in your category across ANZ, including the councils and
   agencies you have never heard of.

### Pricing events

| Event | Price | When |
|---|---|---|
| `actor-start` | $0.005 | Once per run |
| `tender-detected` | $0.015 | Per NEW notice emitted |

A daily schedule with keyword filters typically emits a handful of notices
per run — you pay for signal, not for polling. Runs that find nothing new
cost only the start fee.

### Data sources, freshness & scale

Measured on a live sweep (31 Aug 2026): the AusTender ATM board carried 71
current opportunities, the GETS board 338, and AusTender published 1,098
contract notices in the preceding 7 days. AusTender's OCDS API is the
official Department of Finance feed (CC BY 3.0 AU); both notice boards are
the same public pages a buyer would read.

Keyword accuracy is checked against the portals' own search. On the same
sweep, `keywords: ["construction"]` plus `categories: ["construction"]`
returned **exactly the 15 ATMs** that AusTender's own keyword search
returned for "construction" — no misses, no false positives.

If one portal has an outage the run degrades: it logs a warning, still
delivers the other portal, and exits successfully. If every source is down
the run fails loudly and leaves its state untouched, so nothing is silently
skipped.

Maintenance promise: both portals' field layouts are checked on every run —
missing fields log a named drift warning rather than crashing or silently
emptying your feed — and re-verified with each release.

### Changelog

- **0.1** (2026-08-31) — Initial release. AusTender ATMs, AusTender contract
  notices and NZ GETS in one delta feed; keyword, category, value and stage
  filters; 14-day backfill.

# Actor input Schema

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

Which portals to monitor. Default: both. 'austender' covers Australian Government approaches to market AND contract awards; 'gets' covers New Zealand GETS tender opportunities.

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

Case-insensitive words or phrases matched against the notice title, description and buyer name. Leave empty to match every notice (use the category or value filters instead).

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

Optional category filter. Give a UNSPSC code prefix (e.g. '81' for engineering and research services, '43' for IT) or part of a category name (e.g. 'construction'). A notice matches if any of its categories starts with a code you gave or contains a name you gave.

## `minValueAUD` (type: `integer`):

Only emit notices with a published value of at least this many AUD. NOTE: only AusTender contract awards publish a value — setting any bound therefore excludes all open tenders (AusTender ATMs and GETS notices publish no value).

## `maxValueAUD` (type: `integer`):

Only emit notices with a published value of at most this many AUD. Same caveat as the minimum: value bounds restrict the feed to AusTender contract awards.

## `stages` (type: `array`):

Which stages to emit: 'tender' (open opportunities, both countries) and/or 'award' (Australian contract awards — who won, for how much). GETS publishes no award notices, so 'award' alone means AusTender only. Default: both.

## `sinceDays` (type: `integer`):

How many days of published notices to scan. On the first run this is your backfill; on later runs only notices not seen before are emitted.

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

Cap on new notices emitted in a single run (cost control). Notices over the cap are picked up on the next run.

## `stateStoreName` (type: `string`):

Named key-value store holding the notice references already seen. Change it to reset the monitor and re-emit the backfill.

## Actor input object example

```json
{
  "sources": [
    "austender",
    "gets"
  ],
  "keywords": [
    "construction"
  ],
  "stages": [
    "tender",
    "award"
  ],
  "sinceDays": 14,
  "maxItems": 500,
  "stateStoreName": "anz-tender-monitor-state"
}
```

# Actor output Schema

## `records` (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 = {
    "keywords": [
        "construction"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datadeltas/anz-tender-monitor").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 = { "keywords": ["construction"] }

# Run the Actor and wait for it to finish
run = client.actor("datadeltas/anz-tender-monitor").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 '{
  "keywords": [
    "construction"
  ]
}' |
apify call datadeltas/anz-tender-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datadeltas/anz-tender-monitor"
        }
    }
}

```

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/EKLooH0uTaiDafgot/builds/yBoqx1q5qgGiioGTh/openapi.json
