{
  "openapi": "3.0.1",
  "info": {
    "title": "GulfTalent Job Scraper · Salaries, Emails & Alerts",
    "description": "Search GulfTalent by keyword, category, country or city across all 6 Gulf markets. 33 fields per job: structured salary with exact USD conversion, MENA hiring fields (nationality, gender, Arabic fluency), emails & phones from ads. Incremental runs + Telegram/Slack alerts. No browser.",
    "version": "0.0",
    "x-build-id": "468jgBcYHRU7Lvwgz"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/memo23~gulftalent-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-memo23-gulftalent-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~gulftalent-scraper/runs": {
      "post": {
        "operationId": "runs-sync-memo23-gulftalent-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~gulftalent-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-memo23-gulftalent-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": {
          "query": {
            "title": "🔍 Search keyword(s)",
            "type": "string",
            "description": "Job title or keyword, e.g. `accountant` or `finance manager`. Multiple searches: comma-separate (`accountant, auditor`) or pass a JSON array (`[\"accountant\",\"auditor\"]`). Keyword searches use GulfTalent's title pages; if a keyword has no title page, the actor automatically browses the selected market and keeps only matching jobs."
          },
          "category": {
            "title": "🏷️ Category",
            "enum": [
              "",
              "academic",
              "accounting",
              "admin",
              "architecture",
              "catering",
              "chemical-engineering",
              "civil-engineering",
              "customer-service",
              "design",
              "electronics-engineering",
              "finance-consulting",
              "healthcare",
              "hr",
              "hse",
              "investment",
              "journalism",
              "legal",
              "sales"
            ],
            "type": "string",
            "description": "Browse a GulfTalent category instead of a keyword. Ignored when a search keyword is set.",
            "default": ""
          },
          "country": {
            "title": "🌍 Country",
            "enum": [
              "all",
              "uae",
              "saudi-arabia",
              "qatar",
              "kuwait",
              "bahrain",
              "oman"
            ],
            "type": "string",
            "description": "Which Gulf market to search. `All countries` covers UAE, Saudi Arabia, Qatar, Kuwait, Bahrain and Oman in one run.",
            "default": "all"
          },
          "location": {
            "title": "📍 City",
            "type": "string",
            "description": "City filter, e.g. `Dubai` or `Riyadh`. Multiple: comma-separate or JSON array. Uses GulfTalent's city pages when they exist; otherwise jobs are filtered by their listed location."
          },
          "startUrls": {
            "title": "🔗 GulfTalent listing URLs (optional)",
            "type": "array",
            "description": "Full GulfTalent.com /jobs listing URLs (country, category, city or title pages). Each is paginated automatically until `Maximum items` is reached. Combine freely with the search fields above.",
            "items": {
              "type": "string"
            }
          },
          "includeKeywords": {
            "title": "📝 Must contain keywords",
            "type": "array",
            "description": "Keep only jobs whose title or description contains at least ONE of these keywords (case-insensitive).",
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "🚫 Exclude keywords",
            "type": "array",
            "description": "Drop jobs whose title or description contains ANY of these keywords (case-insensitive).",
            "items": {
              "type": "string"
            }
          },
          "fromDate": {
            "title": "📅 Posted on or after",
            "type": "string",
            "description": "YYYY-MM-DD. Jobs without a readable posted date are dropped while a date filter is active."
          },
          "toDate": {
            "title": "📅 Posted on or before",
            "type": "string",
            "description": "YYYY-MM-DD."
          },
          "maxAgeDays": {
            "title": "⏰ Max age (days)",
            "minimum": 0,
            "type": "integer",
            "description": "Only jobs posted within the last N days (0 = no limit). Pairs well with scheduled runs.",
            "default": 0
          },
          "minSalaryUsd": {
            "title": "💵 Minimum monthly salary (USD)",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only jobs whose disclosed salary is at or above this monthly USD amount (Gulf currencies converted at their USD pegs). Jobs without a disclosed salary are dropped while this filter is active. 0 = off.",
            "default": 0
          },
          "easyApplyOnly": {
            "title": "⚡ Easy Apply only",
            "type": "boolean",
            "description": "Keep only jobs flagged as Easy Apply on the listing.",
            "default": false
          },
          "incrementalMode": {
            "title": "♻️ Incremental mode",
            "type": "boolean",
            "description": "Compare against the previous run's state. By default, already-seen jobs are skipped before their detail page is even fetched (fastest, cheapest). New jobs are emitted with `incrementalStatus: \"NEW\"`.",
            "default": false
          },
          "stateKey": {
            "title": "🔑 State key",
            "type": "string",
            "description": "Optional stable name for the tracked search (e.g. `uae-accountants`). Leave empty to auto-derive from the search inputs, so different searches track independently."
          },
          "detectUpdates": {
            "title": "🔄 Detect updated jobs",
            "type": "boolean",
            "description": "Re-fetch already-seen jobs and compare content — edited postings are emitted as `UPDATED`. Costs a detail fetch per known job, so leave off unless you need edit detection.",
            "default": false
          },
          "emitUnchanged": {
            "title": "♻️ Emit unchanged jobs too",
            "type": "boolean",
            "description": "Also emit rows for jobs that haven't changed (`UNCHANGED`). Implies re-fetching known jobs.",
            "default": false
          },
          "emitExpired": {
            "title": "⚰️ Emit expired jobs",
            "type": "boolean",
            "description": "Emit a small `EXPIRED` record for jobs from previous runs that are no longer listed. Only detected when the run sweeps its full search without hitting `Maximum items`.",
            "default": false
          },
          "telegramToken": {
            "title": "🔔 Telegram bot token",
            "type": "string",
            "description": "Your bot's token from @BotFather. Requires Telegram chat ID below."
          },
          "telegramChatId": {
            "title": "💬 Telegram chat ID",
            "type": "string",
            "description": "Chat or channel ID (e.g. `-100123456789`). The bot must be a member of the chat."
          },
          "slackWebhookUrl": {
            "title": "💼 Slack webhook URL",
            "type": "string",
            "description": "Slack incoming-webhook URL (api.slack.com/messaging/webhooks)."
          },
          "discordWebhookUrl": {
            "title": "🎮 Discord webhook URL",
            "type": "string",
            "description": "Discord webhook URL (Server Settings → Integrations → Webhooks)."
          },
          "webhookUrl": {
            "title": "🪝 Generic webhook URL",
            "type": "string",
            "description": "Receives a JSON POST with `{ metadata, items }` after the run — plug into n8n / Make / Zapier / your backend."
          },
          "webhookHeaders": {
            "title": "📋 Webhook headers",
            "type": "object",
            "description": "Optional custom headers for the generic webhook, e.g. `{\"Authorization\": \"Bearer …\"}`."
          },
          "notificationLimit": {
            "title": "📊 Max jobs per message",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "How many jobs to list in each chat message (1–20). The full data is always in the dataset.",
            "default": 10
          },
          "notifyOnlyNew": {
            "title": "🆕 Notify only new/updated",
            "type": "boolean",
            "description": "With Incremental mode on, notify only about NEW and UPDATED jobs. No effect otherwise.",
            "default": true
          },
          "compact": {
            "title": "📦 Compact output",
            "type": "boolean",
            "description": "Core fields only (title, company, location, salary, URL, dates) — lean payloads for AI agents, MCP and LLM pipelines.",
            "default": false
          },
          "descriptionMaxLength": {
            "title": "✂️ Description max length",
            "minimum": 0,
            "type": "integer",
            "description": "Truncate the description to this many characters (0 = full text). Handy for controlling LLM token cost.",
            "default": 0
          },
          "flatten": {
            "title": "Flatten nested fields for CSV-friendly output",
            "type": "boolean",
            "description": "When enabled (default), nested objects (e.g. `details`) are flattened into CSV-friendly columns. Disable to keep the full nested JSON.",
            "default": true
          },
          "enrichEmails": {
            "title": "📧 Enrich with employer contact emails (billed per email)",
            "type": "boolean",
            "description": "Discovers each employer's website and reads its contact/about pages to add verified `contactEmail` + `contactWebsite` columns — stronger than the emails already extracted free from ad text. Best-effort, billed per email found; never charged for misses.",
            "default": false
          },
          "maxItems": {
            "title": "💯 Maximum items to scrape",
            "minimum": 1,
            "type": "integer",
            "description": "Hard cap on the number of jobs collected — the primary cost control. Each listing page returns ~25 jobs and paginates automatically; every job includes its detail page.",
            "default": 1000
          },
          "maxPages": {
            "title": "📄 Max pages per source",
            "minimum": 0,
            "type": "integer",
            "description": "Safety bound on listing pages scanned per search source (~25 jobs/page). 0 = auto: unlimited for direct listings, 40 pages when a keyword/city has no dedicated page and the actor browse-scans with a filter. `Maximum items` remains the primary cost control.",
            "default": 0
          },
          "maxConcurrency": {
            "title": "Max concurrency",
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of detail pages fetched in parallel. 6-12 is the sweet spot.",
            "default": 8
          },
          "maxRequestRetries": {
            "title": "Max request retries",
            "minimum": 0,
            "type": "integer",
            "description": "Number of retries before a failed request is given up.",
            "default": 5
          },
          "proxy": {
            "title": "Proxy configuration (optional override)",
            "type": "object",
            "description": "Leave empty. On a paid Apify plan the actor routes traffic through its own residential proxy at no extra cost to you. On the free plan runs use your Apify Proxy, and any request GulfTalent refuses is retried through the actor's residential proxy. Only set this if you want to use your own proxies."
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}