Find new Upwork jobs that match your skills before others bid
Search Upwork for a keyword and get jobs as JSON with budget, skills, client history and posted time, to spot gigs worth bidding on and track demand.
If you freelance or run a small agency, the best Upwork jobs go to the first few people who bid, and the search page makes you refresh by hand. If you sell services, the same listings also show what clients ask for and what they pay. Lovely Router runs the search for you. Send a keyword and filters, get one JSON object per job, pay per job from a prepaid balance. Call it from a cron job, a Slack bot or an AI agent with one API key.
Hand it to your AI agent
Copy this prompt into Claude Code, Cursor, Codex or any coding agent. It tells the agent where the docs are and how to use your API key.
Find new Upwork jobs that match your skills before others bid. Use the Lovely Router data tools: each returns JSON and is billed per result.
- Docs (read first): https://lovelyrouter.com/docs/tools/find.md and https://lovelyrouter.com/docs/tools/run.md
- Plan first: POST https://lovelyrouter.com/v1/tools/suggest with `{"task": "<my task in plain words>"}` (free). It returns the tools to run in order, each with an example `input`, the `input_required` fields, an estimated cost and a ready-made `run` request. Replace the example values with my task's; if a field is unclear, read the tool with GET https://lovelyrouter.com/v1/tools/<id>. To browse instead, POST https://lovelyrouter.com/v1/tools/discover searches the catalog.
- Show me the plan and its estimated cost (`total_est_cost_usd`) before running anything large.
- Run: POST https://lovelyrouter.com/v1/tools/<id>/run with `{"input": {...}, "max_results": N}`. A 200 has the finished run with `items`; a 202 means it is still running, so poll the `poll` path until `status` is `succeeded`, `failed`, `timed_out` or `stopped`.
- Only delivered results are billed. Keep max_results small on the first run, check the output, then scale up.
- If you support MCP, connect https://lovelyrouter.com/mcp instead (Streamable HTTP, same key; https://lovelyrouter.com/docs/tools/mcp.md) and use suggest_tools, get_tool and run_tool.
- Auth: read my API key from the LOVELY_API_KEY environment variable and send it as `Authorization: Bearer $LOVELY_API_KEY`. Never print or commit the key. If it is not set, ask me to create one at https://lovelyrouter.com/app/keys.
- Billing is prepaid: every call is charged to my balance, so test with a small request before running anything large.
- Every docs page is plain Markdown; the full index is https://lovelyrouter.com/llms.txt.
My task: <the inputs (links, keywords or accounts) and how many results you need>How it works
Pick your search
Choose the keywords for the work you sell, such as
web scrapingordata entry. Add filters for experience level, payment type or verified payment, and sort bynewest.Run the tool with a cap
Send the input to
POST /v1/tools/upwork-jobs/runwithmax_results. The run holds its maximum cost from your balance and returns the jobs as JSON.Filter and notify
Keep the job ids you have seen. On each run, send yourself only the new jobs that fit your budget, skills and client history.
Get Upwork jobs with one request
Search Upwork jobs takes a query. The result cap goes in perPage; the example below asks for 10 jobs:
curl https://lovelyrouter.com/v1/tools/upwork-jobs/run \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{
"input": {
"query": "web scraping",
"perPage": 10
},
"max_results": 10
}'The call returns the jobs as the search shows them, newest first when you set sort to newest (the default). A run still going after 60 seconds returns 202; Run a tool shows how to poll.
What each job holds
| Field group | What you get |
|---|---|
| Job | Title and what the client asks for |
| Pay | Budget or rate |
| Skills | The skills the client tagged |
| Client | Client history |
| Timing | When the job was posted |
Narrow the search with experienceLevel, jobType (the payment type) and paymentVerified. Ask a model to score each job against your profile in the same pipeline.
Recipes
Run your keyword every 30 minutes with sort set to newest. Compare the results with the job ids you stored and post only the new ones to a channel.
Set paymentVerified to true, then keep the jobs whose client history looks established.
Pull 50 jobs for the work you sell, read the budgets and rates, and set your own rate against the middle of the range.
Count the skill tags across a week of jobs to see what to learn or advertise next.
Send each new job to a model with your portfolio and let it write a first draft you edit before you send it.
Prefer plain words? Connect the MCP server and tell Claude Code or Cursor: "Find the 30 newest Upwork jobs for web scraping with verified payment, drop anything without a stated budget, and list title, budget, skills and client history. Set max_results to 30."
Pair it with other job sources
Upwork covers freelance work. Full-time roles and company career pages tell you who else is hiring for the same skills:
Freelance jobs on Upwork for a search: title, budget or rate, skills, client history, posted time.
LinkedIn job postings for a title/skill and location (or a jobs search URL): title, company, location, salary, posted date, applicants, description.
Indeed job postings by title and location: company, salary, posted date, description.
Glassdoor job postings by keyword and location.
Fresh job postings straight from companies' own career sites and ATSs (Greenhouse, Lever, Workday…), searchable by title, location and company.
linkedin-jobssearches LinkedIn job postings for the same skill.indeed-jobsadds Indeed postings, useful for contract and full-time demand.glassdoor-jobsadds Glassdoor listings.career-site-jobsreads jobs from company career sites.
For hiring-side use of job data, see recruiting data.
What you pay
You pay per job: starting a run holds its maximum cost, the per-call fee plus the per-job fee times max_results, and the run settles to what it returned. The rest of the hold goes back to your balance. A run that fails or times out pays only for the jobs it delivered, and a run refused at the start costs nothing.
Checking 50 jobs every hour is billed as 50 jobs per run, so a narrow search with a low max_results keeps the cost small. There is no subscription and no monthly minimum: top up from $5, and one balance pays for tools and models. The card above shows today's price; pricing lists every tool.
Frequently asked questions
Can I search Upwork by keyword?+
Yes. The query field takes the keywords, and sort can be newest or relevance.
Which filters does it support?+
Experience level, job type (payment type) and payment verified. Anything else you filter in your own code after the run.
How many jobs can one run return?+
Up to 50, set with perPage. The default is 20, and a run returns at least 10 when you set it.
Does it apply to jobs or send proposals for me?+
No. It reads job listings and returns them as JSON. You write and send your own proposals.
Do I need a subscription?+
No. You add credit to a prepaid balance and each run draws it down. Failed runs pay only for the results they delivered, and nothing renews automatically.
Looking at the hiring side too? See recruiting data, and the rest of the tool catalog.