{
  "openapi": "3.0.1",
  "info": {
    "title": "Upwork Job Scraper | Client Intel & Proposals",
    "description": "Scrape Upwork jobs by keyword, budget, experience or client quality. Every job arrives fully enriched — client country, lifetime spend, rating, hires, average rate paid and exact proposal counts — with incremental monitoring and alerts. No add-ons, no Upwork account.",
    "version": "1.0",
    "x-build-id": "BB8AlBRAcg366XPUC"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/corvuslab~upwork-job-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-corvuslab-upwork-job-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/corvuslab~upwork-job-scraper/runs": {
      "post": {
        "operationId": "runs-sync-corvuslab-upwork-job-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/corvuslab~upwork-job-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-corvuslab-upwork-job-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 query 🔍",
            "type": "string",
            "description": "Keywords to search for, e.g. \"python\" or \"shopify developer\"."
          },
          "queries": {
            "title": "Search queries 📑",
            "type": "array",
            "description": "Run several keyword searches in one run. Results are deduplicated by job ID across all queries, so overlapping searches never bill you twice.",
            "items": {
              "type": "string"
            }
          },
          "searchUrls": {
            "title": "Search URLs 🔗",
            "type": "array",
            "description": "Paste Upwork search URLs straight from your browser, e.g. https://www.upwork.com/nx/search/jobs/?q=react&t=1. Every filter in the URL is read and applied automatically.",
            "items": {
              "type": "string"
            }
          },
          "maxResults": {
            "title": "Max results per search 🔢",
            "minimum": 0,
            "maximum": 5000,
            "type": "integer",
            "description": "Maximum jobs to return per search. Upwork caps any single search at 5,000 results; set 0 to take that maximum.",
            "default": 50
          },
          "sort": {
            "title": "Sort by ↕️",
            "enum": [
              "recency",
              "relevance",
              "client_total_charge",
              "client_rating"
            ],
            "type": "string",
            "description": "Result ordering. \"Newest first\" is best for monitoring; \"Most relevant\" is best for one-off research.",
            "default": "recency"
          },
          "jobType": {
            "title": "Job type 💼",
            "enum": [
              "",
              "hourly",
              "fixed"
            ],
            "type": "string",
            "description": "Hourly or fixed-price contracts.",
            "default": ""
          },
          "experienceLevel": {
            "title": "Experience level 🎓",
            "type": "array",
            "description": "Select one or more; leave empty for any level.",
            "items": {
              "type": "string",
              "enum": [
                "entry",
                "intermediate",
                "expert"
              ],
              "enumTitles": [
                "Entry level 🌱",
                "Intermediate 📘",
                "Expert 🏆"
              ]
            }
          },
          "category": {
            "title": "Category 🗂️",
            "enum": [
              "",
              "web-mobile-software-dev",
              "it-networking",
              "data-science-analytics",
              "engineering-architecture",
              "design-creative",
              "sales-marketing",
              "writing",
              "translation",
              "admin-support",
              "customer-service",
              "legal",
              "accounting-consulting"
            ],
            "type": "string",
            "description": "Top-level Upwork category. You can also paste a raw category UID if you need a narrower one.",
            "default": ""
          },
          "budget": {
            "title": "Fixed-price budget 💵",
            "enum": [
              "",
              "0-99",
              "100-499",
              "500-999",
              "1000-4999",
              "5000+"
            ],
            "type": "string",
            "description": "Budget bracket for fixed-price jobs (USD).",
            "default": ""
          },
          "hourlyRate": {
            "title": "Hourly rate range ⏱️",
            "type": "string",
            "description": "Hourly budget range in USD, written as \"min-max\", e.g. \"30-80\". Open-ended works too: \"50-\" means $50/hr and up."
          },
          "workload": {
            "title": "Workload 📅",
            "enum": [
              "",
              "as_needed",
              "part_time",
              "full_time"
            ],
            "type": "string",
            "description": "How many hours per week the client expects.",
            "default": ""
          },
          "duration": {
            "title": "Project duration ⏳",
            "enum": [
              "",
              "week",
              "month",
              "semester",
              "ongoing"
            ],
            "type": "string",
            "description": "Expected engagement length.",
            "default": ""
          },
          "contractToHire": {
            "title": "Contract-to-hire only 🤝",
            "type": "boolean",
            "description": "Only jobs the client may convert into a full-time role.",
            "default": false
          },
          "location": {
            "title": "Client location 📍",
            "type": "string",
            "description": "Filter by the client's country or region, written in full, e.g. \"United States\", \"Ukraine\", \"Europe\". Two-letter codes are not accepted by Upwork."
          },
          "skills": {
            "title": "Skills 🛠️",
            "type": "string",
            "description": "Filter by Upwork skill tags, comma-separated, e.g. \"react,typescript\"."
          },
          "verifiedPaymentOnly": {
            "title": "Payment-verified clients only ✅",
            "type": "boolean",
            "description": "Drop jobs from clients who have not verified a payment method.",
            "default": false
          },
          "minClientTotalSpent": {
            "title": "Min. client lifetime spend 💰",
            "minimum": 0,
            "type": "integer",
            "description": "Only clients who have spent at least this much on Upwork (USD)."
          },
          "minClientRating": {
            "title": "Min. client rating ⭐",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Only clients rated at or above this score (0–5)."
          },
          "minClientReviewCount": {
            "title": "Min. client review count 📝",
            "minimum": 0,
            "type": "integer",
            "description": "Only clients with at least this many reviews — useful for filtering out brand-new accounts."
          },
          "clientHires": {
            "title": "Client hire history 👥",
            "enum": [
              "",
              "0",
              "1-9",
              "10+"
            ],
            "type": "string",
            "description": "How many freelancers the client has hired before.",
            "default": ""
          },
          "proposals": {
            "title": "Competition level 📉",
            "type": "array",
            "description": "Keep only jobs in these proposal-count brackets. Pair the low brackets with \"Newest first\" to find jobs before they get crowded.",
            "items": {
              "type": "string",
              "enum": [
                "0-4",
                "5-9",
                "10-14",
                "15-19",
                "20-49",
                "50+"
              ],
              "enumTitles": [
                "0–4 proposals",
                "5–9",
                "10–14",
                "15–19",
                "20–49",
                "50+"
              ]
            }
          },
          "excludeLocations": {
            "title": "Exclude client countries 🚫",
            "type": "array",
            "description": "Drop jobs from these client countries, written in full, e.g. \"India\", \"Pakistan\".",
            "items": {
              "type": "string"
            }
          },
          "includeKeywords": {
            "title": "Include keywords ✅",
            "type": "array",
            "description": "Keep a job only if it matches at least one of these terms.",
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "Exclude keywords ❌",
            "type": "array",
            "description": "Drop any job matching one of these terms.",
            "items": {
              "type": "string"
            }
          },
          "keywordMatchTitle": {
            "title": "Match keywords in title",
            "type": "boolean",
            "description": "Restrict keyword matching to the job title. If none of the three match toggles is on, all fields are searched.",
            "default": false
          },
          "keywordMatchDescription": {
            "title": "Match keywords in description",
            "type": "boolean",
            "description": "Restrict keyword matching to the job description. If none of the three match toggles is on, all fields are searched.",
            "default": false
          },
          "keywordMatchSkills": {
            "title": "Match keywords in skills",
            "type": "boolean",
            "description": "Restrict keyword matching to the job's skill tags. If none of the three match toggles is on, all fields are searched.",
            "default": false
          },
          "allWords": {
            "title": "All of these words ➕",
            "type": "string",
            "description": "Upwork's native AND search — every word must appear."
          },
          "anyWords": {
            "title": "Any of these words 🔀",
            "type": "string",
            "description": "Upwork's native OR search — at least one word must appear."
          },
          "exactPhrase": {
            "title": "This exact phrase 💬",
            "type": "string",
            "description": "Match the phrase exactly, e.g. \"machine learning\"."
          },
          "noneWords": {
            "title": "None of these words ➖",
            "type": "string",
            "description": "Upwork's native NOT search — filtered server-side, before you pay for the result."
          },
          "titleSearch": {
            "title": "Search in title only 🏷️",
            "type": "string",
            "description": "Match these keywords against the job title only."
          },
          "fromDate": {
            "title": "Posted from 📅",
            "type": "string",
            "description": "Keep jobs posted on or after this date (YYYY-MM-DD or ISO-8601)."
          },
          "toDate": {
            "title": "Posted until 📅",
            "type": "string",
            "description": "Keep jobs posted on or before this date (inclusive)."
          },
          "maxAgeMinutes": {
            "title": "Max age (minutes) ⏰",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only jobs posted within this many minutes before the run. Ideal for near-real-time alerting; 0 disables it.",
            "default": 0
          },
          "customFilters": {
            "title": "Custom field rules 🧪",
            "type": "array",
            "description": "Rule-based filters on any output field, e.g. [{\"field\":\"clientTotalSpent\",\"operator\":\"gte\",\"value\":10000}]. Operators: includes, notIncludes, equals, notEquals, gt, gte, lt, lte, exists, notExists."
          },
          "enrichDetails": {
            "title": "Fetch job details 📄",
            "type": "boolean",
            "description": "Fetch each job's detail page to add the client panel (country, lifetime spend, rating, reviews, payment verification), the exact proposal count and the freelancer requirements. No Upwork account needed, and no extra per-job fee. Turn off for the fastest possible listing-only run.",
            "default": true
          },
          "detailConcurrency": {
            "title": "Detail concurrency ⚡",
            "minimum": 1,
            "maximum": 30,
            "type": "integer",
            "description": "Parallel detail requests. Each one uses its own proxy IP, so higher values spread the load across more IPs. 20 is the measured sweet spot; throughput flattens above it.",
            "default": 20
          },
          "descriptionFormat": {
            "title": "Description format 📝",
            "enum": [
              "all",
              "text",
              "html",
              "markdown"
            ],
            "type": "string",
            "description": "Which description variants to include in each record.",
            "default": "all"
          },
          "descriptionMaxLength": {
            "title": "Truncate description ✂️",
            "minimum": 0,
            "type": "integer",
            "description": "Cut descriptions to this many characters (0 = keep the full text). Useful for keeping LLM context small.",
            "default": 0
          },
          "compact": {
            "title": "Compact records 🪶",
            "type": "boolean",
            "description": "Return only the core fields — ideal for AI agents and MCP pipelines.",
            "default": false
          },
          "excludeEmptyFields": {
            "title": "Drop empty fields 🧹",
            "type": "boolean",
            "description": "Remove null and empty values from each record.",
            "default": false
          },
          "incrementalMode": {
            "title": "Incremental mode 🔁",
            "type": "boolean",
            "description": "The first run builds a baseline; later runs emit only NEW / UPDATED jobs. Unchanged jobs are recognised before their detail page is fetched, so you skip both the work and the cost.",
            "default": false
          },
          "stateKey": {
            "title": "State key 🗝️",
            "type": "string",
            "description": "Stable name for the tracking state. Leave blank to derive it from your search settings automatically."
          },
          "emitUnchanged": {
            "title": "Also emit unchanged jobs",
            "type": "boolean",
            "description": "Return the full result set every run instead of only the changes.",
            "default": false
          },
          "emitExpired": {
            "title": "Also emit expired jobs",
            "type": "boolean",
            "description": "Emit a record for jobs that were tracked last run but have since dropped off.",
            "default": false
          },
          "skipReposts": {
            "title": "Skip reposts ♻️",
            "type": "boolean",
            "description": "Detect jobs re-listed under a new ID and drop them. Kept jobs are tagged with isRepost / repostOfId either way.",
            "default": false
          },
          "telegramToken": {
            "title": "Telegram bot token ✈️",
            "type": "string",
            "description": "Bot token from @BotFather."
          },
          "telegramChatId": {
            "title": "Telegram chat ID ✈️",
            "type": "string",
            "description": "Chat, group or channel ID to post into."
          },
          "slackWebhookUrl": {
            "title": "Slack webhook URL 💬",
            "type": "string",
            "description": "Slack Incoming Webhook URL."
          },
          "discordWebhookUrl": {
            "title": "Discord webhook URL 🎮",
            "type": "string",
            "description": "Discord channel webhook URL."
          },
          "webhookUrl": {
            "title": "Generic webhook URL 🪝",
            "type": "string",
            "description": "Receives a structured JSON payload (run metadata plus a jobs array). Ideal for n8n, Make or Zapier."
          },
          "webhookHeaders": {
            "title": "Webhook headers 🧾",
            "type": "object",
            "description": "Extra HTTP headers for the generic webhook, e.g. an Authorization header."
          },
          "notificationLimit": {
            "title": "Jobs per message 🔢",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "How many jobs to list in each message. The total matched count is always reported.",
            "default": 5
          },
          "notifyOnlyChanges": {
            "title": "Notify only about changes",
            "type": "boolean",
            "description": "Only alert on NEW / UPDATED jobs. Requires incremental mode.",
            "default": false
          },
          "includeRunSummary": {
            "title": "Include run summary",
            "type": "boolean",
            "description": "Prepend a one-line summary to each notification.",
            "default": true
          },
          "proxyConfiguration": {
            "title": "Proxy configuration 🌐",
            "type": "object",
            "description": "This actor talks to Upwork's JSON API and transfers only a few KB per job, so the default datacenter proxy is plenty. Switch to residential only if you see repeated blocks.",
            "default": {
              "useApifyProxy": true
            }
          },
          "sessionToken": {
            "title": "Upwork session token 🔑",
            "type": "string",
            "description": "Optional. Roughly 10–20% of jobs hide their detail page from logged-out visitors. Supplying the oauth2_global_js_token cookie value from a logged-in Upwork session unlocks those too. Everything else works without it."
          },
          "visitorClientId": {
            "title": "Visitor client ID",
            "type": "string",
            "description": "Override for Upwork's public visitor OAuth2 client ID. Only needed if Upwork rotates it and this actor has not been updated yet."
          },
          "visitorClientSecret": {
            "title": "Visitor client secret",
            "type": "string",
            "description": "Override for Upwork's public visitor OAuth2 client secret. See above."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}