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
The proposal ID, e.g. from the proposals list.
Response
Hide proposal
Hide proposal
Proposal ID.
The job this proposal belongs to.
Job title (denormalized for convenience).
ISO submission timestamp.
ISO last-change timestamp.
{raw, label} — machine value (e.g. SHORTLISTED) plus display label.{amountUsd, unit, labelerHourlyRateUsd} — the candidate’s asking rate and its unit.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.{interviewScore, matchScore} — AI-interview score and job-match score, null when not available.null when the candidate has not taken the AI interview.Show aiInterview
Show aiInterview
Normalized interview score.
AI-written summary of the interview.
true when a transcript exists — fetch it via GET /proposals/{proposalId}/interview.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.{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