List leads

List jobs matching a campaign's filters as stable, biddable leads.

GET /v1/campaigns/:campaignId/leads

Returns 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

ParameterTypeDefaultNotes
offsetinteger0Number of items to skip.
limitinteger100Page 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

StatusWhen
401Missing or invalid key, or the subscription is inactive.
404Campaign not found (wrong id, or the campaign belongs to another organization).

On this page