# Time Entries API

The Time Entries API imports, reads, updates, submits, and removes time records. Member subjects are explicitly supported because time records normally belong to a named member.

## Roles

| Operation | Member | Manager | Finance | HR |
|---|---:|---:|---:|---:|
| Read organization time entries | Limited to documented reporting views | Yes | Yes | Yes where permitted |
| Create/update for a member subject | No | Yes | No | No |
| Submit entries | No | Yes | No | No |
| Approve entries | No | No | No | No |

Formal approval decisions remain named-user actions. API Clients may observe approval state through the [Approvals API](approvals.html).

## Time entry object

```json
{
  "object": "time_entry",
  "id": "tim_01J8QB3WRFX0NDCCV87DQ08H0N",
  "member_id": "alice@example.com",
  "project_id": "prj_01J8Q8QFXT2Y3QAD6M0MPB75GC",
  "task_id": "tsk_01J8QA1K7M08W2DVM5RTVZJEF9",
  "work_date": "2026-08-22",
  "minutes": 90,
  "billable": true,
  "notes": "Discovery workshop preparation",
  "status": "draft",
  "external_id": "sf-time-88342",
  "created_at": "2026-08-22T12:15:00Z",
  "updated_at": "2026-08-22T12:15:00Z"
}
```

## List time entries

`GET /v1/time-entries`

Operation ID: `listTimeEntries`

Filters: `member_id`, `project_id`, `task_id`, `work_date_gte`, `work_date_lte`, `status`, `billable`, `external_id`, `limit`, and `after`.

At least one bounded date filter is required for organization-wide queries.

## Create a time entry

`POST /v1/time-entries`

Operation ID: `createTimeEntry`

Required Role: Manager. Required header: `Idempotency-Key`.

```json
{
  "subject": {
    "member_id": "alice@example.com"
  },
  "project_id": "prj_01J8Q8QFXT2Y3QAD6M0MPB75GC",
  "task_id": "tsk_01J8QA1K7M08W2DVM5RTVZJEF9",
  "work_date": "2026-08-22",
  "minutes": 90,
  "billable": true,
  "notes": "Discovery workshop preparation",
  "external_id": "sf-time-88342"
}
```

`external_id` is unique for an API Client and supports source-system reconciliation. The subject member must be active and references must be valid for the work date.

## Bulk import

`POST /v1/time-entries/batches`

Operation ID: `createTimeEntryBatch`

Required Role: Manager. Required header: `Idempotency-Key`. Maximum 100 entries.

The operation validates the entire batch. By default, any invalid entry rejects the batch. `atomic=false` permits partial acceptance and returns one result per item.

## Get and update

- `GET /v1/time-entries/{time_entry_id}` — `getTimeEntry`
- `PATCH /v1/time-entries/{time_entry_id}` — `updateTimeEntry`, Manager, `If-Match`

Only draft or rejected entries are editable unless the configured workflow explicitly reopens them.

## Submit

`POST /v1/time-entries/{time_entry_id}/submit`

Operation ID: `submitTimeEntry`

Required Role: Manager. Required header: `Idempotency-Key`.

Submission creates or updates the appropriate named-user approval request. It does not approve the entry.

## Delete a draft entry

`DELETE /v1/time-entries/{time_entry_id}`

Operation ID: `deleteTimeEntry`

Required Role: Manager. Required header: `Idempotency-Key`. Only draft or rejected entries can be deleted. Deletion is audited and idempotent.

## Common errors

`TIME_ENTRY_NOT_FOUND`, `INVALID_SUBJECT_MEMBER`, `INVALID_WORK_DATE`, `INVALID_DURATION`, `EXTERNAL_ID_CONFLICT`, `TIME_ENTRY_LOCKED`, and `APPROVAL_REQUIRED`.

Next: [Tickets API](tickets.html).
