curl -sS "https://app.opentrain.ai/api/public/v1/contracts?status=active" \
-H "Authorization: Bearer $OT_API_TOKEN"
opentrain contracts list --status active --json
{
"status": "active"
}
{
"contracts": [
{
"id": "<CONTRACT_ID>",
"status": "active",
"title": "Spanish Sentiment Labeling Contract",
"jobId": "<JOB_ID>",
"proposalId": "<PROPOSAL_ID>",
"paymentType": "FIXED_PRICE",
"rateUsd": 300,
"estimatedTotalUsd": 300,
"estimatedVolume": null,
"hasActiveMilestone": true,
"startDate": "2026-06-12T09:30:00.000Z",
"endDate": null,
"createdAt": "2026-06-12T09:30:00.000Z",
"updatedAt": "2026-06-12T09:30:00.000Z",
"freelancer": {
"userId": "<FREELANCER_ID>",
"displayName": "Maria G.",
"country": "Spain",
"profilePath": "/profile/maria-g"
},
"milestones": [
{
"id": "<MILESTONE_ID>",
"name": "First labeling batch",
"description": "Label the first 5,000 posts per the guidelines",
"status": "ACTIVE_FUNDED",
"amountUsd": 300,
"volume": null,
"milestoneNumber": 1,
"dueDate": "2026-07-01T00:00:00.000Z",
"pendingApproval": false,
"needsReview": false,
"invoiceId": "<INVOICE_ID>",
"createdAt": "2026-06-12T09:30:00.000Z"
}
]
}
]
}
Contracts
List Contracts
List your contracts (hired AI trainers) with milestones, optionally filtered by job or status.
GET
/
api
/
public
/
v1
/
contracts
curl -sS "https://app.opentrain.ai/api/public/v1/contracts?status=active" \
-H "Authorization: Bearer $OT_API_TOKEN"
opentrain contracts list --status active --json
{
"status": "active"
}
{
"contracts": [
{
"id": "<CONTRACT_ID>",
"status": "active",
"title": "Spanish Sentiment Labeling Contract",
"jobId": "<JOB_ID>",
"proposalId": "<PROPOSAL_ID>",
"paymentType": "FIXED_PRICE",
"rateUsd": 300,
"estimatedTotalUsd": 300,
"estimatedVolume": null,
"hasActiveMilestone": true,
"startDate": "2026-06-12T09:30:00.000Z",
"endDate": null,
"createdAt": "2026-06-12T09:30:00.000Z",
"updatedAt": "2026-06-12T09:30:00.000Z",
"freelancer": {
"userId": "<FREELANCER_ID>",
"displayName": "Maria G.",
"country": "Spain",
"profilePath": "/profile/maria-g"
},
"milestones": [
{
"id": "<MILESTONE_ID>",
"name": "First labeling batch",
"description": "Label the first 5,000 posts per the guidelines",
"status": "ACTIVE_FUNDED",
"amountUsd": 300,
"volume": null,
"milestoneNumber": 1,
"dueDate": "2026-07-01T00:00:00.000Z",
"pendingApproval": false,
"needsReview": false,
"invoiceId": "<INVOICE_ID>",
"createdAt": "2026-06-12T09:30:00.000Z"
}
]
}
]
}
Lists the contracts on your account — one per hired AI trainer per job — newest first, each with its milestone timeline. Contracts are created by hiring from a proposal. The AI trainer’s identity stays masked: first name + last initial, country, and profile path (never a full last name or an email — see privacy).
Refunded and cancelled milestones are excluded from the milestone timeline, mirroring the in-app contract view. For the post-hire conversation ID, read a single contract with
GET /contracts/{id}.
Requirements: payments:read scope. Works pre-claim.
Request
Only return contracts on this job. Must be a job you own or can access (
403 otherwise; 404 if the job doesn’t exist).Filter by contract status:
active or ended. Omit to list both.Response
Show contract entry
Show contract entry
Contract ID — use with
GET /contracts/{id}, POST /contracts/{id}/milestones, and POST /contracts/{id}/end.active or ended.Contract display title.
The job this contract belongs to.
The proposal the hire came from.
Payment model:
FIXED_PRICE, PAY_PER_HOUR, or PAY_PER_LABEL.Contract rate in USD (per hour / per label for per-unit contracts; total for fixed-price).
Estimated total contract value in USD.
Estimated unit volume for per-unit contracts.
true when the contract currently has a funded, in-progress milestone.ISO contract start timestamp.
ISO contract end timestamp,
null while active.ISO creation timestamp.
ISO last-change timestamp.
The hired AI trainer:
{userId, displayName, country, profilePath}. displayName is masked to first name + last initial ("Maria G."); full last names and emails are never included.Milestone timeline, ordered by milestone number.
Show milestone entry
Show milestone entry
Milestone ID — use with
POST /milestones/{id}/fund and POST /milestones/{id}/approve.Short milestone name.
Work to deliver.
NOT_FUNDED, ACTIVE_FUNDED, or COMPLETED.Milestone amount in USD.
Unit volume for per-unit milestones.
Position in the contract’s milestone sequence.
ISO due date.
true when the AI trainer has submitted work and the milestone awaits your approval.true when the milestone is flagged for review.Linked invoice once funded/paid.
ISO creation timestamp.
Errors
| Status | code | Meaning |
|---|---|---|
400 | BAD_REQUEST | status is not active or ended (details: {field: "status"}) |
401 | UNAUTHORIZED | Missing or invalid token |
403 | FORBIDDEN | Missing payments:read scope, or jobId belongs to another account |
404 | NOT_FOUND | jobId does not exist |
curl -sS "https://app.opentrain.ai/api/public/v1/contracts?status=active" \
-H "Authorization: Bearer $OT_API_TOKEN"
opentrain contracts list --status active --json
{
"status": "active"
}
{
"contracts": [
{
"id": "<CONTRACT_ID>",
"status": "active",
"title": "Spanish Sentiment Labeling Contract",
"jobId": "<JOB_ID>",
"proposalId": "<PROPOSAL_ID>",
"paymentType": "FIXED_PRICE",
"rateUsd": 300,
"estimatedTotalUsd": 300,
"estimatedVolume": null,
"hasActiveMilestone": true,
"startDate": "2026-06-12T09:30:00.000Z",
"endDate": null,
"createdAt": "2026-06-12T09:30:00.000Z",
"updatedAt": "2026-06-12T09:30:00.000Z",
"freelancer": {
"userId": "<FREELANCER_ID>",
"displayName": "Maria G.",
"country": "Spain",
"profilePath": "/profile/maria-g"
},
"milestones": [
{
"id": "<MILESTONE_ID>",
"name": "First labeling batch",
"description": "Label the first 5,000 posts per the guidelines",
"status": "ACTIVE_FUNDED",
"amountUsd": 300,
"volume": null,
"milestoneNumber": 1,
"dueDate": "2026-07-01T00:00:00.000Z",
"pendingApproval": false,
"needsReview": false,
"invoiceId": "<INVOICE_ID>",
"createdAt": "2026-06-12T09:30:00.000Z"
}
]
}
]
}
⌘I