Query recent Upwork job listings with AI quality scores built in. Every result includes scores — no extra calls required.
Pass your API key as a Bearer token on every request. Generate keys in Settings → Developer.
Authorization: Bearer vw_your_api_key_here
Responses are always { data: [...], count: N } on success, or { error: '...' } with an appropriate HTTP status on failure. Free accounts also include quotaRemaining in each response.count is the number of jobs in this response, not the total number of jobs matching the filters.
https://kttkatrmvlzsepgprqqd.supabase.co/functions/v1/public-jobsReturns recent Upwork job listings matching your filters. Jobs are continuously ingested and scored as they are posted, and are usually available within 1–2 minutes of going live on Upwork.
Example request
curl https://kttkatrmvlzsepgprqqd.supabase.co/functions/v1/public-jobs \ -H "Authorization: Bearer vw_your_key" \ -G \ -d keywords=react \ -d jobType=fixed \ -d minQuickWin=7 \ -d sort=quick_win \ -d limit=20
Example response
{
"data": [
{
"id": "vw_b797267068b246bfa8da8722",
"title": "Build a Next.js dashboard with Supabase backend",
"category": "Web Development",
"jobType": "fixed",
"budget": 800,
"budgetMax": null,
"experienceLevel": "Intermediate",
"duration": "Less than 1 month",
"connects": 11,
"hoursPerWeek": null,
"skills": ["Next.js", "TypeScript", "Supabase", "Tailwind CSS"],
"clientLocation": "United States",
"clientPaymentVerified": true,
"clientTotalSpent": 42000,
"clientHireRate": 78,
"clientRating": 4.9,
"clientAvgRate": null,
"description": "Build a clean admin dashboard...",
"upworkUrl": "https://www.upwork.com/jobs/~01abc...",
"scores": {
"quickWin": 8,
"scopeClarity": 9,
"redFlags": 10,
"effortHours": 14
},
"postedAt": "2026-06-08T09:31:00+00:00",
"receivedAt": "2026-06-08T09:32:14.000+00:00"
}
],
"count": 1,
"quotaRemaining": 99
}keywordsstringFilter by job title keyword (e.g. react, shopify). Case-insensitive partial match.categorystringFilter by the exact category string returned on a job, for example Web Development, AI & Machine Learning, or QA & Testing. Categories originate upstream and may expand over time.jobTypefixed | hourlyFilter by contract type.experienceLevelEntry Level | Intermediate | ExpertFilter by the client's requested experience level.minBudgetnumberMinimum budget in USD. Uses the project budget for fixed-price jobs and the minimum hourly rate for hourly jobs.minQuickWininteger 0–10Only return jobs at or above this Quick Win score. Set to 7 to filter for high-quality quick wins only.sortnewest | quick_win | budgetSort order. Default: newest.limitinteger 1–100Maximum number of results to return. Default: 50. Free accounts are charged only for jobs actually returned.Every job returned by this endpoint has been scored by an LLM. The scores object is included on every result. Individual fields may be null when the source data or estimate is unavailable.
scores.quickWininteger 0–10Fixed price + clear bounded scope + completable in one session. Higher = faster money with less negotiation risk.scores.scopeClarityinteger 0–10How precisely the deliverable is defined. Low scores indicate vague requirements and scope creep risk.scores.redFlagsinteger 0–10Absence of bad signals. 10 = clean client with no red flags. Low scores mean proceed with caution.scores.effortHoursnumber | nullRealistic estimated hours to complete the job.| Free | Paid | |
|---|---|---|
| Results per day | 100 | Unlimited |
| Max per request | 100 | 100 |
| Per-minute limit | None | None |
| Quota reset | Midnight UTC | — |
| API keys | Multiple | Multiple |
The daily quota is per account, not per key — creating additional API keys does not increase your limit. There is no application-level per-minute throttle, but clients should avoid unnecessary high-frequency polling.
The live API uses an approximately seven-day rolling job window. It currently returns only the first matching page (up to 100 jobs); date cursors, pagination, and access to the cold archive are not available through this endpoint.
Rather than polling the API, webhooks push a job payload to your endpoint when a matching job is ingested — usually within 1–2 minutes of it posting on Upwork. Available on paid plans. Webhooks are configured per filter: open a filter's alert settings in the dashboard, enable the Webhook channel, and paste your endpoint URL. Use Preview alert to send a sample payload immediately.
Payload shape
{
"event": "job.matched",
"matchedAt": "2026-06-08T09:32:14.000Z",
"filterName": "React fixed-price",
"match": {
"scoreQuickWin": 8,
"scoreScopeClarity": 9,
"scoreRedFlags": 10,
"effortEstimateHours": 14,
"reasoning": "Clear bounded deliverable..."
},
"job": {
"id": "vw_b797267068b246bfa8da8722",
"title": "Build a Next.js dashboard",
"description": "Build a clean admin dashboard...",
"url": "https://www.upwork.com/jobs/~01abc...",
"type": "fixed",
"contractType": null,
"budget": { "min": 800, "max": null, "currency": "USD", "display": "$800" },
"duration": "Less than 1 month",
"hoursPerWeek": null,
"experienceLevel": "Intermediate",
"connectsRequired": 11,
"skills": ["Next.js", "TypeScript"],
"categories": ["Web Development"],
"postedAt": "2026-06-08T09:31:00+00:00"
},
"client": {
"location": "United States",
"locationRestriction": null,
"paymentVerified": true,
"totalSpent": 42000,
"jobsPosted": 31,
"hires": 24,
"hireRate": 78,
"rating": 4.9,
"reviewCount": 19,
"avgHourlyRate": null,
"rankScore": null,
"rankLabel": null
}
}Requests carry the X-Vibeworker-Event: job.matched header. Preview deliveries include "preview": true in the payload. Delivery is currently a single best-effort POST with no automatic retries or signature. Your endpoint should respond quickly, be idempotent, and treat the URL as a secret. Anyone who knows it can send requests to it, so ignore payloads that don't match this shape.