curl -sS https://app.opentrain.ai/api/public/v1/proposals/<PROPOSAL_ID> \
-H "Authorization: Bearer $OT_API_TOKEN"
opentrain proposals get --proposal-id <PROPOSAL_ID> --json
{
"proposalId": "<PROPOSAL_ID>"
}
{
"proposal": {
"id": "<PROPOSAL_ID>",
"jobId": "<JOB_ID>",
"jobTitle": "Spanish Sentiment Labeling — Social Media Posts",
"createdAt": "2026-06-11T15:40:00.000Z",
"updatedAt": "2026-06-12T09:05:00.000Z",
"status": {
"raw": "SHORTLISTED",
"label": "Shortlisted"
},
"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
},
"aiInterview": {
"score": 86,
"summary": "Strong grasp of sentiment-labeling edge cases; clear communication; native Spanish speaker with prior social-media annotation experience.",
"transcriptAvailable": true
},
"verification": {
"location": {
"status": "PASSED",
"method": "GPS",
"checkedAt": "2026-06-11T15:38:00.000Z"
},
"identity": {
"verified": true
}
},
"openLabel": null,
"contract": null
}
}
Proposals
Get Proposal
Read one proposal in depth: bid, AI-interview score and summary, location/identity verification, assessment results, and contract state.
GET
/
api
/
public
/
v1
/
proposals
/
{proposalId}
curl -sS https://app.opentrain.ai/api/public/v1/proposals/<PROPOSAL_ID> \
-H "Authorization: Bearer $OT_API_TOKEN"
opentrain proposals get --proposal-id <PROPOSAL_ID> --json
{
"proposalId": "<PROPOSAL_ID>"
}
{
"proposal": {
"id": "<PROPOSAL_ID>",
"jobId": "<JOB_ID>",
"jobTitle": "Spanish Sentiment Labeling — Social Media Posts",
"createdAt": "2026-06-11T15:40:00.000Z",
"updatedAt": "2026-06-12T09:05:00.000Z",
"status": {
"raw": "SHORTLISTED",
"label": "Shortlisted"
},
"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
},
"aiInterview": {
"score": 86,
"summary": "Strong grasp of sentiment-labeling edge cases; clear communication; native Spanish speaker with prior social-media annotation experience.",
"transcriptAvailable": true
},
"verification": {
"location": {
"status": "PASSED",
"method": "GPS",
"checkedAt": "2026-06-11T15:38:00.000Z"
},
"identity": {
"verified": true
}
},
"openLabel": null,
"contract": null
}
}
Reads a single proposal in full — everything from
GET /jobs/{id}/proposals plus the AI-interview block, location/identity verification, labeling-assessment results, and the contract created if you already hired. This is the deep-dive step of the candidate evaluation flow.
Candidate identity stays masked pre-hire (first name + last initial). Resume files, personal emails, phone numbers, and payment details are never returned — see privacy. For the full interview transcript, use GET /proposals/{proposalId}/interview.
Requirements: proposals:read scope. The proposal must be on a job you own (403 otherwise). Works pre-claim.
Request
string
required
The proposal ID, e.g. from the proposals list.
Response
object
Hide proposal
Hide proposal
string
Proposal ID.
string
The job this proposal belongs to.
string
Job title (denormalized for convenience).
string
ISO submission timestamp.
string
ISO last-change timestamp.
object
{raw, label} — machine value (e.g. SHORTLISTED) plus display label.object
{amountUsd, unit, labelerHourlyRateUsd} — the candidate’s asking rate and its unit.object
Privacy-safe candidate summary:
{id, profileSlug, displayName, firstName, lastNameInitial, profileTitle, profilePhotoUrl, countryCode, country, talentType, highestEarningsUsd, reviewCount} — same shape as the proposals list. Use id or profileSlug with GET /freelancers/{idOrSlug} for the full profile.object
{interviewScore, matchScore} — AI-interview score and job-match score, null when not available.object | null
null when the candidate has not taken the AI interview.Show aiInterview
Show aiInterview
number | null
Normalized interview score.
string | null
AI-written summary of the interview.
boolean
true when a transcript exists — fetch it via GET /proposals/{proposalId}/interview.object
object | null
Latest result from OpenTrain’s built-in labeling assessment, when the candidate completed one for this proposal:
{status, score, employerRating, completedAt} (each null-able). null when no assessment exists.object | null
{id, status} with status of ACTIVE or ENDED when you already hired from this proposal — track it via GET /contracts/{id}. null pre-hire.Errors
| Status | code | Meaning |
|---|---|---|
400 | BAD_REQUEST | Missing proposalId |
401 | UNAUTHORIZED | Missing or invalid token |
403 | FORBIDDEN | Missing proposals:read scope, or the proposal is on another account’s job |
404 | NOT_FOUND | No such proposal |
curl -sS https://app.opentrain.ai/api/public/v1/proposals/<PROPOSAL_ID> \
-H "Authorization: Bearer $OT_API_TOKEN"
opentrain proposals get --proposal-id <PROPOSAL_ID> --json
{
"proposalId": "<PROPOSAL_ID>"
}
{
"proposal": {
"id": "<PROPOSAL_ID>",
"jobId": "<JOB_ID>",
"jobTitle": "Spanish Sentiment Labeling — Social Media Posts",
"createdAt": "2026-06-11T15:40:00.000Z",
"updatedAt": "2026-06-12T09:05:00.000Z",
"status": {
"raw": "SHORTLISTED",
"label": "Shortlisted"
},
"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
},
"aiInterview": {
"score": 86,
"summary": "Strong grasp of sentiment-labeling edge cases; clear communication; native Spanish speaker with prior social-media annotation experience.",
"transcriptAvailable": true
},
"verification": {
"location": {
"status": "PASSED",
"method": "GPS",
"checkedAt": "2026-06-11T15:38:00.000Z"
},
"identity": {
"verified": true
}
},
"openLabel": null,
"contract": null
}
}
⌘I