# Canada Job Bank Scraper (`automation-lab/canada-job-bank-scraper`) Actor

🍁 Extract complete Canada Job Bank postings with employers, salaries, LMIA signals, qualifications, responsibilities, benefits, dates, and application details.

- **URL**: https://apify.com/automation-lab/canada-job-bank-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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.

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 Job Bank Scraper

Extract structured Canadian job listings from the public Government of Canada Job Bank.

Canada Job Bank Scraper turns keyword searches, locations, search-result URLs, and individual posting URLs into analysis-ready records. Each result includes the employer, pay, location, employment terms, qualifications, responsibilities, technologies, benefits, LMIA signals, and application details available on the source page.

Use the dataset in spreadsheets, ATS pipelines, labour-market dashboards, lead research, or scheduled monitors—without maintaining a crawler.

- 🍁 Public Job Bank search and detail pages
- 💵 Normalized salary values and currency
- 🧭 City, province, postal code, and work-location status
- 🛂 Requested and approved LMIA signals
- 📋 Requirements, tasks, technologies, and benefits
- 🔗 CSV, Excel, JSON, XML, API, webhooks, and integrations

### What does Canada Job Bank Scraper do?

The Actor searches `jobbank.gc.ca`, follows posting links, and saves one normalized record per job.

It supports three practical routes:

1. Search by one or more keywords.
2. Preserve filters from complete Job Bank search URLs.
3. Enrich individual Job Bank posting URLs.

The crawler removes temporary session identifiers from URLs and deduplicates postings by canonical ID. It stops when `maxItems` is reached.

By default, search workflows keep jobs posted directly on Job Bank. Enable `includeExternalJobs` when you also want externally sourced listings shown by Job Bank.

### Who is it for?

#### Recruiters and staffing teams

Build current candidate-market and employer datasets by title, skill, and Canadian location.

#### Job aggregators and ATS vendors

Normalize Job Bank records into a stable schema for search, matching, enrichment, or ingestion.

#### Immigration and LMIA researchers

Monitor postings that show requested or approved Labour Market Impact Assessment signals.

#### Labour-market analysts

Track pay ranges, employment terms, demand, technologies, and geographic patterns over time.

#### Data and automation teams

Schedule repeatable exports and send fresh results to databases, queues, webhooks, or cloud storage.

### Why use this Canada jobs scraper?

- ✅ No Job Bank account is required for public listings.
- ✅ Search and detail extraction are combined in one run.
- ✅ Explicit URLs and discovery inputs share the same filters.
- ✅ Numeric salary and hours fields are ready for analysis.
- ✅ Arrays preserve tasks, technologies, benefits, and qualifications.
- ✅ Conservative HTTP requests avoid a costly browser runtime.
- ✅ `maxItems` gives predictable run size and spend.
- ✅ Total extraction failure returns a failed run instead of silent empty data.

### What Canada Job Bank data can I extract?

| Field | Description |
|---|---|
| `jobBankId` | Posting ID from the canonical URL |
| `jobBankNumber` | Public Job Bank job number |
| `url` | Canonical posting URL |
| `title` | Job title |
| `employer` | Hiring employer |
| `employerWebsite` | Linked employer website when present |
| `datePosted` | Displayed posting date |
| `validThrough` | Advertised-until date |
| `city`, `province`, `postalCode` | Structured location |
| `workLocation` | On site, remote, or hybrid |
| `salaryMin`, `salaryMax` | Numeric salary range |
| `salaryCurrency`, `salaryUnit` | Currency and period |
| `hoursPerWeek` | Weekly hours when stated |
| `employmentType` | Permanent, temporary, full-time, or part-time terms |
| `vacancies` | Number of openings |
| `directApply` | Whether Job Bank Direct Apply is available |
| `lmiaRequested`, `lmiaApproved` | LMIA signals |
| `language`, `education`, `experience` | Candidate requirements |
| `workSetting` | Workplace or industry settings |
| `tasks` | Responsibilities listed by the employer |
| `technologies` | Software and technical knowledge |
| `benefits` | Listed employee benefits |
| `applicationMethod` | How the posting directs candidates to apply |
| `description` | Complete structured source description |
| `scrapedAt` | UTC extraction timestamp |

Fields absent from a particular posting are omitted rather than filled with invented values.

### How to scrape Canada Job Bank jobs

1. Open the Actor input page.
2. Enter one or more job keywords, such as `software developer`.
3. Optionally enter a location such as `Toronto, ON`.
4. Set a small `maxItems` for your first run.
5. Choose Direct Apply, remote/hybrid, or LMIA filters if needed.
6. Click **Start**.
7. Preview results in the Dataset tab.
8. Export to JSON, CSV, Excel, XML, or your integration.

For source-specific monitoring, paste a complete Job Bank search URL into `searchUrls`. Existing source filters and pagination parameters are preserved.

### Input parameters

| Input | Type | Default | Purpose |
|---|---|---:|---|
| `keywords` | string array | `software developer` | Search title, skill, or employer terms |
| `location` | string | `Toronto, ON` | Narrow keyword searches geographically |
| `searchUrls` | URL array | empty | Job Bank search or posting URLs |
| `maxItems` | integer | `10` | Maximum saved postings |
| `includeExternalJobs` | boolean | `false` | Include externally sourced listings |
| `directApplyOnly` | boolean | `false` | Require Direct Apply |
| `remoteOnly` | boolean | `false` | Require remote or hybrid work |
| `lmiaStatus` | enum | `any` | Any, requested, or approved LMIA |
| `maxConcurrency` | integer | `5` | Parallel detail requests, maximum 10 |
| `proxyConfiguration` | object | disabled | Optional Apify Proxy settings |

Provide at least one keyword or URL. Only public `www.jobbank.gc.ca/jobsearch/` URLs are accepted.

### Example input: keyword and location

```json
{
  "keywords": ["software developer", "data engineer"],
  "location": "Toronto, ON",
  "maxItems": 25,
  "includeExternalJobs": false
}
````

This discovers matching postings, follows detail pages, and saves up to 25 unique jobs.

### Example input: LMIA lead research

```json
{
  "keywords": ["cook", "truck driver"],
  "lmiaStatus": "approved",
  "maxItems": 50
}
```

The filter is checked against the extracted posting. Unknown values do not pass a requested or approved LMIA filter.

### Example input: specific posting URLs

```json
{
  "searchUrls": [
    { "url": "https://www.jobbank.gc.ca/jobsearch/jobposting/49875004" }
  ],
  "maxItems": 1
}
```

Use this mode to enrich known posting IDs from an ATS, spreadsheet, or monitoring queue.

### Output example

```json
{
  "jobBankId": "49875004",
  "jobBankNumber": "3618826",
  "url": "https://www.jobbank.gc.ca/jobsearch/jobposting/49875004",
  "title": "software developer",
  "employer": "Corinex",
  "city": "Vancouver",
  "province": "BC",
  "postalCode": "V6E 3V7",
  "workLocation": "On site",
  "salaryMin": 96000,
  "salaryMax": 100000,
  "salaryCurrency": "CAD",
  "salaryUnit": "YEAR",
  "hoursPerWeek": 30,
  "directApply": true,
  "lmiaRequested": false,
  "lmiaApproved": false,
  "applicationMethod": "Direct Apply on Job Bank",
  "source": "Government of Canada Job Bank"
}
```

The real record can also contain employment terms, vacancies, requirements, tasks, technologies, benefits, and a full description.

### How much does it cost to scrape Canada Job Bank?

The Actor uses pay-per-event pricing:

- one small Actor start charge per run;
- one item charge for each complete job posting saved.

Your Apify plan tier determines the item rate and higher tiers receive volume discounts. The input page shows the current live price before a run starts.

Keep early tests inexpensive with `maxItems: 10`. A run that saves no records does not incur item charges, though the start event still covers setup and validation work.

### Search filters and source behavior

Job Bank search URLs are useful when you need filters not represented as separate Actor fields. Configure the search on Job Bank, copy the resulting URL, and pass it through `searchUrls`.

The Actor applies these product filters after extraction:

- Direct Apply only;
- remote or hybrid only;
- LMIA requested;
- LMIA approved.

This means direct posting URLs cannot bypass a selected filter.

By default, externally aggregated results are excluded from search pages. Individual posting URLs remain extractable when they are valid public Job Bank detail pages.

### Pagination, limits, and deduplication

Keyword and search-URL workflows request additional result pages until:

- `maxItems` candidates are collected;
- no new posting IDs appear; or
- the source returns no result cards.

Temporary `jsessionid` segments and tracking queries are stripped from posting URLs. Duplicate IDs from multiple keywords or search URLs are fetched once.

If you supply overlapping searches, set `maxItems` to the total unique jobs you need, not the sum of each search page.

### Tips for reliable job data workflows

- 🎯 Start with precise titles rather than very broad words.
- 📍 Include a city or province when geography matters.
- 🔁 Schedule searches daily for incremental monitoring.
- 🆔 Store `jobBankId` as your external deduplication key.
- 📅 Use `validThrough` to remove expired opportunities.
- 💰 Compare salaries only after grouping by `salaryUnit`.
- 🛂 Treat LMIA indicators as source signals, not legal advice.
- 🧪 Test a copied search URL with 10 items before scaling.
- ⚙️ Keep concurrency conservative for this public service.

### Integrations and automation workflows

#### ATS enrichment

Send newly discovered posting URLs from your ATS, then merge results by `jobBankId`.

#### LMIA lead monitor

Schedule approved-LMIA searches and trigger a webhook when a new employer or posting appears.

#### Salary intelligence warehouse

Export numeric salary fields to BigQuery, Snowflake, PostgreSQL, or a spreadsheet. Normalize annual and hourly units downstream.

#### Job alert pipeline

Use Zapier or Make to notify Slack, email, or Microsoft Teams when records match title, location, pay, or technology rules.

#### Labour-market dashboard

Connect the dataset API to Power BI, Tableau, Looker Studio, or a notebook for time-series and geographic analysis.

### Use Canada Job Bank Scraper with the API

Replace `<APIFY_TOKEN>` with your token. Actor ID paths use `automation-lab/canada-job-bank-scraper`.

#### Node.js

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/canada-job-bank-scraper').call({
  keywords: ['software developer'],
  location: 'Toronto, ON',
  maxItems: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/canada-job-bank-scraper').call(run_input={
    'keywords': ['software developer'],
    'location': 'Toronto, ON',
    'maxItems': 10,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~canada-job-bank-scraper/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keywords":["software developer"],"location":"Toronto, ON","maxItems":10}'
```

### Use with MCP and AI agents

Expose the Actor to Claude Code with Apify MCP:

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=automation-lab/canada-job-bank-scraper"
```

For Claude Desktop, Cursor, or VS Code, add this server configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/canada-job-bank-scraper"
    }
  }
}
```

Example prompts for MCP usage:

- “Use the Canada Job Bank Scraper MCP tool to find 20 software jobs in Toronto and compare annual salary ranges.”
- “Extract this Job Bank posting and summarize required technologies.”
- “Find approved-LMIA cook postings and group employers by province.”
- “Monitor remote data engineer jobs and return only new posting IDs.”

### Data quality and limitations

Results reflect public Job Bank pages at extraction time.

Some employers do not provide every optional field. Missing values are omitted rather than guessed. The Actor does not infer salary periods, immigration eligibility, remote status, or LMIA approval.

Application instructions can be interactive on Job Bank. The Actor reports Direct Apply availability and points users to the canonical posting for the current application process.

Postings may expire or be removed between search discovery and detail fetching. One removed record is skipped; if every candidate fails extraction, the run fails visibly.

### Is it legal to scrape Canada Job Bank?

The Actor accesses public pages without logging in or bypassing access controls. Users remain responsible for their use of the data, applicable website terms, privacy law, employment rules, and downstream communications.

Do not use job data for discrimination, spam, misrepresentation, or automated employment decisions without appropriate safeguards.

Collect only what your workflow needs, respect source capacity, and define retention periods. For legal questions, consult qualified counsel.

### FAQ

#### Does this require a Job Bank account?

No. Public searches and posting details are available anonymously. Account-only features such as saved favourites are outside this Actor.

#### Can I scrape a specific Job Bank search?

Yes. Paste its full URL into `searchUrls`. The Actor preserves source query parameters and handles pagination.

#### Can I extract one job posting?

Yes. Pass its `/jobsearch/jobposting/<id>` URL and set `maxItems` to 1.

#### How do I find LMIA jobs?

Set `lmiaStatus` to `requested` or `approved`. The Actor fails closed when that signal is not present.

#### Why did my run return fewer records than `maxItems`?

The source may have fewer unique matching postings, filters may exclude records, or a posting may have expired between discovery and extraction.

#### Why did my no-results run fail?

A failed status prevents scheduled pipelines from treating total extraction failure as successful fresh data. Check spelling, URLs, location, and restrictive filters.

#### Are salaries always annual?

No. Read `salaryUnit` before comparing values. Job Bank may report hourly, weekly, monthly, or annual pay.

#### Does the Actor contact employers or apply for jobs?

No. It extracts public listing data only.

### Related job scrapers

Build broader recruiting and labour-market workflows with other automation-lab Actors:

- [Indeed Scraper](https://apify.com/automation-lab/indeed-scraper)
- [LinkedIn Jobs Scraper](https://apify.com/automation-lab/linkedin-jobs-scraper)
- [Google Jobs Scraper](https://apify.com/automation-lab/google-jobs-scraper)
- [Glassdoor Jobs Scraper](https://apify.com/automation-lab/glassdoor-jobs-scraper)
- [Remote OK Jobs Scraper](https://apify.com/automation-lab/remote-ok-jobs-scraper)

Use Canada Job Bank Scraper when the official Canadian source, Job Bank numbers, LMIA signals, and detailed Canadian location and employment fields are essential.

### Support

If a public Job Bank page works in your browser but the Actor cannot extract it, open an issue from the Actor page and include:

- the input used;
- the affected public URL;
- the run ID;
- the field or behavior you expected.

Do not include private credentials or candidate personal data. Reproducible examples help us investigate source changes quickly.

# Actor input Schema

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

Job titles, skills, or employer names to search on Job Bank.

## `location` (type: `string`):

City, province, territory, or postal area passed to Job Bank search.

## `searchUrls` (type: `array`):

Optional public jobbank.gc.ca search-result or job-posting URLs.

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

Stop after this many normalized jobs are saved.

## `includeExternalJobs` (type: `boolean`):

Include listings aggregated from outside Job Bank. Disabled by default for source consistency.

## `directApplyOnly` (type: `boolean`):

Return only postings that support Job Bank Direct Apply.

## `remoteOnly` (type: `boolean`):

Return only remote or hybrid postings; unknown work-location values fail closed.

## `lmiaStatus` (type: `string`):

Return any posting, requested-LMIA jobs, or approved-LMIA jobs.

## `maxConcurrency` (type: `integer`):

Parallel detail-page requests. Keep conservative to respect the public service.

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy settings. Direct HTTP normally works.

## Actor input object example

```json
{
  "keywords": [
    "software developer"
  ],
  "location": "Toronto, ON",
  "searchUrls": [],
  "maxItems": 10,
  "includeExternalJobs": false,
  "directApplyOnly": false,
  "remoteOnly": false,
  "lmiaStatus": "any",
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the normalized job dataset table with employer, location, salary, employment, LMIA, date, and posting URL fields.

# 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": [
        "software developer"
    ],
    "location": "Toronto, ON",
    "searchUrls": [],
    "maxItems": 10,
    "includeExternalJobs": false,
    "directApplyOnly": false,
    "remoteOnly": false,
    "lmiaStatus": "any",
    "maxConcurrency": 5,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/canada-job-bank-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 = {
    "keywords": ["software developer"],
    "location": "Toronto, ON",
    "searchUrls": [],
    "maxItems": 10,
    "includeExternalJobs": False,
    "directApplyOnly": False,
    "remoteOnly": False,
    "lmiaStatus": "any",
    "maxConcurrency": 5,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/canada-job-bank-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 '{
  "keywords": [
    "software developer"
  ],
  "location": "Toronto, ON",
  "searchUrls": [],
  "maxItems": 10,
  "includeExternalJobs": false,
  "directApplyOnly": false,
  "remoteOnly": false,
  "lmiaStatus": "any",
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call automation-lab/canada-job-bank-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Canada Job Bank Scraper",
        "description": "🍁 Extract complete Canada Job Bank postings with employers, salaries, LMIA signals, qualifications, responsibilities, benefits, dates, and application details.",
        "version": "0.1",
        "x-build-id": "ZYNyvPRskQe6ZAVYZ"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/automation-lab~canada-job-bank-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-automation-lab-canada-job-bank-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/automation-lab~canada-job-bank-scraper/runs": {
            "post": {
                "operationId": "runs-sync-automation-lab-canada-job-bank-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/automation-lab~canada-job-bank-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-automation-lab-canada-job-bank-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": {
                    "keywords": {
                        "title": "🔎 Keywords",
                        "type": "array",
                        "description": "Job titles, skills, or employer names to search on Job Bank.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "City, province, territory, or postal area passed to Job Bank search."
                    },
                    "searchUrls": {
                        "title": "Job Bank search or posting URLs",
                        "type": "array",
                        "description": "Optional public jobbank.gc.ca search-result or job-posting URLs.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxItems": {
                        "title": "Maximum job postings",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Stop after this many normalized jobs are saved.",
                        "default": 10
                    },
                    "includeExternalJobs": {
                        "title": "Include jobs from external sources",
                        "type": "boolean",
                        "description": "Include listings aggregated from outside Job Bank. Disabled by default for source consistency.",
                        "default": false
                    },
                    "directApplyOnly": {
                        "title": "Direct Apply only",
                        "type": "boolean",
                        "description": "Return only postings that support Job Bank Direct Apply.",
                        "default": false
                    },
                    "remoteOnly": {
                        "title": "Remote or hybrid only",
                        "type": "boolean",
                        "description": "Return only remote or hybrid postings; unknown work-location values fail closed.",
                        "default": false
                    },
                    "lmiaStatus": {
                        "title": "LMIA filter",
                        "enum": [
                            "any",
                            "requested",
                            "approved"
                        ],
                        "type": "string",
                        "description": "Return any posting, requested-LMIA jobs, or approved-LMIA jobs.",
                        "default": "any"
                    },
                    "maxConcurrency": {
                        "title": "Maximum concurrency",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Parallel detail-page requests. Keep conservative to respect the public service.",
                        "default": 5
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Optional Apify Proxy settings. Direct HTTP normally works."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
