Skip to main content
GET
/
api
/
public
/
v1
/
jobs
/
{id}
/
proposals
curl -sS "https://app.opentrain.ai/api/public/v1/jobs/<JOB_ID>/proposals?status=UNREVIEWED&limit=25" \
  -H "Authorization: Bearer $OT_API_TOKEN"
{
  "proposals": [
    {
      "id": "<PROPOSAL_ID>",
      "jobId": "<JOB_ID>",
      "jobTitle": "Spanish Sentiment Labeling — Social Media Posts",
      "createdAt": "2026-06-11T15:40:00.000Z",
      "updatedAt": "2026-06-11T15:40:00.000Z",
      "status": {
        "raw": "UNREVIEWED",
        "label": "Unreviewed"
      },
      "bid": {
        "amountUsd": 0.06,
        "unit": "PER_LABEL",
        "labelerHourlyRateUsd": null
      },
      "candidate": {
        "id": "<FREELANCER_ID>",
        "profileSlug": "maria-g",
        "displayName": "Maria G.",
        "firstName": "Maria",
        "lastNameInitial": "G",
        "profileTitle": "Text Annotation Specialist",
        "profilePhotoUrl": "https://app.opentrain.ai/<PHOTO_PATH>",
        "countryCode": "ES",
        "country": "Spain",
        "talentType": "FREELANCER",
        "highestEarningsUsd": 2400,
        "reviewCount": 7
      },
      "metrics": {
        "interviewScore": 86,
        "matchScore": 0.91
      }
    }
  ],
  "nextCursor": null
}
Lists the proposals on one of your jobs, newest first — each with the candidate’s bid, AI-interview score, and a privacy-safe candidate summary. This is the entry point of the candidate evaluation flow: list here, then drill into GET /proposals/{id} and the interview transcript. Candidate identity is masked pre-hire: first name + last initial, no contact details. Personal emails are never exposed at any stage — see privacy. Requirements: proposals:read scope. The job must be yours (403 otherwise). Works pre-claim.

Request

id
string
required
Your job’s ID.
status
string
Filter by proposal status: UNREVIEWED, SHORTLISTED, MAYBE, HIRED, DECLINED, NOT_A_FIT, or RESUME_SENT. Case-insensitive; spaces and hyphens are normalized to underscores. Invalid values return 400 with details.supportedStatuses.
limit
number
default:"25"
Page size, max 100. Below 1 → 400.
cursor
string
Pagination cursor (a proposal ID) from a previous response’s nextCursor.

Response

proposals
object[]
Proposals ordered by creation date, newest first.
nextCursor
string | null
Pass back as cursor for the next page; null at the end.

Errors

StatuscodeMeaning
400BAD_REQUESTInvalid status (details.supportedStatuses) or limit below 1
401UNAUTHORIZEDMissing or invalid token
403FORBIDDENMissing proposals:read scope, or the job belongs to another account
404NOT_FOUNDNo such job
curl -sS "https://app.opentrain.ai/api/public/v1/jobs/<JOB_ID>/proposals?status=UNREVIEWED&limit=25" \
  -H "Authorization: Bearer $OT_API_TOKEN"
{
  "proposals": [
    {
      "id": "<PROPOSAL_ID>",
      "jobId": "<JOB_ID>",
      "jobTitle": "Spanish Sentiment Labeling — Social Media Posts",
      "createdAt": "2026-06-11T15:40:00.000Z",
      "updatedAt": "2026-06-11T15:40:00.000Z",
      "status": {
        "raw": "UNREVIEWED",
        "label": "Unreviewed"
      },
      "bid": {
        "amountUsd": 0.06,
        "unit": "PER_LABEL",
        "labelerHourlyRateUsd": null
      },
      "candidate": {
        "id": "<FREELANCER_ID>",
        "profileSlug": "maria-g",
        "displayName": "Maria G.",
        "firstName": "Maria",
        "lastNameInitial": "G",
        "profileTitle": "Text Annotation Specialist",
        "profilePhotoUrl": "https://app.opentrain.ai/<PHOTO_PATH>",
        "countryCode": "ES",
        "country": "Spain",
        "talentType": "FREELANCER",
        "highestEarningsUsd": 2400,
        "reviewCount": 7
      },
      "metrics": {
        "interviewScore": 86,
        "matchScore": 0.91
      }
    }
  ],
  "nextCursor": null
}