> ## Documentation Index
> Fetch the complete documentation index at: https://opentrain.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Report Usage

> Report cumulative per-worker, per-day work totals (time, tasks, labels) on a linked contract. Idempotent upserts — re-POSTing never double counts.

Reports work done on your platform against an OpenTrain contract. Entries are **cumulative per-worker, per-day totals**: each entry replaces the stored totals for its (worker, `workDate`), so re-POSTing the same report — or a corrected one — is idempotent and never double counts. Fields omitted from an entry keep their previously stored values.

The response includes the recomputed [budget](/docs/developers/annotation-platforms/api-reference/contracts/budget). Crossing the 80% / 100% consumption thresholds emits [`milestone.budget_low` / `milestone.budget_depleted`](/docs/developers/annotation-platforms/usage-sync#the-depletion-events) webhooks.

**Requirements:** `usage:write` scope, and the contract's job must be referenced by a [project link](/docs/developers/annotation-platforms/project-links) on the calling token's install.

## Request

<ParamField path="contractId" type="string" required>
  The OpenTrain contract to attribute usage to.
</ParamField>

<ParamField body="entries" type="object[]" required>
  1–100 usage entries. One entry per (worker, day).

  <Expandable title="Entry fields">
    <ParamField body="workDate" type="string" required>
      Calendar day the work happened, as `YYYY-MM-DD` (UTC). Cannot be in the future.
    </ParamField>

    <ParamField body="workerOpentrainUserId" type="string">
      OpenTrain user ID of the worker. Defaults to the contract's hired AI trainer; if provided, it must match a participant on the contract.
    </ParamField>

    <ParamField body="totalSeconds" type="number">
      Cumulative seconds worked that day, 0–86400. Consumes budget on `PAY_PER_HOUR` contracts (hours = seconds / 3600).
    </ParamField>

    <ParamField body="tasksCompleted" type="integer">
      Cumulative tasks completed that day. Non-negative. Informational on all payment types.
    </ParamField>

    <ParamField body="labelsCompleted" type="integer">
      Cumulative labels completed that day. Non-negative. Consumes budget on `PAY_PER_LABEL` contracts.
    </ParamField>

    <ParamField body="externalReportId" type="string">
      Your report identifier for audit, max 200 characters.
    </ParamField>
  </Expandable>
</ParamField>

## Response

<ResponseField name="contractId" type="string">
  The contract the usage was recorded against.
</ResponseField>

<ResponseField name="accepted" type="integer">
  Number of entries upserted.
</ResponseField>

<ResponseField name="budget" type="object">
  The recomputed budget — same shape as [`GET /contracts/{contractId}/budget`](/docs/developers/annotation-platforms/api-reference/contracts/budget#response).
</ResponseField>

## Errors

| Status | `code`         | Meaning                                                                                                                                                                                        |
| ------ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `BAD_REQUEST`  | Invalid entries: missing/malformed `workDate`, future date, `totalSeconds` out of range, negative counts, more than 100 entries, or `workerOpentrainUserId` not a participant on this contract |
| `401`  | `UNAUTHORIZED` | Missing, invalid, or revoked token                                                                                                                                                             |
| `403`  | `FORBIDDEN`    | Token lacks `usage:write`                                                                                                                                                                      |
| `404`  | `NOT_FOUND`    | Contract not found, or its job is not linked by this install                                                                                                                                   |
| `409`  | `CONFLICT`     | Contract has no hired AI trainer to attribute usage to                                                                                                                                         |

<RequestExample>
  ```bash curl theme={null}
  curl -sS -X POST "https://app.opentrain.ai/api/partner/v1/contracts/<CONTRACT_ID>/usage" \
    -H "Authorization: Bearer $OT_PARTNER_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "entries": [
        {
          "workDate": "2026-06-12",
          "totalSeconds": 14400,
          "tasksCompleted": 52,
          "labelsCompleted": 410,
          "externalReportId": "daily-report-8841"
        }
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "contractId": "<CONTRACT_ID>",
    "accepted": 1,
    "budget": {
      "contractId": "<CONTRACT_ID>",
      "paymentType": "PAY_PER_HOUR",
      "state": "OK",
      "fundedVolume": 40,
      "fundedAmountUsd": 560,
      "consumed": { "seconds": 100800, "hours": 28, "labels": 410, "tasks": 52 },
      "consumedVolume": 28,
      "remainingVolume": 12,
      "consumedFraction": 0.7,
      "activeMilestone": {
        "id": "<MILESTONE_ID>",
        "name": "Week 2",
        "amountUsd": 280,
        "volume": 20,
        "status": "ACTIVE_FUNDED"
      },
      "lastUsageAt": "2026-06-12T18:00:00.000Z"
    }
  }
  ```
</ResponseExample>
