# Middle East Jobs API (`aspen-technology-labs-inc/middle-east-jobs-api`) Actor

Find job postings across Middle Eastern markets by role, location query, company, category, salary, posting age, employment type, remote status, and seniority.

- **URL**: https://apify.com/aspen-technology-labs-inc/middle-east-jobs-api.md
- **Developed by:** [Aspen Technology Labs, Inc.](https://apify.com/aspen-technology-labs-inc) (community)
- **Categories:** Developer tools, Jobs, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 job records

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

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

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Middle East Jobs API - JobsIndex by Aspen Tech Labs

Access fresh job postings across the Middle East through the JobsIndex API, built by Aspen Tech Labs. Job data is sourced directly from company career pages and ATS platforms, not scraped from job boards or aggregators. Coverage spans the United Arab Emirates, Saudi Arabia, and other countries throughout the region, with coverage depth varying by country.

Use this Actor when you need job posting data centered on the Middle East rather than the full global JobsIndex feed. Search by keyword, title, company, category, salary, seniority, employment type, work arrangement, posting age, and more across the default region, with the option to add other locations through `where`.

### Regional Coverage

The current regional dataset contains **~89,000 active jobs from 85,000+ employer career sites across 13 countries**.

- United Arab Emirates (UAE): ~29,000 jobs
- Saudi Arabia: ~15,000 jobs
- Egypt: ~10,000 jobs
- Qatar: ~8,000 jobs
- Turkey: ~5,000 jobs

### Need More or Something Different?

If this Actor is working well for you, we'd love a review. For more data, custom feeds, feedback, or any questions, reach out via our [website](https://jobsindex.com/) or by [email](mailto:inquiry+apify@aspentechlabs.com). You can also explore [JobMarketPulse](https://jobmarketpulse.com/), our labor and job market intelligence platform.

### Built-In Regional Preset

The intended regional preset covers the United Arab Emirates, Saudi Arabia, Qatar, Israel, Turkey, Egypt, Jordan, Kuwait, Oman, Bahrain, Lebanon, Iraq, and Cyprus.

Direct structured location inputs are not accepted because they could replace the default country scope. Use `where` to add locations to the default region.

### Quick Start

```json
{
  "what": "hotel OR hospitality OR restaurant",
  "size": 5
}
```

### Input Parameters

| Parameter | Description | Example |
|---|---|---|
| `salary` | Salary amount or range filter. | `20h-30h` |
| `what` | Job search query with keywords, boolean logic, exact phrases, or field targeting. | `hotel OR hospitality OR restaurant` |
| `where` | Additional field-targeted location query combined with the default regional preset using `OR`. | `@(city) (Dubai)` |
| `title` | Job title filter. | `Hotel Manager` |
| `company_name` | Employer name filter. | `Hospitality Group` |
| `company_domain` | Employer website domain. | `example-hospitality.com` |
| `category` | Job category. | `Hotels` |
| `sub_category` | More specific job function or role. | `Housekeeper` |
| `industry` | Employer industry. | `Hotels and Restaurants` |
| `posted` | Relative posting age or ISO date. | `1w` |
| `employment_type` | Employment type. | `Full-Time` |
| `remote` | Work arrangement: `remote`, `on-site`, or `hybrid`. | `hybrid` |
| `seniority` | Seniority level. | `Senior` |
| `page` | Page number, starting from 0. | `0` |
| `size` | Results per page, from 1 to 100. | `5` |

### Advanced Filters

`what` supports plain text, boolean logic, exact phrases, and field-targeted search.

```text
what = hotel OR hospitality OR restaurant
what = @(title,description) (housekeeper OR bartender)
```

#### Structured Filter Precedence

When `what` is provided together with structured job filters such as `title`, `company_name`, `company_domain`, `category`, `sub_category`, `industry`, `posted`, `salary`, `employment_type`, `remote`, or `seniority`, those structured filters take priority and can override or narrow the keyword query. Use `what` when the corresponding structured fields are not set.

`where` adds locations to the internal 13-country regional preset using `OR`. The default regional results remain included. Use field-targeted location syntax:

```text
where = @(city) (Dubai)
where = @(region) (Abu Dhabi)
```

Do not send separate `country`, `region`, `city`, `postal_code`, `metro_area`, `county`, or `sub_city` fields. The Actor removes those fields to protect the default country scope. User-provided `where` values are always appended with `OR`; they can add locations but cannot remove or replace the default Middle East preset.

Example with an additional city query:

```json
{
  "what": "software engineer",
  "where": "@(city) (Dubai)",
  "size": 5
}
```

### Salary Filter Format

Use `NUMBER[UNIT]` or `NUMBER[UNIT]-NUMBER[UNIT]`. Supported units are `h`, `d`, `w`, `m`, and `y`.

### Limits and Pagination

This Actor uses the JobsIndex jobs API. Results are paginated with `page` and `size`.

| Parameter | Default | Min | Max |
|---|---:|---:|---:|
| `page` | 0 | 0 | Depends on `size` and the item cap |
| `size` | 5 | 1 | 100 |

Invalid `page` or `size` values can return `400 Invalid page or size parameters`.

#### Item Caps

| Query shape | Max items | Effective max `size` | Over-size behavior |
|---|---:|---:|---|
| No company filter | 1000 | 100 | Validation error; not silently capped |
| Company filter plus another keyword or filter | 20 | 20 | Silent cap with capping metadata |
| Company filter only | 5 | 5 | Silent cap with capping metadata |

A company filter means `company_name`, `company_domain`, or a company field referenced inside `what`. Another keyword or filter means anything in `what` other than `company_*`, or a value in fields such as `title`, `category`, `sub_category`, `industry`, `posted`, `salary`, `employment_type`, `remote`, or `seniority`.

This Actor always applies an internal regional `where` preset, so company-filtered requests normally use the 20-item `company|keywords` cap.

When a company-filtered request asks for `size` greater than the effective cap, the API returns up to the capped number of results instead of erroring. Response metadata includes `size_requested` and `size_capped_by`: `"company"` for the 5-item cap or `"company|keywords"` for the 20-item cap. These fields are absent from uncapped responses.

No-company-filter requests are not silently capped. Requests beyond the 1000-item retrieval window can return `400 Item limit reached. Maximum of 1000 items can be retrieved`.

#### Free-Text Query Limits

The user-facing `what` and `where` queries are subject to JobsIndex free-text limits. The effective upstream `where` expression includes the default regional preset and the `OR` wrapper.

| Limit | Value | Error behavior |
|---|---:|---|
| User-entered `what` length | 700 characters | `400 parameter exceeds 700 characters` |
| User-entered `where` length | 511 characters | Input validation error or `400 parameter exceeds 700 characters` for the combined query |
| Effective upstream `where` length | 700 characters, including the regional preset | `400 parameter exceeds 700 characters` |
| Excessive MATCH operators | Backend safety limit | `400 Too many MATCH operators` |
| Unsafe SQL-like keywords | blocked | `400 Unsafe MATCH expression` |

#### Field Validation

Invalid filter values can return `400 Invalid value for parameter: <name>`. Common validation examples include malformed company domains, invalid dates or relative `posted` values, invalid salary format, unsupported location formats, or overly long field values.

### Output

Each run stores job records in the default Apify dataset. The dataset schema includes an `Overview` table for the most useful fields and a `Raw data (all fields)` table for the complete JobsIndex record.

Example dataset item:

```json
{
  "id": "example-middle-east-job-id",
  "title": "Housekeeper",
  "title_raw": "Hotel Housekeeping Attendant",
  "company_name": "Example Hospitality Group",
  "company_domain": "example-hospitality.com",
  "company_type": "company",
  "category": "Hotels",
  "sub_category": "Housekeeper",
  "industry": "Hotels and Restaurants",
  "country": "United Arab Emirates",
  "region": "Dubayy",
  "city": "Dubai",
  "salary_value": "18000.00-25000.00",
  "salary_currency": "AED",
  "salary_unit": "MONTH",
  "employment_type": "Full-Time",
  "remote": "on-site",
  "posted": "2026-08-01",
  "url_source": "https://example-hospitality.com/careers/housekeeper",
  "url_apply": "https://example-hospitality.com/careers/housekeeper/apply"
}
```

Field availability depends on the source job posting.

# Actor input Schema

## `salary` (type: `string`):

Salary amount/range filter. Format: 1-9 digits followed by y, m, w, d, or h; optional range A-B. Examples: 20h-30h, 35h, 20h-200000y.

## `what` (type: `string`):

Main job search query. Supports keywords, exact phrases, boolean logic (AND, OR, NOT or &, |, !), and field targeting. Maximum 700 characters. Examples: hotel OR hospitality OR restaurant, "hotel manager", @(title) (housekeeper).

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

Optional location query added to the Actor's built-in 13-country Middle East preset using OR. The default Middle East results always remain included. Use field-targeted syntax to add any location, for example @(country) (Iran), @(country) (Morocco), or @(city) (Casablanca). The user-entered value is limited to 511 characters because the Actor adds the regional preset to the effective query.

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

Job title filter. Maximum 200 characters.

## `company_name` (type: `string`):

Company name filter. Company filters reduce the retrievable item cap; see README.

## `company_domain` (type: `string`):

Company website domain in valid DNS form, for example ibm.com. Company filters reduce the retrievable item cap; see README.

## `category` (type: `string`):

Job category. Maximum 100 characters.

## `sub_category` (type: `string`):

More specific job function or role.

## `industry` (type: `string`):

Company industry. Maximum 100 characters. Example: Food Products or Hotels and Restaurants.

## `posted` (type: `string`):

Relative posting age, such as 1h, 1d, 1w, 1m, or an ISO date: YYYY, YYYY-MM, YYYY-MM-DD.

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

Employment type, for example Full-Time. Comma-separated values are supported; each value can be up to 31 characters.

## `remote` (type: `string`):

Work arrangement filter. Supported values: remote, on-site, hybrid.

## `seniority` (type: `string`):

Seniority level, for example Junior, Middle, Senior. Comma-separated values are supported; each value can be up to 31 characters.

## `page` (type: `integer`):

Page number. Starts from 0. Pagination is capped by query shape: no company filter up to 1000 items, company filter with another filter up to 20 items, company filter only up to 5 items.

## `size` (type: `integer`):

Number of results per page. Default 5, min 1, max 100. Effective maximum can be lower for company-filtered queries; see README.

## Actor input object example

```json
{
  "what": "",
  "where": "",
  "title": "",
  "company_name": "",
  "company_domain": "",
  "category": "",
  "sub_category": "",
  "industry": "",
  "posted": "",
  "employment_type": "",
  "remote": "",
  "seniority": "",
  "page": 0,
  "size": 5
}
```

# Actor output Schema

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

No description

## `meta` (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("aspen-technology-labs-inc/middle-east-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("aspen-technology-labs-inc/middle-east-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 aspen-technology-labs-inc/middle-east-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,aspen-technology-labs-inc/middle-east-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/YXSuBdp31A1R0fyd2/builds/KEasNKNH1QxFP29lZ/openapi.json
