# contractorOps.history.markPaid

Record imported timesheets as paid, for example once the payroll that settled them went out: ids (the historyId of each imported row, up to 500), paidOn (today when omitted; never in the future), an optional transactionId of the bank payment that paid them (money out of an account, and then every row must be the same contractor's; it counts once as money sent even if it's linked to the contractor later), an optional note, and idempotencyKey. Rows already paid are left as they are and counted in alreadyPaid. Oatmilk pay periods aren't marked here; they're paid through their payouts. Importing the table again never marks them unpaid. Audited for each contractor.

`POST /api/v1/accounting/contractorOps.history.markPaid`

Permissions: `accounting:read`, `accounting:write` · Roles: admin, finance · Idempotency key required

MCP tool: `accounting_contractor_ops_history_mark_paid`

## Fields

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `ids` | array of strings (ID) | Yes | 1–500 items. |
| `paidOn` | string (date) |  | A date, as YYYY-MM-DD. |
| `transactionId` | string (ID) or null |  | The ID of a bank or card transaction, from transactions.list. |
| `note` | string |  | A short note, kept with the record. at most 500 characters. |
| `idempotencyKey` | string | Yes | Any unique text you generate once per intended change, so a retried request only happens once. Send it as the Idempotency-Key header instead if you prefer; if you send both they must match. 8–200 characters. |

## Example request

```bash
curl https://app.getoatmilk.com/api/v1/accounting/contractorOps.history.markPaid \
  -H "Authorization: Bearer $OATMILK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "ids": [
    "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
  ]
}'
```

Reference page: https://app.getoatmilk.com/docs/api/contractorOps.history.markPaid
