Skip to main content
GET
/
api
/
public
/
v1
/
contracts
curl -sS "https://app.opentrain.ai/api/public/v1/contracts?status=active" \
  -H "Authorization: Bearer $OT_API_TOKEN"
{
  "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

jobId
string
Only return contracts on this job. Must be a job you own or can access (403 otherwise; 404 if the job doesn’t exist).
status
string
Filter by contract status: active or ended. Omit to list both.

Response

contracts
object[]

Errors

StatuscodeMeaning
400BAD_REQUESTstatus is not active or ended (details: {field: "status"})
401UNAUTHORIZEDMissing or invalid token
403FORBIDDENMissing payments:read scope, or jobId belongs to another account
404NOT_FOUNDjobId does not exist
curl -sS "https://app.opentrain.ai/api/public/v1/contracts?status=active" \
  -H "Authorization: Bearer $OT_API_TOKEN"
{
  "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"
        }
      ]
    }
  ]
}