# US & Canada Jobs API (`thejobsapi/us-canada-jobs-api`) Actor

Search US and Canadian jobs by keyword, location, remote work and salary. Get full descriptions, source details and original employer links. Try three saved sample records free of job charges. Live jobs will be billed through Apify. No separate API account.

- **URL**: https://apify.com/thejobsapi/us-canada-jobs-api.md
- **Developed by:** [The Jobs API](https://apify.com/thejobsapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / 1,000 live jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## US & Canada Jobs API

**Find jobs for your website, spreadsheet, or app.** Search job listings from employer career sites in the United States and Canada.

### Try the free sample

Choose **Preview sample data**, then click **Start**. You get three saved Canadian job records with full descriptions and nested source fields.

Samples were captured on **October 15, 2026**. Each row is marked `_sample: true`. They are examples, not current vacancy checks. Preview ignores country and search filters. No paid job events are charged for preview.

### Search live jobs

Choose **Search live jobs**, select a country, add your filters, and set a result limit. Live results are billed through Apify. You do not need a separate API account or API key.

**US$0.50 per 1,000 live jobs or saved catch-up updates.** Platform usage is included. No startup fee and no separate charge for descriptions or source details. Check the Pricing tab for the current price before each run.

### Catch up after a missed import

Keep your job board in sync even if your import was offline. Choose **Catch up on job updates (paid)**. No separate Jobs API key is needed.

1. Open **Input > JSON** and paste this small first run:

```json
{"mode":"changes","country":"US","resumeToken":"US:0","maxItems":10,"maxRequests":30}
```

2. Start the run. Open **Updates** to see what to add, update or remove. Export **All fields > JSON** for the full records.
3. Apply the rows in order. For `upsert`, save or replace the job using `job_id`. For `remove`, remove that job from your active listings. An unavailable job is marked `not_available`, not falsely labelled closed.
4. Open **Run summary and resume cursor**. Copy its `resumeInput` into your next run **only after you have applied all saved rows**.
5. Repeat until `caughtUp` is `true`. Save that token for your next daily import. Use a separate token for Canada (`CA:0` to begin).

The first run starts at the beginning of retained change history. It may take many runs to catch up. A token remembers your place, not a date. Existing search cursors do not work here. The Actor does not update a saved task's input automatically: your integration must pass the last successfully applied token into the next run. Scheduling an unchanged task repeats the same rows and charges again.

#### How updates work

Each row includes `event_id`, `job_id`, `operation`, the original event type and time, and the job's **current** data. A job that closed and later reopened is returned as an upsert when it is currently active. This is a current-state sync feed, not a historical snapshot service.

The feed uses retained change records, not a one-day window. Retention is not guaranteed forever, and jobs without a retained change are not a complete initial catalogue. Use live search for your initial import, then catch up. A missing row from a limited search is never proof that a job closed.

Catch-up mode takes a country and token, without search filters. Apply your own niche filters to each upsert. If a job no longer matches, remove it from your niche board. Process remove rows even if they have no job details.

Delivery is **at least once**. A failed write or retried run may repeat rows and charges. Deduplicate by `event_id`, process runs for each country in order, and save your token together with the imported data. Do not run two imports for the same country at once. Always inspect partial output after a failed run before resuming.

Ten updates cost **US$0.005** at the current rate. Each update checks the job's current details, so allow roughly one request per update plus one per page. The example uses 30 requests for 10 updates to leave room for retries. A run stops safely at your item, request or cost limit; use its saved token to continue.

### What can I build?

- **A niche job board:** find roles for a city, industry, or skill.
- **A remote jobs newsletter:** link readers to the original employer posting.
- **A hiring dashboard:** follow roles and employers over time.
- **A daily workflow:** send new listings to a spreadsheet or automation.

### What is included?

Each row preserves the full API job object: title, employer, locations, source, job URL, application link when supplied, text and HTML descriptions, and available source-specific details. Salary and employment type depend on the source. Missing information stays missing. Any derived data stays separate from source-provided facts.

Use **All fields** and export **JSON** to retain nested details. Apify also supports CSV, Excel and XML exports. Selected table views may export only their selected columns.

The run summary includes the saved job count, request count, stop reason and resume cursor. A short or empty page can still have more matches later. The Actor continues until it reaches the end, your result limit, your request limit, or the available job budget.

### Ready-to-use searches

#### US software jobs with salary

```json
{
  "mode": "live",
  "country": "US",
  "title": "software engineer",
  "has_salary": true,
  "maxItems": 100,
  "maxRequests": 10
}
```

#### Remote jobs discovered in the last day

```json
{
  "mode": "live",
  "country": "US",
  "remote": true,
  "window": "24h",
  "maxItems": 100,
  "maxRequests": 10
}
```

Remote jobs can still require an applicant to live in a specific place. Check the original eligibility details.

#### Canadian healthcare jobs

```json
{
  "mode": "live",
  "country": "CA",
  "region": "ON,BC",
  "title": "nurse OR physician",
  "maxItems": 100,
  "maxRequests": 10
}
```

#### Jobs from Greenhouse, Lever and Ashby

Set `source` to `greenhouse,lever,ashby`. Add the country and any title or location filters you need. This searches the catalogue; it does not start a new scrape of an employer site.

### Search tips

| Input | What it does |
| --- | --- |
| Country | United States (`US`) or Canada (`CA`). Run once per country. |
| Keywords | Searches title, employer and description. Words combine with AND. Use `OR`, quoted phrases and exclusions to narrow a search. |
| Title | Searches only job titles. |
| Region | Two-letter codes: `CA,NY` for US states or `ON,BC` for Canadian provinces. |
| City | A city such as Austin or Toronto. |
| Remote only | Keeps jobs marked remote by the API. |
| Salary only | Keeps jobs with a structured salary amount. |
| First discovered within | Last hour, day, week, month or six months. This is discovery time, not employer posting time. |
| Resume cursor | Continues a previous search using the same country and filters. |

Filters combine. If a narrow search returns no jobs but has a resume cursor, increase the request limit carefully or continue with that cursor.

### Limits and billing

The defaults are **100 jobs** and **10 upstream requests**. You may request up to 5,000 jobs or 100 requests per run. Your Apify maximum-cost setting can reduce the result limit further.

The only paid event is **Live job**, charged once per live job or catch-up update saved. At US$0.50 per 1,000, 100 jobs cost $0.05 and 5,000 jobs cost $2.50. There is no separate startup, search, description, or enrichment event. Check the **Pricing** tab for the current event price before running live data. An empty successful search has no job-result charge. Preview does not trigger paid job events.

Repeating a search can charge again for the same jobs. A run can stop at your limits before exhausting every match. It is not necessarily a complete feed.

### Daily imports and automation

Save your live search as an Apify task and add a schedule. For new listings, begin with `window: "24h"`, leave the cursor empty, and run daily. Store the job ID to deduplicate results across runs. The Actor deduplicates repeated IDs within each run.

A discovery window is not an expiration feed. Do not delete jobs simply because they are absent from a limited search. Coverage, refresh timing, and available fields vary by source.

Use Apify datasets with your own code, Make, n8n, or other supported workflows. Their costs and setup are separate. No employer-site account or applicant login is needed, and the Actor does not submit applications.

### Troubleshooting

- **Live data unavailable:** open an Actor issue with your run ID; the publisher may need to restore its data allowance.
- **No results:** broaden the filters and inspect the resume cursor.
- **Budget too small:** set a maximum cost that covers at least one live job.
- **Rate limit or temporary failure:** wait, then resume using the saved cursor.
- **Run stopped during a write:** inspect saved rows and deduplicate by job ID before resuming.

For help or a missing employer, open an Actor issue with your filters and run ID. Do not include credentials or personal applicant information.

# Actor input Schema

## `mode` (type: `string`):

Preview returns three saved Canadian examples, not current jobs, and ignores search filters. Live mode searches US or Canada and charges for each saved job through Apify. Catch-up returns current job states for ordered change events. Search filters are not allowed in catch-up mode.

## `country` (type: `string`):

Country to search in live mode. Run once per country for separate US and Canada datasets.

## `q` (type: `string`):

Search titles, employers and descriptions. Example: software engineer. Words match together; OR and quoted phrases are supported.

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

Maximum saved jobs or catch-up updates. Billed at the price shown on Pricing. Your run budget may reduce this limit.

## `maxRequests` (type: `integer`):

Hard request cap, including retries. Catch-up needs about one request per update plus one per page: use 30 for a 10-update test. Copy the saved resume input to continue.

## `region` (type: `string`):

US examples: CA,NY. Canada examples: ON,BC. Use uppercase two-letter codes separated by commas.

## `city` (type: `string`):

City name, for example Austin or Toronto.

## `remote` (type: `boolean`):

When selected, return jobs marked remote by the API. Remote does not mean work from any country; check job eligibility.

## `has_salary` (type: `boolean`):

Only jobs with a structured salary amount. Missing salary information is not invented.

## `window` (type: `string`):

Filters when our catalogue first saw the job, not its employer posting date.

## `employment_type` (type: `string`):

Optional employment type supplied by the source.

## `title` (type: `string`):

Narrow the job title. Example: nurse OR physician. This combines with the other filters.

## `source` (type: `string`):

Optional source system name, for example greenhouse, lever or ashby. Comma-separated names are allowed.

## `cursor` (type: `string`):

Copy next_cursor from a previous run OUTPUT summary. Keep the same country and search filters. Leave empty for a new search.

## `resumeToken` (type: `string`):

Paste resumeToken from a previous catch-up OUTPUT after applying its rows. Blank starts at the beginning of retained history. Keep a separate token for US and CA. This is not a search cursor.

## Actor input object example

```json
{
  "mode": "sample",
  "country": "US",
  "maxItems": 100,
  "maxRequests": 10,
  "remote": false,
  "has_salary": false,
  "window": "all"
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `summary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("thejobsapi/us-canada-jobs-api").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("thejobsapi/us-canada-jobs-api").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 '{}' |
apify call thejobsapi/us-canada-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thejobsapi/us-canada-jobs-api"
        }
    }
}
```

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/BYyPaqH3oA6BfR3nr/builds/GQre3b9jP88030H6Z/openapi.json
