{
  "openapi": "3.0.1",
  "info": {
    "title": "Upwork Jobs Scraper",
    "description": "Scrape Upwork job posts by keyword or search URL: title, full description, skills, budget, hourly rate, experience level, duration and publication time. Export to JSON, CSV or Excel.",
    "version": "0.0",
    "x-build-id": "cfWVT72NIY7tWTpQa"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/nice_dev~upwork-jobs-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-nice_dev-upwork-jobs-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/nice_dev~upwork-jobs-scraper/runs": {
      "post": {
        "operationId": "runs-sync-nice_dev-upwork-jobs-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/nice_dev~upwork-jobs-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-nice_dev-upwork-jobs-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": "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. 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 for the whole run (after deduplication and filters). 0 = no limit.",
            "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"
          },
          "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
          },
          "onlyNew": {
            "title": "Only new job posts",
            "type": "boolean",
            "description": "Return only the job posts never delivered by a previous run with the same **Monitoring key**. A run that finds nothing new saves 0 items and is charged only the run-start fee.",
            "default": false
          },
          "stateKey": {
            "title": "Monitoring key",
            "pattern": "^[a-zA-Z0-9_-]+$",
            "maxLength": 60,
            "type": "string",
            "description": "Name of the memory used by **Only new job posts**. Use a different key per watched search so two searches do not hide each other's results.",
            "default": "default"
          },
          "resetState": {
            "title": "Reset monitoring memory",
            "type": "boolean",
            "description": "Forget everything remembered under this **Monitoring key** before starting, so this run returns every match again.",
            "default": false
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy, included in the price. Keep the default setting: the residential proxy is refused, because it would cost you money this Actor does not need.",
            "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}