{
  "openapi": "3.0.1",
  "info": {
    "title": "Remote Jobs Aggregator & Scraper: Remote Job Boards, One Feed",
    "description": "Remote jobs aggregator and remote jobs scraper, no API key: RemoteOK, WeWorkRemotely, Working Nomads, Remotive, Jobicy, Himalayas, The Muse, HN Who is hiring in one deduplicated feed. New remote jobs alerts on a schedule, remote job boards scraper with salaries, JSON/CSV, Slack digests. $2/1k.",
    "version": "0.1",
    "x-build-id": "VtcsLIJYhbR4YXoUR"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/flash_scraper~remote-job-aggregator/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-flash_scraper-remote-job-aggregator",
        "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/flash_scraper~remote-job-aggregator/runs": {
      "post": {
        "operationId": "runs-sync-flash_scraper-remote-job-aggregator",
        "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/flash_scraper~remote-job-aggregator/run-sync": {
      "post": {
        "operationId": "run-sync-flash_scraper-remote-job-aggregator",
        "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": {
          "searchTerms": {
            "title": "Search terms",
            "type": "array",
            "description": "Keywords, case-insensitive. This form starts in WIDE mode (Match descriptions too is ticked): a term matches the job title, its tags or the first 500 characters of its description. Untick it for title-only precision. A job matches if ANY term matches (OR). Multi-word terms need every word ('python developer' requires both) — prefer short terms like 'python'. Empty = every job. Capped at 10 terms per run - extras beyond the first 10 are ignored, and the run's status message says so.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "matchDescriptions": {
            "title": "Match descriptions too",
            "type": "boolean",
            "description": "ON (this form starts wide): searchTerms match the job title, its tags and the first 500 characters of its description — exactly what ships in `tags` and `description_snippet`, so you can always see why a row matched. Measured 2026-08-15 with ['python']: 194 rows wide vs 28 title-only. OFF = title-only, the precision opt-out: every hit visibly carries your keyword in the title, but a Python job titled 'Backend Engineer' is skipped. API and scheduled inputs that omit this field stay title-only (the stored default is false), so existing runs and their onlyNewJobs memories do not change. DevITjobs publishes no descriptions, so there wide mode adds its technology tags only.",
            "default": false
          },
          "boards": {
            "title": "Boards",
            "type": "array",
            "description": "Which boards to sweep. Default: the ten core boards. One more is opt-in and joins only when you add it here: Arbeitnow (Germany-centric, remote rows only, a handful of rows per run). Adding a board to a scheduled onlyNewJobs search starts a fresh baseline for that search. Results are deduplicated across boards, so selecting more boards never means paying twice for the same role.",
            "items": {
              "type": "string",
              "enum": [
                "remoteok",
                "weworkremotely",
                "working_nomads",
                "devitjobs_us",
                "devitjobs_uk",
                "muse",
                "remotive",
                "jobicy",
                "himalayas",
                "hn_hiring",
                "arbeitnow"
              ],
              "enumTitles": [
                "Remote OK",
                "We Work Remotely",
                "Working Nomads",
                "DevITjobs US (remote rows only)",
                "DevITjobs UK (remote rows only)",
                "The Muse (remote filter)",
                "Remotive",
                "Jobicy",
                "Himalayas",
                "Hacker News \"Who is hiring?\" (remote posts only)",
                "Arbeitnow (opt-in — Germany-centric, remote rows only)"
              ]
            },
            "default": [
              "remoteok",
              "weworkremotely",
              "working_nomads",
              "devitjobs_us",
              "devitjobs_uk",
              "muse",
              "remotive",
              "jobicy",
              "himalayas",
              "hn_hiring"
            ]
          },
          "maxItems": {
            "title": "Max jobs",
            "minimum": 1,
            "maximum": 4000,
            "type": "integer",
            "description": "Maximum number of deduplicated jobs to return across all boards. Sources are paginated to their real limits (The Muse ~1,980 rows, Himalayas ~2,000, Jobicy 200 per call), so large orders are reachable - but depth is source-limited, not unlimited.",
            "default": 100
          },
          "includeDescription": {
            "title": "Include full descriptions",
            "type": "boolean",
            "description": "ON: every row's `description` column carries the job's full HTML-stripped description text (rows get heavy). OFF (default): `description` carries the first 2,000 characters (visibly cut with …) alongside the always-on 500-character `description_snippet`. Boards that publish no description (DevITjobs) deliver null either way.",
            "default": false
          },
          "onlyNewJobs": {
            "title": "Only new jobs",
            "type": "boolean",
            "description": "Deliver only postings this exact search (same searchTerms + boards + filters) has never delivered before. The first run is the baseline — it delivers everything (up to maxItems; the matching postings it leaves behind stay eligible: the next runs read the boards back to the oldest one, at most 30 days, and deliver exactly those postings alongside new ones — never the same row twice within the 90-day memory, and never a merely newly-reachable older posting) and says so; every later run returns only new postings. A run where nothing is new delivers 0 rows, reports 'Nothing new since <last run>' and bills nothing. Memory lives in a named key-value store ('remote-job-monitor') in YOUR Apify account, one record per search, entries pruned after 90 days.",
            "default": false
          },
          "postedWithinDays": {
            "title": "Posted within (days)",
            "minimum": 0,
            "maximum": 365,
            "type": "integer",
            "description": "Drop postings whose posted_at is older than this many days. 0 (default) = off. The boards publish posted_at on ~100% of rows; a row with no date is kept unless strictFilters is on.",
            "default": 0
          },
          "salaryMinAnnual": {
            "title": "Minimum annual salary",
            "minimum": 0,
            "type": "integer",
            "description": "Drop postings whose annualized salary_max (salary_min when no max is published) is below this number. 0 (default) = off. Hourly / weekly / monthly figures are already annualized upstream. The floor is CURRENCY-AGNOSTIC: the number is compared as the board published it (a 60,000 EUR row passes a 50,000 floor; use salary_currency downstream to tell them apart). Rows with no salary (~65% of a default run) are kept unless strictFilters is on.",
            "default": 0
          },
          "countries": {
            "title": "Countries",
            "type": "array",
            "description": "Keep postings whose location is open to ANY of these. ISO-2 codes or names: US / USA / United States / America, UK / GB / United Kingdom / England / Britain, EU / Europe / European Union, Canada, Germany, France, Spain, Netherlands, Poland, Portugal, India, Australia, Brazil, Mexico, plus the regions LATAM / Latin America, APAC, EMEA and Americas. A region matches its member countries both ways ('Europe' rows match a Germany filter and vice versa). Locations that are empty or say worldwide / anywhere / global / remote match any country. A location the actor cannot read (a bare city, as RemoteOK publishes) is kept unless strictFilters is on. Empty (default) = off.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "seniority": {
            "title": "Seniority",
            "type": "array",
            "description": "Keep postings whose derived `seniority` column is one of these. Derived from the board's own level field where it publishes one (Jobicy, Himalayas, The Muse, DevITjobs) and from title keywords otherwise ('Senior', 'Lead', 'Staff', 'Principal', 'Head of'…); a row whose seniority is unknown is kept unless strictFilters is on. Empty (default) = off.",
            "items": {
              "type": "string",
              "enum": [
                "entry",
                "junior",
                "mid",
                "senior",
                "lead",
                "staff",
                "principal",
                "manager",
                "director"
              ],
              "enumTitles": [
                "Entry level / intern / graduate",
                "Junior",
                "Mid level",
                "Senior",
                "Lead",
                "Staff",
                "Principal",
                "Manager",
                "Director (also VP / Head of / C-level)"
              ]
            },
            "default": []
          },
          "excludeKeywords": {
            "title": "Exclude keywords",
            "type": "array",
            "description": "Drop a posting when ANY of these terms appears in its title — and, when 'Match descriptions too' is on, in its tags or the first 500 characters of its description (the same fields searchTerms reads, so an exclusion is always visible in the delivered row). Case-insensitive substring; a term of up to 4 letters must stand as a whole word ('go' does not exclude 'Django'); a multi-word term is one phrase ('team lead'). Runs before the cap and the charge — an excluded row is never billed — and the status message counts what it removed. Empty (default) = off. Setting it on an onlyNewJobs search starts a fresh baseline for that search.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "strictFilters": {
            "title": "Strict filters",
            "type": "boolean",
            "description": "OFF (default): a row missing the data a filter needs — no posted date, no salary, an unreadable location, unknown seniority — is KEPT, and the status message says how many were kept that way. ON: such rows are dropped as well. Does nothing unless at least one filter above is set.",
            "default": false
          },
          "webhookUrl": {
            "title": "Alert webhook URL (Slack, Discord, n8n, Make, Zapier…)",
            "type": "string",
            "description": "Optional. When at least one row is delivered, the run POSTs a digest to this URL: a Slack incoming webhook gets a text message, a Discord webhook gets a message, any other URL (n8n / Make / Zapier catch hook, your own endpoint) gets JSON with the counts, console links and the first 20 rows. Quiet runs send nothing. Pair it with onlyNewJobs on a schedule and this actor becomes an alert service on its own. Delivery is best-effort: a webhook failure is reported in the status message and never fails the run."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}