# Hi Jobs (HIJOBS) Scraper (`memo23/hijobs-scraper`) Actor

Scrape hijobs.net — Scotland's Highlands & Islands jobs board — via the official HIJOBS mobile API. Title, employer, salary, location, hours, sector, closing date, apply email + full description. Search by URL or filters, recency filter, 37 fields per row. JSON or CSV out.

- **URL**: https://apify.com/memo23/hijobs-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Jobs, Agents, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.90 / 1,000 results

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/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.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.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/platform/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

## Hi Jobs (HIJOBS) Scraper

**Scrape hijobs.net — Scotland's Highlands & Islands jobs board — through the official HIJOBS mobile JSON API.** The website itself sits behind Cloudflare's interactive challenge, but the HIJOBS iOS app talks to a clean, public JSON API (`api.hijobs.co.uk`) that is **not** Cloudflare-gated and needs **no login**. This actor uses that API directly — so you get structured JSON (not scraped HTML), fast, with richer fields than the website exposes. Newest-first by default, with an optional "posted within N hours" recency filter that early-stops pagination. JSON or CSV out.

#### How it works

![How Hi Jobs Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-hijobs.png)

#### ✨ Why use this scraper?

HIJOBS is *the* jobs board for the Scottish Highlands & Islands — Inverness, Oban, Skye, the Outer Hebrides, Argyll, Moray. ~2,300 live vacancies across care, hospitality, retail, public sector, trades, engineering, and community/third-sector roles.

- 🚀 **Official mobile API, not HTML scraping.** We reverse-engineered the HIJOBS iOS app and found its public JSON API (`api.hijobs.co.uk`). It needs no auth and isn't behind Cloudflare — so every field comes back clean and structured, no brittle HTML parsing, no browser, no proxy required.
- 🧱 **Two endpoints, full coverage.** `/search/results` returns paginated job lists (id, title, ISO posted time, closing date, salary, location, hours, contract, sector, recruiter, logo, badges). `/job/<id>` adds the full HTML description, the **real apply contact (name + email)** for direct employers, the external application URL, and the employer record.
- ⏱️ **Built-in recency filter.** `postedWithinHours: 24` returns only jobs added in the last day — and because results are sorted newest-first, it **early-stops pagination** the moment it passes the cutoff. Cheap, fast daily monitoring.
- 💰 **Proper salary ranges.** `£42,600 to £64,000 per annum`, `£13.45 to £14.45 per hour` → structured `{currency, min, max, unit, raw}`.
- 📧 **Real apply contacts.** Direct-employer jobs expose a genuine `applyEmail` + `contactName`; agency/external jobs expose the `externalApplyUrl`.
- 🧭 **Consistent field names.** Emits the same canonical core columns (in the same order) as every other scraper in this collection — drop the rows straight into your existing mapping.
- 📤 **Clean exports.** One row per vacancy. JSON + CSV exported automatically.

#### 🎯 Use cases

| Team | What they build |
|------|-----------------|
| **Highlands & Islands recruiters** | Daily new-vacancy feeds across Inverness / Argyll / the Isles |
| **Care & hospitality aggregators** | Live regional vacancy boards for the sectors that dominate HIJOBS |
| **Relocation / community sites** | "Jobs in the Highlands" listings auto-populated each morning |
| **Workforce & economic researchers** | Rural Scotland labour-market datasets with salary + sector |
| **Third-sector / public bodies** | Track who's hiring across Highland charities and councils |

#### 📥 Supported inputs

There are **two ways to search**, and **Search-by-URL always wins** when both are filled in:

**1. Search by URL** (`startUrls`) — paste any hijobs.net address. The easiest way: go to hijobs.net, click the filter chips you want (sector, location, employer type, salary, last-N-days…), then copy the address-bar URL straight in. Every chip is honoured.

| URL | Behaviour |
|---|---|
| `https://hijobs.net/search/results?employers=charity-cic&where=Scotland&sort=relevance&since=3` | **Full filtered search** — all chips honoured; `since=3` → last-3-days recency |
| `https://hijobs.net/jobs` | **Newest-first listing** |
| `https://hijobs.net/jobs/<location>` | **Location facet** (e.g. `/jobs/oban`) |
| `https://hijobs.net/job/<id>/<slug>` | **Single job** → `GET /job/<id>` |
| `https://api.hijobs.co.uk/search/results?...` | **Raw API search URL** (params passed through) |

**2. Search by filters** — used only when `startUrls` is empty. Pick from dropdowns instead of building a URL:

| Field | Maps to | Values |
|---|---|---|
| `keywords` | keyword search | free text (e.g. `support worker`) |
| `where` | location | free text (e.g. `Inverness`, `Scotland`) |
| `employerType` | recruiter type | Charity / CIC, Direct Employer, Agency, Recruitment Consultant, Local Government |
| `hours` | working hours | Full Time, Part Time |
| `contractType` | contract | Permanent, Contract, Interim, Graduate, Temporary, Casual, Student Placement, Volunteer |
| `sort` | ordering | Newest first, Date, Highest salary, Relevance |
| `postedWithinHours` | recency | e.g. 24 (last day), 72 (last 3 days) |

Leave everything empty for the newest-first feed.

**Not supported:** authenticated/recruiter features, the applicant flow, employer dashboards.

#### 🔄 How it works

1. **Resolve input** — turn `startUrls` (website or API), or `keywords`/`where`, into API queries (or direct job-IDs).
2. **Paginate** `GET /search/results?sort=added&size=25&pg=N` (newest-first).
3. **Parse each `Jobs[]` item** — id, title, ISO `Added` (posted), `Expires` (closing), rate, location, hours, contract, sector, recruiter, logo, flags (Work-from-home / Immediate-start / Promoted), teaser.
4. **Recency gate** — with `postedWithinHours` set, skip older items and **stop paginating** once a whole page is past the cutoff.
5. **Enrich (optional)** — `GET /job/<id>` for the full HTML description, apply contact (name + email), application URL, employer record.
6. **Normalise + push** — every row goes through the shared canonical normaliser so the column layout matches the rest of the collection.

#### ⚙️ Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | (empty) | **Search by URL — takes priority.** Any hijobs.net listing/search/facet/job URL. When set, the filter fields below are ignored. |
| `keywords` | string | (none) | Keyword search (filter mode). |
| `where` | string | (none) | Location / area (filter mode). |
| `employerType` | string | Any | Recruiter type → `employers` (e.g. `charity-cic`). Filter mode. |
| `hours` | string | Any | `full-time` / `part-time`. Filter mode. |
| `contractType` | string | Any | `permanent`, `contract`, `temporary`, `volunteer`, … Filter mode. |
| `sort` | string | `added` | `added` (newest), `date`, `salary`, `relevance`. |
| `enrichDetail` | boolean | `true` | Fetch each `/job/<id>` for the full description + apply contact. Disable for list-only (faster, fewer calls). |
| `postedWithinHours` | integer | (none) | Only return jobs added in the last N hours (24 = last day, 72 = last 3 days). Empty/0 = all. Early-stops pagination — ideal for daily monitoring. |
| `maxItems` | integer | `1000` | Hard cap on rows pushed (~2,300 live jobs total). |
| `maxPages` | integer | `120` | Safety cap on API pages walked (25 jobs/page). The recency filter usually stops far earlier. |
| `maxConcurrency` | integer | `5` | Parallel `/job/<id>` detail fetches. |
| `proxy` | object | (off) | Optional. The API is open, so a proxy isn't needed — left here for users who want one. |

#### 📊 Output overview

Each scraped vacancy is one **single dataset row** of `type: "job"`. List fields are always present; `description` (full HTML), `applyEmail`/`contactName`, and `externalApplyUrl` come from detail enrichment when `enrichDetail` is on.

#### 📦 Output sample

```json
{
  "type": "job",
  "source": "hijobs.net",
  "jobId": "410005",
  "slug": "principal-overhead-line-ohl-engineer",
  "jobUrl": "https://hijobs.net/job/410005/principal-overhead-line-ohl-engineer",
  "title": "Principal Overhead Line (OHL) Engineer",
  "companyName": "SSE",
  "companyWebsite": null,
  "companyDomain": null,
  "location": "Glasgow, Perth, Aberdeen, Inverness",
  "remote": false,
  "salary": { "currency": "GBP", "min": 58100, "max": 87100, "raw": "£58,100 to £87,100 per annum", "unit": "year" },
  "salaryRaw": "£58,100 to £87,100 per annum",
  "categories": ["Engineering and Technical", "Engineering Management"],
  "employmentTypes": ["Permanent"],
  "contractType": "Permanent",
  "hours": "40 per week",
  "postedDate": "2026-06-05T16:34:18Z",
  "closingDate": "2026-06-18T00:00:00Z",
  "modifiedDate": null,
  "description": "<p><strong>Base Location:</strong> …</p>",
  "descriptionText": "Base Location: …",
  "applyType": "external",
  "applyUrl": "https://hijobs.net/apply/410005/principal-overhead-line-ohl-engineer",
  "applyEmail": null,
  "externalApplyUrl": "https://hijobs.net/apply/external/410005",
  "scrapedAt": "2026-06-05T18:13:00.000Z",
  "sourceProvider": "hijobs",
  "apiUrl": "https://api.hijobs.co.uk/job/410005",
  "recruiterType": "direct-employer",
  "recruiterSlug": "sse",
  "companyLogo": "https://hjcdn.co.uk/images/employers/…",
  "city": null,
  "country": null,
  "postedFriendly": "June, 05, 2026 4:34 PM",
  "descriptionTeaser": "…",
  "reference": "Job Number: 558523",
  "requiresCv": false,
  "numberVacancies": 1,
  "flags": ["Promoted"],
  "contactName": "Human Resources"
}
````

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Identifiers** | `type`, `source`, `sourceProvider` (`hijobs`), `jobId`, `slug`, `jobUrl`, `apiUrl`, `scrapedAt` |
| **Content** | `title`, `description` (HTML, with `enrichDetail`), `descriptionText`, `descriptionTeaser` |
| **Dates** | `postedDate` (ISO, from `Added`), `postedFriendly`, `closingDate` (from `Expires`), `modifiedDate` |
| **Employer** | `companyName`, `recruiterType` (`direct-employer` / agency), `recruiterSlug`, `companyLogo`, `contactName` |
| **Location** | `location`, `city`, `country`, `remote` |
| **Compensation** | `salary.{currency, min, max, unit, raw}`, `salaryRaw` |
| **Classification** | `categories[]` (sector + specialism), `employmentTypes[]`, `contractType`, `hours` |
| **Apply flow** | `applyType` (`external` / `email` / `internal`), `applyUrl`, `applyEmail`, `externalApplyUrl` |
| **HIJOBS-specific** | `flags[]` (Work-from-home / Immediate-start / Promoted / Popular), `reference`, `requiresCv`, `numberVacancies` |

#### ❓ FAQ

**How does this get past Cloudflare?**
It doesn't have to. The HIJOBS *website* is Cloudflare-gated, but the HIJOBS iOS app talks to a separate, public JSON API on `api.hijobs.co.uk` that isn't behind Cloudflare and needs no login. We call that API directly — cleaner and faster than scraping the site. (A Cloudflare-bypass fallback exists for resilience but is rarely needed.)

**Why is `applyEmail` sometimes null?**
Direct-employer jobs publish a real contact email (you'll get `applyEmail` + `contactName`). Agency / "apply on the employer's site" jobs instead publish an `externalApplyUrl`, and `applyType` is `external`. Jobs with neither default to the on-site HIJOBS apply page in `applyUrl`.

**Does `postedWithinHours` really save money?**
Yes. Results are newest-first, so the actor stops paginating as soon as it hits a full page older than your cutoff. A `postedWithinHours: 24` run typically touches 1–3 pages instead of all ~95.

**Why is `closingDate` / full `description` sometimes null?**
The full description + closing date come from the `/job/<id>` detail call. With `enrichDetail: false` those calls are skipped — the list still gives title, employer, posted time, salary, location, hours, sector, and the closing date (`Expires`).

**Can I scrape a specific town or sector?**
Set `where` (e.g. `Inverness`) and/or `keywords`, or paste a `https://hijobs.net/jobs/<location>` URL. The same row shape applies.

**Can I scrape private pages or applicant data?**
No. Only the same public job listings + detail the HIJOBS app itself loads — no authenticated endpoints.

#### 💬 Support

- For issues or feature requests, please use the **Issues** tab on the actor's Apify Console page.
- Author's website: <https://muhamed-didovic.github.io/>
- Email: <muhamed.didovic@gmail.com>

#### 🛠 Additional services

- Custom output shape, additional fields, or one-off datasets: <muhamed.didovic@gmail.com>
- Mobile-API reverse-engineering for other Cloudflare-gated sites in your portfolio (same approach as here): drop an email.
- For API access (no Apify fee, just usage): <muhamed.didovic@gmail.com>

#### 🔎 Explore more scrapers

See other scrapers at [memo23's Apify profile](https://apify.com/memo23) — covering job boards, real estate, social media, and more.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by HIJOBS, HIJOBS Limited, hijobs.net, or any of their subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The scraper accesses only the public job-search and job-detail endpoints of the HIJOBS mobile API — the same data the HIJOBS app loads for any user — with no authenticated endpoints, recruiter-only features, applicant data, or content behind a login. Users are responsible for ensuring their use complies with HIJOBS's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organisation.

***

### SEO Keywords

hijobs scraper, scrape hijobs.net, hijobs api, hijobs mobile api scraper, api.hijobs.co.uk, highlands and islands jobs scraper, scottish highlands jobs api, inverness jobs scraper, oban jobs scraper, skye jobs scraper, argyll jobs api, moray jobs scraper, outer hebrides jobs scraper, rural scotland jobs data, highland care jobs scraper, highland hospitality jobs api, scotland jobs board scraper, mobile app api scraper, reverse engineered job board api, highland third sector jobs api, asva alternative scraper, s1jobs alternative scraper, highlandjobs alternative scraper, scottish job board api

# Actor input Schema

## `startUrls` (type: `array`):

Supported shapes: `https://hijobs.net/search/results?employers=charity-cic&where=Scotland&sort=relevance&since=3` (full filtered search — all the chip filters are honoured), `https://hijobs.net/jobs` (newest listing), `https://hijobs.net/jobs/<location>` (e.g. /jobs/oban), `https://hijobs.net/job/<id>/<slug>` (single job). `since=<days>` is applied as a recency filter. Empty = use the filters below.

## `keywords` (type: `string`):

Free-text keyword search (job title, skill, employer). Example: `support worker`.

## `where` (type: `string`):

Town, region, or area to search within. Examples: `Inverness`, `Scotland`, `Oban`.

## `employerType` (type: `string`):

Filter by who's hiring. e.g. Charity / CIC.

## `hours` (type: `string`):

Full-time or part-time.

## `contractType` (type: `string`):

Contract / employment type.

## `sort` (type: `string`):

How to order results. 'Newest first' is best for daily monitoring + the recency filter.

## `enrichDetail` (type: `boolean`):

When enabled, each job triggers one extra fetch to /job/<id>/<slug> to read the JobPosting JSON-LD — full HTML description, closing date, employment type, and structured location. Disable to skip — the listing already gives title, employer, posted time, location, hours, and salary.

## `postedWithinHours` (type: `integer`):

Only return jobs posted in the last N hours (24 = last day, 72 = last 3 days). Empty or 0 = all. Because results are sorted newest-first, this also early-stops pagination once it passes the cutoff — ideal (and cheap) for daily monitoring runs that only want fresh postings.

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

Hard cap on rows pushed. hijobs.net lists ~2,200 live jobs across ~114 pages.

## `maxPages` (type: `integer`):

Safety cap on listing pages crawled (~20 jobs per page). The recency filter usually stops far earlier.

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

Maximum detail-page fetches in parallel (each is one Scrape.do request).

## `scrapedoKey` (type: `string`):

Optional. Provide your own Scrape.do API token to bill Cloudflare-bypass requests to your account. Leave empty to use the actor's built-in access.

## `minConcurrency` (type: `integer`):

Reserved.

## `maxRequestRetries` (type: `integer`):

Retries before a failed request is given up.

## `proxy` (type: `object`):

Not used — Cloudflare bypass is handled by Scrape.do, not a proxy. Left here for compatibility.

## Actor input object example

```json
{
  "startUrls": [
    "https://hijobs.net/jobs?sort=date"
  ],
  "sort": "added",
  "enrichDetail": true,
  "postedWithinHours": 24,
  "maxItems": 1000,
  "maxPages": 120,
  "maxConcurrency": 3,
  "minConcurrency": 1,
  "maxRequestRetries": 5,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "startUrls": [
        "https://hijobs.net/jobs?sort=date"
    ],
    "postedWithinHours": 24,
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/hijobs-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 = {
    "startUrls": ["https://hijobs.net/jobs?sort=date"],
    "postedWithinHours": 24,
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/hijobs-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 '{
  "startUrls": [
    "https://hijobs.net/jobs?sort=date"
  ],
  "postedWithinHours": 24,
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call memo23/hijobs-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Hi Jobs (HIJOBS) Scraper",
        "description": "Scrape hijobs.net — Scotland's Highlands & Islands jobs board — via the official HIJOBS mobile API. Title, employer, salary, location, hours, sector, closing date, apply email + full description. Search by URL or filters, recency filter, 37 fields per row. JSON or CSV out.",
        "version": "0.0",
        "x-build-id": "bW6xGqktXOjdYOjK6"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~hijobs-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-hijobs-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/memo23~hijobs-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-hijobs-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/memo23~hijobs-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-hijobs-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": {
                    "startUrls": {
                        "title": "hijobs.net URLs",
                        "type": "array",
                        "description": "Supported shapes: `https://hijobs.net/search/results?employers=charity-cic&where=Scotland&sort=relevance&since=3` (full filtered search — all the chip filters are honoured), `https://hijobs.net/jobs` (newest listing), `https://hijobs.net/jobs/<location>` (e.g. /jobs/oban), `https://hijobs.net/job/<id>/<slug>` (single job). `since=<days>` is applied as a recency filter. Empty = use the filters below.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "keywords": {
                        "title": "Keywords",
                        "type": "string",
                        "description": "Free-text keyword search (job title, skill, employer). Example: `support worker`."
                    },
                    "where": {
                        "title": "Location / area",
                        "type": "string",
                        "description": "Town, region, or area to search within. Examples: `Inverness`, `Scotland`, `Oban`."
                    },
                    "employerType": {
                        "title": "Employer type",
                        "enum": [
                            "",
                            "charity-cic",
                            "direct-employer",
                            "agency",
                            "recruitment-consultant",
                            "council"
                        ],
                        "type": "string",
                        "description": "Filter by who's hiring. e.g. Charity / CIC."
                    },
                    "hours": {
                        "title": "Hours",
                        "enum": [
                            "",
                            "full-time",
                            "part-time"
                        ],
                        "type": "string",
                        "description": "Full-time or part-time."
                    },
                    "contractType": {
                        "title": "Contract type",
                        "enum": [
                            "",
                            "permanent",
                            "contract",
                            "interim",
                            "graduate-contract",
                            "temporary",
                            "casual",
                            "student-placement",
                            "volunteer"
                        ],
                        "type": "string",
                        "description": "Contract / employment type."
                    },
                    "sort": {
                        "title": "Sort order",
                        "enum": [
                            "added",
                            "date",
                            "salary",
                            "relevance"
                        ],
                        "type": "string",
                        "description": "How to order results. 'Newest first' is best for daily monitoring + the recency filter.",
                        "default": "added"
                    },
                    "enrichDetail": {
                        "title": "Fetch each detail page for the full description + closing date (recommended)",
                        "type": "boolean",
                        "description": "When enabled, each job triggers one extra fetch to /job/<id>/<slug> to read the JobPosting JSON-LD — full HTML description, closing date, employment type, and structured location. Disable to skip — the listing already gives title, employer, posted time, location, hours, and salary.",
                        "default": true
                    },
                    "postedWithinHours": {
                        "title": "Only jobs posted within the last N hours",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only return jobs posted in the last N hours (24 = last day, 72 = last 3 days). Empty or 0 = all. Because results are sorted newest-first, this also early-stops pagination once it passes the cutoff — ideal (and cheap) for daily monitoring runs that only want fresh postings."
                    },
                    "maxItems": {
                        "title": "Maximum jobs to scrape",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on rows pushed. hijobs.net lists ~2,200 live jobs across ~114 pages.",
                        "default": 1000
                    },
                    "maxPages": {
                        "title": "Maximum listing pages to walk",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Safety cap on listing pages crawled (~20 jobs per page). The recency filter usually stops far earlier.",
                        "default": 120
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum detail-page fetches in parallel (each is one Scrape.do request).",
                        "default": 3
                    },
                    "scrapedoKey": {
                        "title": "Bring-your-own Scrape.do key (optional)",
                        "type": "string",
                        "description": "Optional. Provide your own Scrape.do API token to bill Cloudflare-bypass requests to your account. Leave empty to use the actor's built-in access."
                    },
                    "minConcurrency": {
                        "title": "Min concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Reserved.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max request retries",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Retries before a failed request is given up.",
                        "default": 5
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Not used — Cloudflare bypass is handled by Scrape.do, not a proxy. Left here for compatibility.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
