Upwork icon

Upwork data API: jobs, proposals, Connects and contracts

Upwork Global Inc. · Jobs & Careers

Upwork, published by Upwork Global Inc. (part of Nasdaq-listed Upwork Inc.), is the Android app of the freelance marketplace born from the 2013 merger of Elance and oDesk and renamed Upwork in 2015, and one account runs both sides of a hire. Freelancers browse a Find Work feed split into Best Matches and Most Recent tabs, save jobs for later, open job details that show the client's payment-verification badge, location and hiring history, and bid with proposals paid for in Connects, the platform's bidding credits managed on the Membership & Connects screen. An Invitations tab collects invitations to interview, the Proposals tab tracks active, submitted and archived applications, and won work moves into contract rooms covering hourly terms with weekly limits or fixed-price terms, backed by earnings reports. Clients use the same app to browse recommended talent, send offers from the Hires screen and follow up in the Messages tab, while an Alerts bell flags job activity, interview invitations and new messages across every organization a user belongs to. Its audience is concentrated in the US, India and Pakistan, where businesses and independent professionals meet over hourly and fixed-price work, putting it in direct competition with Fiverr and Freelancer.com for remote independent talent.

Connects-priced proposals sit at the center of the record: each application carries its applicationUID, the openingUID of the job it targets, the freelancer's quoted chargeRate and the connectsBid spent to submit it, set against the wallet's availableConnects, currentPrice and consumedConnectFraction. Upstream, job cards hold hourlyBudget min/max ranges, prefLabel skill tags and a connectPrice, and the client's public company card adds paymentVerified, totalContracts, totalJobsWithHires and lifetime totalCharges. Interview invitations link a jobPostingUid to its contractorUid and clientUid; contracts, keyed by referenceContractRid, settle into charge_rate, weekly_limit and combinedTotalEarnings; on the hiring side, recommended-talent cards carry hourlyRateAmount and occupationTitle, and sent offers record their state and the freelancer's countryName. Message rooms and alerts round it out with unreadMessageCount and per-organization counters.

Staffing CRMs join proposals and interview invitations to client spend in totalCharges to see which clients actually hire; freelancer finance bots forecast weekly Connects burn from connectsBid and wallet pricing before the membership renews; agency ledgers reconcile contract rates and combinedTotalEarnings against the offers a client has sent; and hiring desks shortlist recommended talent by rate, then pick up any conversation already open in a message room. openData Studio turns Upwork's jobs, proposals, Connects and contracts into callable open data.

Screenshots

  • Upwork screenshot 1
  • Upwork screenshot 2
  • Upwork screenshot 3
  • Upwork screenshot 4
  • Upwork screenshot 5
  • Upwork screenshot 6

API surface

The endpoints and request/response examples below are reconstructed from the app's interface — illustrative, not a live capture.

  • Issue scoped session token

    POST /v1/auth/scoped-token osint

    Exchanges the mobile session for a scoped token (accessToken, refreshToken, expiresInSecs, tenantId) required by feed, proposal and room calls that the cookie-exchange path otherwise issues.

    Auth: Signed-in AccessToken plus session cookies. The server rejects a plain mobile Bearer when the scoped session-exchange is missing.

    • accessToken
    • refreshToken
    • expiresInSecs
    • tenantId
    • grant_type
    • scope
    POST /v1/auth/scoped-token HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    Content-Type: application/json
    
    {
      "grant_type": "client_credentials",
      "scope": "workspace"
    }
    {
      "accessToken": "eyJhbGciOiJSUzI1NiJ9...",
      "refreshToken": "rt_7c2e91ab",
      "expiresInSecs": 3600,
      "tenantId": "1513535512629587969"
    }
  • Best-match job recommendations feed

    POST /v1/feeds/best-match opendata

    Powers Find Work best-match cards: uid, ciphertext, title, hourlyBudget min/max, skills.prefLabel, connectPrice and the client's totalSpent / paymentVerificationStatus for the signed-in freelancer.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • results
    • uid
    • title
    • ciphertext
    • description
    • type
    • recno
    • hourlyBudget
    • min
    • max
    • skills
    • prefLabel
    • connectPrice
    • client
    • totalHires
    • totalSpent
    • paymentVerificationStatus
    • publishedOn
    • paging
    • total
    • count
    POST /v1/feeds/best-match HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    Content-Type: application/json
    
    {
      "limit": 10,
      "offset": 0
    }
    {
      "results": [
        {
          "uid": "1784869486235123712",
          "title": "Staff Product Manager",
          "ciphertext": "~015c7cd346853e24fd",
          "description": "Own the freelancer home feed.",
          "type": "HOURLY",
          "recno": 4123456789,
          "connectPrice": 16,
          "hourlyBudget": {
            "type": "RANGE",
            "min": 60,
            "max": 90
          },
          "skills": [
            {
              "id": "1017484851352698921",
              "prefLabel": "Product Management"
            }
          ],
          "client": {
            "totalHires": 12,
            "totalSpent": 71401.96,
            "paymentVerificationStatus": "VERIFIED"
          },
          "publishedOn": "2026-09-20T12:00:00.000Z"
        }
      ],
      "paging": {
        "total": 248,
        "count": 10
      }
    }
  • Most-recent job recommendations feed

    POST /v1/feeds/most-recent opendata

    Loads the Most Recent Find Work tab (id, ciphertext, publishedDateTime, title, type, recno, hourlyBudget) used when the freelancer switches off best-match ranking.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • results
    • id
    • uid
    • ciphertext
    • publishedOn
    • title
    • type
    • recno
    • hourlyBudget
    • attrs
    • skills
    • prefLabel
    • paging
    POST /v1/feeds/most-recent HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    Content-Type: application/json
    
    {
      "limit": 10
    }
    {
      "results": [
        {
          "id": "1784869486235123712",
          "uid": "1784869486235123712",
          "ciphertext": "~015c7cd346853e24fd",
          "publishedOn": "2026-09-21T08:15:00.000Z",
          "title": "Android contractor for wallet SDK",
          "type": "FIXED",
          "recno": 4123456790,
          "hourlyBudget": {
            "type": "RANGE",
            "min": 45,
            "max": 70
          },
          "attrs": [
            {
              "id": "1017484851352698921",
              "prefLabel": "Android"
            }
          ]
        }
      ],
      "paging": {
        "total": 248,
        "count": 10
      }
    }
  • Hydrate marketplace job posting

    GET /v1/jobs/{jobId}/posting opendata

    Hydrates a job-detail screen with the client's public company card: country, paymentVerified, totalContracts, totalJobsWithHires and totalCharges.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • id
    • clientCompanyPublic
    • country
    • twoLetterAbbreviation
    • timezone
    • memberSinceDateTime
    • paymentVerification
    • paymentVerified
    • workHistoryStats
    • totalContracts
    • totalJobsWithHires
    • totalCharges
    • currency
    • displayValue
    GET /v1/jobs/1802671287393773389/posting HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "id": "1802671287393773389",
      "clientCompanyPublic": {
        "id": "1009763084",
        "country": {
          "id": "922824128549781504",
          "name": "United States",
          "twoLetterAbbreviation": "US"
        },
        "timezone": "America/Los_Angeles",
        "memberSinceDateTime": "2022-08-18T00:00:00.000Z",
        "paymentVerification": {
          "paymentVerified": true
        },
        "workHistoryStats": {
          "totalContracts": 12,
          "totalJobsWithHires": 9,
          "totalCharges": {
            "currency": "USD",
            "displayValue": "71401.96"
          }
        }
      }
    }
  • Read Connects / invitation-bonus balance

    GET /v1/connects/wallet openfinance

    Returns the freelancer's Proposal Invitation Bonus / Connects wallet (pibStatus.availableConnects, currentPrice, maxPrice, consumedConnectFraction) used by Membership & Connects.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • pibStatus
    • personId
    • active
    • currentPrice
    • maxPrice
    • consumedConnectFraction
    • availableConnects
    • connectsBalance
    • connectsBalanceFree
    • connectsBalancePaid
    • visibilityLevel
    GET /v1/connects/wallet HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "pibStatus": {
        "personId": "1513535512629587968",
        "active": true,
        "currentPrice": 8,
        "maxPrice": 37,
        "consumedConnectFraction": 0.01,
        "availableConnects": 163
      },
      "user": {
        "freelancerProfile": {
          "userPreferences": {
            "visibilityLevel": 1
          }
        }
      }
    }
  • List proposals by type

    POST /v1/proposals opendata

    Pages the Proposals tab (active/submitted/archived): applicationUID, openingUID, chargeRate, connectsBid, coverLetter and occupationTitle for each application.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • paging
    • total
    • offset
    • applications
    • applicationUID
    • vendorUID
    • openingUID
    • title
    • status
    • coverLetter
    • terms
    • chargeRate
    • amount
    • currency
    • connectsBid
    • duration
    • occupationTitle
    POST /v1/proposals HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    Content-Type: application/json
    
    {
      "type": "ACTIVE",
      "limit": 10
    }
    {
      "paging": {
        "total": 42,
        "offset": "eyJBY3RpdmUiOiIxMCJ9",
        "count": 10
      },
      "applications": [
        {
          "applicationUID": "1784936978461474817",
          "vendorUID": "1513535512629587968",
          "openingUID": "1784869486235123712",
          "title": "Lead Paradigm Representative",
          "status": 7,
          "coverLetter": "I can start this week.",
          "terms": {
            "chargeRate": {
              "amount": "85",
              "currency": "USD"
            },
            "connectsBid": 17,
            "duration": 0
          },
          "occupationTitle": "Product Management"
        }
      ]
    }
  • List interview invitations

    POST /v1/invitations opendata

    Pages Invitation to interview rows (uid, jobPostingUid, status, invitationLetter, contractorUid, clientUid) that populate the Invitations tab.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • totalCount
    • count
    • invitations
    • uid
    • jobPostingUid
    • title
    • status
    • statusId
    • invitationLetter
    • contractorUid
    • clientUid
    • ctime
    POST /v1/invitations HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    Content-Type: application/json
    
    {
      "status": "PENDING",
      "pagination": {
        "offset": 0,
        "count": 10
      }
    }
    {
      "totalCount": 826,
      "count": 10,
      "invitations": [
        {
          "uid": "1784872122316197888",
          "jobPostingUid": "1784872118568779776",
          "title": "Legacy Division Technician",
          "status": "Pending",
          "statusId": 0,
          "invitationLetter": "We would like to interview you this week.",
          "contractorUid": "1441159363691524096",
          "clientUid": "1783553054015062016",
          "ctime": "2026-04-29T09:07:29.000Z"
        }
      ]
    }
  • List saved jobs

    GET /v1/saved-jobs opendata

    Returns Saved jobs with followed/jobRid plus the posting's title, hourlyBudgetMin/Max and the client's paymentVerified / totalCharges card.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • personSavedJobs
    • followed
    • jobRid
    • job
    • id
    • content
    • title
    • description
    • contractTerms
    • hourlyContractTerms
    • hourlyBudgetType
    • hourlyBudgetMin
    • hourlyBudgetMax
    • clientCompanyPublic
    • paymentVerified
    • workHistoryStats
    • totalCharges
    • rawValue
    GET /v1/saved-jobs?limit=20&offset=0&followed=true HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "personSavedJobs": [
        {
          "followed": true,
          "jobRid": "4123456789",
          "job": {
            "id": "1784869486235123712",
            "content": {
              "title": "Staff Product Manager",
              "description": "Own the freelancer home feed."
            },
            "contractTerms": {
              "hourlyContractTerms": {
                "hourlyBudgetType": "RANGE",
                "hourlyBudgetMin": 60,
                "hourlyBudgetMax": 90
              }
            },
            "clientCompanyPublic": {
              "paymentVerification": {
                "paymentVerified": true
              },
              "workHistoryStats": {
                "totalCharges": {
                  "rawValue": 71401.96,
                  "currency": "USD",
                  "displayValue": "71401.96"
                },
                "totalContracts": 12
              }
            }
          }
        }
      ]
    }
  • Recommended freelancers (talent search)

    GET /v1/talent/recommended osint

    Returns ranked freelancer cards (id, ciphertext, hourlyRateAmount, occupationTitle, portraitUrl) that the client Talent search / recommended-talent strip hydrates.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • freelancers
    • id
    • name
    • photoUrl
    • profileUrl
    • ciphertext
    • hourlyRateAmount
    • occupationTitle
    • portraitUrl
    GET /v1/talent/recommended?openingId=1784869486235123712&limit=10 HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "freelancers": [
        {
          "id": "1939570823820670781",
          "name": "Ruthie L.",
          "photoUrl": "https://cdn.example.com/portraits/c1example",
          "profileUrl": "/freelancers/~01a4efc20a2cd41f48",
          "ciphertext": "~01a4efc20a2cd41f48",
          "hourlyRateAmount": 75,
          "occupationTitle": "Product Manager",
          "portraitUrl": "https://cdn.example.com/portraits/c1example"
        }
      ]
    }
  • List message rooms (simplified)

    GET /v1/inbox/rooms osint

    Returns the simplified room list (id, unreadStoriesCount, unreadMessageCount) that seeds the Messages tab before a full room payload is fetched.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • rooms
    • id
    • roomId
    • title
    • unreadStoriesCount
    • unreadMessageCount
    • unreadStories
    • userId
    GET /v1/inbox/rooms?userId=1513535512629587968 HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "rooms": [
        {
          "id": "room_5a82d4931d5f5aea3817fd0a14fcbbba",
          "roomId": "room_5a82d4931d5f5aea3817fd0a14fcbbba",
          "title": "Staff Product Manager",
          "unreadStoriesCount": 2,
          "unreadMessageCount": 2,
          "unreadStories": true,
          "userId": "1513535512629587968"
        }
      ]
    }
  • List room stories (simplified)

    GET /v1/inbox/rooms/{roomId}/stories osint

    Pages the simplified story (message) list for one room after the Messages tab opens a conversation.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • stories
    • storyId
    • roomId
    • unreadStoriesCount
    GET /v1/inbox/rooms/room_5a82d4931d5f5aea3817fd0a14fcbbba/stories HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "stories": [
        {
          "storyId": "story_9f3a1c",
          "roomId": "room_5a82d4931d5f5aea3817fd0a14fcbbba",
          "unreadStoriesCount": 1
        }
      ]
    }
  • List user notifications

    GET /v1/alerts/{userId} osint

    Pages the Alerts bell: notificationId, unread flags and title for job activity, invitations and room events.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • notifications
    • notificationId
    • unread
    • notification_unread
    • title
    • userId
    GET /v1/alerts/1513535512629587968 HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "notifications": [
        {
          "notificationId": "n_9f3a1c",
          "unread": true,
          "notification_unread": true,
          "title": "Invitation to interview",
          "userId": "1513535512629587968"
        }
      ]
    }
  • Read organization notification counts

    GET /v1/alerts/org-counts osint

    Returns per-organization notification counters (organizations[].counters) that drive the Alerts and Messages badges.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • organizations
    • id
    • orgUid
    • counters
    • count
    GET /v1/alerts/org-counts HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "organizations": [
        {
          "id": "1513535512629587969",
          "orgUid": "1513535512629587969",
          "counters": [
            {
              "id": "messages",
              "count": 2
            }
          ]
        }
      ]
    }
  • Fetch contract details

    GET /v1/contracts/{contractId} openfinance

    Loads a Contract room: uid, referenceContractRid, hourly charge_rate and weekly_limit, plus combinedTotalEarnings used by Reports / earnings history.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • uid
    • referenceContractRid
    • state
    • clientOrgUid
    • clientTeamUid
    • freelancerUid
    • offerDetails
    • title
    • hourly
    • charge_rate
    • weekly_limit
    • start_date
    • fixedPrice
    • combinedTotalEarnings
    • currency
    • displayValue
    GET /v1/contracts/1669484061874712576 HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    {
      "uid": "1669484061874712576",
      "referenceContractRid": "20799532",
      "state": 1,
      "clientOrgUid": "1638232740248182785",
      "clientTeamUid": "1638232740248182785",
      "freelancerUid": "1663144681572958208",
      "offerDetails": {
        "title": "Staff Product Manager",
        "description": "Hourly product contract",
        "hourly": {
          "charge_rate": "85",
          "weekly_limit": "40",
          "start_date": "2026-09-17T00:00:00.000Z"
        },
        "fixedPrice": null
      },
      "combinedTotalEarnings": {
        "currency": "USD",
        "displayValue": "12840.00"
      }
    }
  • List client contract offers

    POST /v1/hires/offers openfinance

    Pages the client's sent offers: offer id, title, state, type, contract.rid and freelancer.location.countryName for the Hires / Offers screens.

    Auth: OAuth2 Bearer AccessToken issued after sign-in; X-Upwork-Authentication and X-Upwork-API-TenantId. GraphQL-style data calls additionally expect a scoped session-exchange token — a plain mobile Bearer is rejected when that scope is missing.

    • totalCount
    • edges
    • node
    • id
    • startDateTime
    • endDateTime
    • title
    • state
    • type
    • contract
    • rid
    • agency
    • name
    • freelancer
    • location
    • countryName
    POST /v1/hires/offers HTTP/1.1
    Authorization: Bearer <accessToken>
    X-Upwork-Authentication: <accessToken>
    X-Upwork-API-TenantId: <tenantId>
    Content-Type: application/json
    
    {
      "pagination": {
        "offset": 0,
        "count": 10
      }
    }
    {
      "totalCount": 3,
      "edges": [
        {
          "node": {
            "id": "101694088",
            "startDateTime": "2026-09-17T00:00:00.000Z",
            "endDateTime": null,
            "title": "Staff Product Manager",
            "state": "ACCEPTED",
            "type": "HOURLY",
            "contract": {
              "rid": "20799532"
            },
            "agency": {
              "name": "Northwind Studio"
            },
            "freelancer": {
              "location": {
                "countryName": "United States"
              }
            }
          }
        }
      ]
    }

Data categories

  • job postings
  • proposals
  • interview invitations
  • Connects balance
  • contracts
  • client company stats
  • message rooms
  • notifications
  • freelancer profiles

Where teams use this data

  • Freelance talent CRM from job + proposal fields

    A staffing CRM can poll POST /v1/proposals and POST /v1/invitations for applicationUID, openingUID, chargeRate, connectsBid and invitation status, then join each row to GET /v1/jobs/{jobId}/posting (paymentVerified, totalCharges, country) so recruiters see which clients actually spend.

  • Connects wallet and bid-cost tracking

    A freelancer finance bot can read pibStatus (availableConnects, currentPrice, maxPrice, consumedConnectFraction) on GET /v1/connects/wallet and the connectsBid on each submitted proposal to forecast weekly Connects burn before the Membership & Connects screen renews.

  • Contract rate and earnings reconciliation

    An agency ledger can pull GET /v1/contracts/{contractId} for hourly charge_rate, weekly_limit and combinedTotalEarnings, keyed by uid / referenceContractRid, and cross-check those figures against POST /v1/hires/offers on the client's Hires screen.

  • Client-side recommended-talent shortlist

    A hiring desk can call GET /v1/talent/recommended for ciphertext, hourlyRateAmount, occupationTitle and portraitUrl, then open the matching simplified room on GET /v1/inbox/rooms when a conversation already exists.

Frequently asked questions

How does the Upwork Android app authenticate data calls?

Sign-in yields an OAuth2 AccessToken (accessToken, refreshToken, expiresInSecs, tenantId). Subsequent calls send Authorization: Bearer plus X-Upwork-Authentication and X-Upwork-API-TenantId. Feed, proposal and room hosts additionally expect a scoped token from POST /v1/auth/scoped-token — a plain mobile Bearer is rejected when that scope is missing.

Which data powers Find Work job cards?

POST /v1/feeds/best-match and POST /v1/feeds/most-recent return uid, ciphertext, title, hourlyBudget and skills.prefLabel. Opening a card hydrates GET /v1/jobs/{jobId}/posting, including paymentVerified and workHistoryStats.totalCharges on the client's public company card.

Where is the Connects / invitation-bonus balance exposed?

The Membership & Connects screens read GET /v1/connects/wallet: pibStatus.availableConnects, currentPrice, maxPrice and consumedConnectFraction. Submitted proposals also carry terms.connectsBid.

Can I read contracts and message rooms, not just jobs?

Yes. GET /v1/contracts/{contractId} returns uid, hourly charge_rate, weekly_limit and combinedTotalEarnings. GET /v1/inbox/rooms lists rooms with unreadStoriesCount, and GET /v1/alerts/{userId} pages the Alerts bell.

Apps similar to Upwork

  • Fiverr — Fiverr is an Israeli online marketplace where buyers purchase packaged freelance services (gigs) rather than posting an open job brief.
  • Freelancer — Freelancer is an Australian marketplace where clients post jobs and contests, with a large share of users in India, the United States, the Philippines, Pakistan and the United Kingdom.
  • Toptal — Toptal is a remote talent network that screens freelance developers and designers before matching them with companies.
  • Guru — Guru.com is a Pittsburgh-based freelance marketplace that supports fixed-price, hourly, task-based and recurring contracts.
  • PeoplePerHour — PeoplePerHour is a London-based freelance marketplace that connects clients with independent professionals.
  • LinkedIn: Community & Network — LinkedIn is a professional network with job listings and an Open for Business profile so freelancers can be discovered by clients.
  • 99designs — 99designs is a freelancer platform that connects graphic designers with clients through contests and direct hiring.

Topics

  • Upwork data API
  • Upwork job feed
  • Upwork best-match jobs
  • Upwork Connects wallet
  • Upwork proposals list
  • Upwork interview invitations
  • Upwork contract earnings
  • Upwork inbox rooms
  • Upwork talent search
  • Upwork AccessToken

Need this app's data API integrated?

We deliver scoped integrations for any named app — from USD 500 with source-code handoff, or hosted access billed per call. Tell us the data you need.

  • NDA + SOW on every engagement
  • Delivery in 3–7 days
  • Payment only after acceptance
  • Work scoped to authorized use

Get a quote