{
  "openapi": "3.0.1",
  "info": {
    "title": "Upwork Job Alerts: New Jobs Monitor & Filters",
    "description": "Get alerts for new Upwork jobs: schedule it every few minutes or hours and each run returns only the job posts published since the last run, filtered by keyword, budget, hourly rate, experience level, skills and category. Send them to email, Slack or Google Sheets with Apify integrations.",
    "version": "0.0",
    "x-build-id": "CnCDJJxPgr6scj2OH"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/nice_dev~upwork-job-alerts/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-nice_dev-upwork-job-alerts",
        "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/nice_dev~upwork-job-alerts/runs": {
      "post": {
        "operationId": "runs-sync-nice_dev-upwork-job-alerts",
        "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/nice_dev~upwork-job-alerts/run-sync": {
      "post": {
        "operationId": "run-sync-nice_dev-upwork-job-alerts",
        "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": "Start URLs",
            "maxItems": 100,
            "type": "array",
            "description": "Upwork search URLs copied from the site (`https://www.upwork.com/nx/search/jobs/?q=python&sort=recency`). Only the keyword, the sort and the page are read from the URL: filters ticked on Upwork's page are not, so set them below — they apply to these URLs too. When this list is not empty, **Search keyword** below is ignored; the caps and monitoring below still apply. Max 100 URLs.",
            "default": [],
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "query": {
            "title": "Search keyword",
            "maxLength": 500,
            "type": "string",
            "description": "Free-text search, exactly as typed on Upwork: the keywords you want alerts for. Upwork's own search syntax works: `title:(web scraping)`, `python AND NOT wordpress`, `\"exact phrase\"`. Empty = every open job post (about 108 000)."
          },
          "searchQueries": {
            "title": "More search keywords",
            "maxItems": 100,
            "uniqueItems": true,
            "type": "array",
            "description": "Several keywords in one run: one search per keyword. Added to **Search keyword**. A job post found by several searches is saved once. Max 100.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "maxItems": {
            "title": "Max job posts",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Maximum number of job posts to save in one run (after deduplication and filters). 0 = no limit. For an alert, keep it above the number of new job posts that appear between two runs: with Only new job posts on, the newest ones are returned first and the run stops at this number.",
            "default": 100
          },
          "maxItemsPerQuery": {
            "title": "Max job posts per search",
            "minimum": 0,
            "maximum": 5050,
            "type": "integer",
            "description": "Cap for EACH search, so the first keyword cannot use up the whole **Max job posts** budget. 0 = no per-search cap. Upwork itself never returns more than 5 050 job posts for one search, whatever you set here.",
            "default": 0
          },
          "sortBy": {
            "title": "Sort by",
            "enum": [
              "recency",
              "relevance",
              "client_total_charge"
            ],
            "type": "string",
            "description": "Upwork's own sort order. `recency` (newest first) is the only one that makes **Only new job posts** and early stopping work — keep it for monitoring.",
            "default": "recency"
          },
          "onlyNew": {
            "title": "Only new job posts",
            "type": "boolean",
            "description": "Return only the job posts never delivered by a previous run of the same search (same **Monitoring key**). The first run of a search has nothing to compare with: it returns the newest job posts, up to **Max job posts**. Untick it for a plain search that returns every match, every time. A run that finds nothing new saves 0 items and pays only the run-start fee.",
            "default": true
          },
          "stateKey": {
            "title": "Monitoring key",
            "pattern": "^[a-zA-Z0-9_-]*$",
            "maxLength": 60,
            "type": "string",
            "description": "Name of the memory used by **Only new job posts**. Leave empty: every search (its keywords or Start URLs) then gets its own memory, so two Tasks never hide each other's job posts, and changing the keywords starts a new alert. Type a name to keep one memory when you change the keywords or the filters of an alert, or to share it between several runs. Letters, digits, `_` and `-` only."
          },
          "resetState": {
            "title": "Reset monitoring memory",
            "type": "boolean",
            "description": "Forget everything remembered under this **Monitoring key** (or under this search, when the key is empty) before starting, so this run returns every match again.",
            "default": false
          },
          "jobType": {
            "title": "Job type",
            "enum": [
              "",
              "hourly",
              "fixed"
            ],
            "type": "string",
            "description": "Hourly or fixed-price contracts. Empty = both.",
            "default": ""
          },
          "experienceLevel": {
            "title": "Experience level",
            "uniqueItems": true,
            "type": "array",
            "description": "Client's required level. Several can be ticked.",
            "items": {
              "type": "string",
              "enum": [
                "Entry level",
                "Intermediate",
                "Expert"
              ],
              "enumTitles": [
                "Entry level",
                "Intermediate",
                "Expert"
              ]
            },
            "default": []
          },
          "projectDuration": {
            "title": "Project duration",
            "uniqueItems": true,
            "type": "array",
            "description": "How long the client expects the work to last. Checked on every job post, fixed-price ones included.",
            "items": {
              "type": "string",
              "enum": [
                "Less than one month",
                "1 to 3 months",
                "3 to 6 months",
                "More than 6 months"
              ],
              "enumTitles": [
                "Less than one month",
                "1 to 3 months",
                "3 to 6 months",
                "More than 6 months"
              ]
            },
            "default": []
          },
          "workload": {
            "title": "Hours per week",
            "uniqueItems": true,
            "type": "array",
            "description": "Workload the client asks for. Hourly posts only: fixed-price posts have no hours per week, so they drop out unless a fixed budget is set too.",
            "items": {
              "type": "string",
              "enum": [
                "Less than 30 hrs/week",
                "30+ hrs/week",
                "As needed"
              ],
              "enumTitles": [
                "Less than 30 hrs/week",
                "30+ hrs/week",
                "As needed"
              ]
            },
            "default": []
          },
          "contractToHire": {
            "title": "Contract-to-hire only",
            "type": "boolean",
            "description": "Only job posts the client flagged as leading to a long-term contract.",
            "default": false
          },
          "minFixedBudget": {
            "title": "Min fixed budget (USD)",
            "minimum": 0,
            "maximum": 1000000,
            "type": "integer",
            "description": "Only fixed-price job posts with a budget at or above this. Hourly posts drop out, unless an hourly rate or hours per week is set too: then you get both kinds, each matching its own filter."
          },
          "maxFixedBudget": {
            "title": "Max fixed budget (USD)",
            "minimum": 0,
            "maximum": 1000000,
            "type": "integer",
            "description": "Upper bound of the fixed budget. Can be used alone."
          },
          "minHourlyRate": {
            "title": "Min hourly rate (USD)",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Only hourly job posts whose rate range reaches this. Fixed-price posts drop out, unless a fixed budget is set too: then you get both kinds, each matching its own filter."
          },
          "maxHourlyRate": {
            "title": "Max hourly rate (USD)",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Upper bound of the hourly rate. Can be used alone."
          },
          "categories": {
            "title": "Categories",
            "maxItems": 20,
            "uniqueItems": true,
            "type": "array",
            "description": "Upwork category names as shown on the site, e.g. `Web, Mobile & Software Dev`, `Design & Creative`, `Sales & Marketing`. The list of categories is read from Upwork at the start of the run, so it is never out of date. An unknown name stops the run with the list of valid ones.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "subcategories": {
            "title": "Subcategories",
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "Upwork subcategory names, e.g. `Web Development`, `Data Extraction`. More precise than **Categories**; both can be used together.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "skills": {
            "title": "Skills",
            "maxItems": 10,
            "uniqueItems": true,
            "type": "array",
            "description": "Skills the job post asks for, as Upwork names them, e.g. `Python`, `Web Scraping`, `Graphic Design` (case ignored). Several skills = the job post must ask for ALL of them. Each name is looked up on Upwork at the start of the run; an unknown name stops the run with the closest names Upwork knows.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "clientHires": {
            "title": "Client hires",
            "uniqueItems": true,
            "type": "array",
            "description": "How many freelancers the client has hired before.",
            "items": {
              "type": "string",
              "enum": [
                "No hires",
                "1 to 9 hires",
                "10+ hires"
              ],
              "enumTitles": [
                "No hires",
                "1 to 9 hires",
                "10+ hires"
              ]
            },
            "default": []
          },
          "clientLocations": {
            "title": "Client locations",
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "Country names as Upwork writes them, e.g. `United States`, `United Kingdom`, `Canada`. Several countries = job posts from any of them.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "clientTimezones": {
            "title": "Client time zones",
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "The client's time zone, as Upwork names it, e.g. `Europe/Paris`, `America/New_York`, `Asia/Calcutta`. Several zones = job posts from any of them. A zone with no open job post right now is kept and said in the log.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "postedAfter": {
            "title": "Posted after",
            "maxLength": 40,
            "type": "string",
            "description": "Only job posts published on or after this date (days are UTC): `2026-09-01`, or a period before now such as `7 days`, `2 weeks`, `1 month` (API: `2 hours` and full ISO date-times work too). With **Sort by: Newest first**, the run stops after 5 hours of older posts (Upwork ranks a few posts up to 3 hours before it publishes them), so a short window costs very little."
          },
          "postedBefore": {
            "title": "Posted before",
            "maxLength": 40,
            "type": "string",
            "description": "Only job posts published on or before this date (days are UTC; the whole day is included), or older than a period such as `30 days`. Same formats as **Posted after**. Upwork shows only the 5 050 newest posts of a search (on all of Upwork, about the last 31 hours): to reach older ones, narrow the search with a keyword or a category."
          },
          "includeKeywords": {
            "title": "Must contain",
            "maxItems": 100,
            "uniqueItems": true,
            "type": "array",
            "description": "Keep only job posts whose title, description or skills contain at least one of these words. Case and accents are ignored. Runs on our side, after Upwork's own search.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "Must not contain",
            "maxItems": 100,
            "uniqueItems": true,
            "type": "array",
            "description": "Drop job posts whose title, description or skills contain any of these words, e.g. `wordpress`, `unpaid`. Case and accents are ignored.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "maxDescriptionLength": {
            "title": "Max description length",
            "minimum": 0,
            "maximum": 32000,
            "type": "integer",
            "description": "Cut each description to this many characters (never inside an emoji). 0 = keep the full text, which is what Upwork returns.",
            "default": 0
          },
          "includeClientDetails": {
            "title": "Include client details",
            "type": "boolean",
            "description": "Adds 24 client columns (clientTotalSpent, clientHires, clientRating, clientCountry, applicantsCount…) and `clientDetailsRead`. Each job post delivered WITH its client's details is charged the **Client details** event on top of the job post; a job post whose page gives no client (private or closed job) goes out without them and is not charged for it. About 3 seconds per job post.",
            "default": false
          },
          "proxyConfiguration": {
            "title": "Proxy configuration (included proxy: paying users only)",
            "type": "object",
            "description": "Proxy, included in the price. Keep the default setting: the Actor picks the IP addresses Upwork accepts. The Apify residential proxy is refused, because it would cost you money this Actor does not need. On the Apify free plan the included proxy is not available: add your own proxy URLs, or the run stops at once with a message.",
            "default": {
              "useApifyProxy": true
            }
          },
          "minRequestIntervalMs": {
            "title": "Minimum delay between requests",
            "minimum": 0,
            "maximum": 60000,
            "type": "integer",
            "description": "Milliseconds waited between two requests to Upwork. 500 ms is the measured safe pace (no refusal over 120 calls). Lowering it risks 403s; raising it only makes the run slower.",
            "default": 500
          },
          "maxRequestRetries": {
            "title": "Max retries",
            "minimum": 0,
            "maximum": 20,
            "type": "integer",
            "description": "How many times a failed request is retried before it is listed as failed.",
            "default": 5
          },
          "debugLog": {
            "title": "Debug log",
            "type": "boolean",
            "description": "Verbose log. Useful when opening a support ticket.",
            "default": 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
                  },
                  "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}