List leads
List jobs matching a campaign's filters as stable, biddable leads.
GET /v1/campaigns/:campaignId/leadsReturns jobs from the Upwork job pool that match the campaign's saved filters, newest first. Each returned job is materialized into a persisted lead with a stable id, so you can bid on or reject any item immediately. This works on brand-new campaigns too; you do not need to wait for webhooks to start integrating.
Beyond driving bids, this endpoint is the easiest way to test your decision logic and prompts against a real batch of jobs: pull a page, run your suitability scoring or proposal generation over it, and iterate without waiting for new webhooks to fire.
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
offset | integer | 0 | Number of items to skip. |
limit | integer | 100 | Page size, 1 to 100. |
Example
curl "https://api.lancer.app/v1/campaigns/CAMPAIGN_ID/leads?limit=10" \
-H "Authorization: Bearer lk_..."Response
{
// The page of leads, newest first (ordered by createdAt desc). Each item
// is exactly the "lead" object you would receive on a job.new webhook,
// plus bidUrl / rejectUrl for convenience.
"data": [
{
"id": "lead_abc123",
"title": "Next.js developer for dashboard rebuild",
"description": "We are looking for...",
"jobUrl": "https://www.upwork.com/jobs/~021234567890",
"createdAt": 1754450000000,
"datetime": 1754449000000,
"category": "Web Development",
"skills": [{ "name": "Next.js" }, { "name": "TypeScript" }],
"questions": [
"Describe your recent experience with similar projects"
],
"metadata": {
"experienceLevel": "Expert",
"paymentType": "Hourly",
"hourlyRate": { "min": 30, "max": 60 },
"fixedPrice": null,
"duration": "3 to 6 months",
"hours": "More than 30 hrs/week"
},
"clientInfo": {
"isPaymentVerified": true,
"rating": 4.9,
"numberOfReviews": 41,
"country": "United States",
"totalSpent": 120000,
"numberOfHires": 38,
"hireRate": 71,
"memberSince": "2019-03-12"
},
"campaignId": "cmp_123",
"campaignName": "US SaaS clients",
"organizationId": "org_123",
"bidUrl": "https://api.lancer.app/v1/campaigns/cmp_123/leads/lead_abc123/bid",
"rejectUrl": "https://api.lancer.app/v1/campaigns/cmp_123/leads/lead_abc123/reject"
}
],
// Total number of matching leads in this campaign across all pages.
"total": 342,
// Echo of the offset/limit you sent (or the defaults, if you did not).
"offset": 0,
"limit": 10,
// true if offset + data.length < total. Stop paginating when this is false.
"hasMore": true
}The lead object is the same shape delivered in webhook payloads, plus ready-to-call bidUrl and rejectUrl. The full field list is documented there.
Timestamps
All timestamps inside lead objects are UNIX milliseconds.
Errors
| Status | When |
|---|---|
401 | Missing or invalid key, or the subscription is inactive. |
404 | Campaign not found (wrong id, or the campaign belongs to another organization). |