Skip to main content

Tracker API

Manage tracker projects, work entries, and per-user timers through organization-scoped REST endpoints.

The Tracker API captures billable and non-billable work against clients and projects. It gives the same project, entry, and timer records that Conduitt Tracker uses.

/v1/work/tracker

Use the tracker:read scope for GET requests. Use tracker:write for create, update, delete, start, stop, or discard requests. Conduitt scopes every request to the organization attached to the credential. The API rejects a client, project, entry, or timer identifier from another organization, or returns it as not found.

Projects

MethodEndpointPurpose
GET/projectsList projects with tracked and billable totals
POST/projectsCreate a project
GET/projects/{id}Retrieve one project with all-time totals
PATCH/projects/{id}Update supplied project fields
DELETE/projects/{id}Delete a project but keep its work entries

List Projects

GET /v1/work/tracker/projects

Query parameterTypeNeededDefaultDescription
limitinteger, 1–200No50Maximum projects returned
offsetinteger, 0 or greaterNo0Projects skipped
statusin_progress, completed, or archivedNoFilter by lifecycle status
clientIdUUIDNoFilter by an organization-owned client

Each project includes totalMinutes for all time, billableMinutes for billable work, and totalAmount calculated from entry-level rates. These totals can change when you edit or import entries. Refresh them after a mutation or a completed remote sync.

{
  "data": [
    {
      "id": "a97b0cda-1c68-4fae-b84e-46d4340f63c6",
      "clientId": "74957d67-9132-42b5-9238-b6fe520611d5",
      "name": "Website redesign",
      "code": "WEB-2026",
      "description": "Discovery, design, and implementation",
      "externalRef": null,
      "billingMode": "time_and_materials",
      "billable": true,
      "defaultRate": "175.00",
      "currency": "USD",
      "estimateHours": 80,
      "status": "in_progress",
      "color": "#4F46E5",
      "tags": ["design", "priority"],
      "assignedUserIds": [],
      "totalMinutes": 945,
      "billableMinutes": 870,
      "totalAmount": 2537.5,
      "createdAt": "2026-07-01T13:00:00.000Z",
      "updatedAt": "2026-07-12T14:30:00.000Z"
    }
  ],
  "meta": { "limit": 50, "offset": 0, "total": 1 }
}

Create or Update a Project

Create with POST /v1/work/tracker/projects. Update with PATCH /v1/work/tracker/projects/{id}. A patch must contain at least one field and changes only supplied fields.

FieldTypeNeeded on createDefaultConstraints and behavior
namestringYes1–255 characters; unique within the organization
descriptionstringNoUp to 1,000 characters
clientIdUUID or nullNoMust point to a client in the current organization
codestringNoUp to 50 characters
billablebooleanNofalseDefault billable state inherited by new timers
ratenumberNoNon-negative default hourly rate
currencystringNoUSDThree-character ISO 4217 code
estimateHoursintegerNoZero or greater
statusenumNoin_progressin_progress, completed, or archived
colorstringNoUp to 20 characters
tagsstring arrayNoUp to 20 category names, each 1–50 characters
assignedUserIdsUUID arrayNoUp to 50 assigned users
curl -X POST "https://api.conduitt.io/v1/work/tracker/projects" \
  -H "Authorization: Bearer $CONDUITT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Website redesign",
    "clientId": "74957d67-9132-42b5-9238-b6fe520611d5",
    "billable": true,
    "rate": 175,
    "currency": "USD",
    "tags": ["design", "priority"]
  }'

The API returns rates as decimal strings, such as "175.00", to preserve money precision. Project deletion sets the project link on current work entries to null. It does not erase tracked work.

Work Entries

MethodEndpointPurpose
GET/entriesList native and imported work entries
GET/entries/summaryCalculate billable totals for a date range
POST/entriesCreate a native work entry
GET/entries/{id}Retrieve one work entry
PATCH/entries/{id}Update a work entry
DELETE/entries/{id}Permanently delete a work entry

List Entries

GET /v1/work/tracker/entries

Query parameterTypeNeededDescription
limitinteger, 1–200NoMaximum entries returned; default 50
offsetinteger, 0 or greaterNoEntries skipped; default 0
dateFromYYYY-MM-DDNoInclude entries on or after this UTC date
dateToYYYY-MM-DDNoInclude entries on or before this UTC date
projectIdUUIDNoFilter by project
clientIdUUIDNoFilter by client
sourceenumNoFilter by native_tracker, harvest_api, or another documented work source
billabletrue or falseNoFilter by billing eligibility
qstring, up to 200 charactersNoSearch work descriptions and labels for clients

Responses give normalized billing fields. They omit provider rawPayload, internal deduplication hashes, and extensible metadata.

Create an Entry

POST /v1/work/tracker/entries

FieldTypeNeededDefaultConstraints and behavior
descriptionstringYes1–2,000 characters
durationMinutesintegerYes1–525,600
entryDateYYYY-MM-DDYesCalendar date interpreted in UTC
startTimeHH:mmNoSend it together with endTime
endTimeHH:mmNoSend it together with startTime
billablebooleanNotrueWhether you can invoice the entry
ratenumberNoNon-negative hourly rate
currencystringNoUSDThree-character ISO 4217 code
clientIdUUIDNoMust belong to the current organization
projectIdUUIDNoMust belong to the current organization
{
  "description": "Implemented invoice approval workflow",
  "durationMinutes": 135,
  "entryDate": "2026-07-12",
  "startTime": "09:30",
  "endTime": "11:45",
  "billable": true,
  "rate": 175,
  "currency": "USD",
  "projectId": "a97b0cda-1c68-4fae-b84e-46d4340f63c6"
}

The response includes the server-owned source, billingStatus, quantity, timestamps, and identifiers. quantity and rate are decimal strings. entryDate, startedAt, and endedAt are ISO 8601 timestamps.

For updates, PATCH /entries/{id} accepts the same fields as create, all optional. If you change a date, duration, start, or end time, Conduitt recomputes the related time fields together. Supply both startTime and endTime when you add explicit clock times.

Billable Summary

GET /v1/work/tracker/entries/summary?dateFrom=2026-07-01&dateTo=2026-07-31

You must supply both dates. Both dates are inclusive. The response returns totalMinutes, totalAmount, currency, and a byProject breakdown. Entries without a project appear with projectId: null.

Timers

Timers belong to the authenticated user as well as the organization. One user cannot stop or discard another user's timer.

MethodEndpointPurpose
GET/timer/activeReturn the current user's active timer or null
POST/timer/startStart a timer
POST/timer/{sessionId}/stopStop a timer and optionally create a work entry
POST/timer/{sessionId}/discardDiscard an active timer without an entry
GET/timer/sessionsList the current user's timer history

Start a Timer

{
  "description": "Client discovery call",
  "projectId": "a97b0cda-1c68-4fae-b84e-46d4340f63c6",
  "billable": true
}

description, clientId, projectId, billable, and rate are optional. When you supply a project, the timer inherits its billable setting and default rate. An explicit rate overrides the inherited rate.

Conduitt serializes concurrent start requests. If a timer is already active, the API returns 409 Conflict. Stop or discard the active timer before you retry.

Stop a Timer

POST /v1/work/tracker/timer/{sessionId}/stop

{
  "description": "Client discovery and follow-up notes",
  "billable": true,
  "rate": 175,
  "createWorkEntry": true
}

All fields are optional. createWorkEntry defaults to true. The response contains the stopped session, the created workEntry or null, and durationMinutes rounded to at least one minute.

A stop is duplicate-safe within the timer workflow. A repeated or concurrent stop returns 409 Conflict and does not create a second work entry. Do not retry a timed-out stop blindly. First read /timer/active. Then search entries for the timer's time range.

Timer History

GET /v1/work/tracker/timer/sessions accepts limit, offset, and optional status (running, stopped, or discarded). It returns only sessions owned by the authenticated user.

Errors and Recovery

  • 400 shows an invalid date range, cross-organization link, or malformed business input.
  • 401 shows missing or invalid authentication.
  • 403 shows that the credential lacks tracker:read or tracker:write.
  • 404 hides the difference between a missing record and a record outside the active organization.
  • 409 shows a timer state conflict or another uniqueness conflict.
  • 422 reports Zod validation failures with field paths and constraints.
  • 429 shows a rate limit. Honor Retry-After.

After any ambiguous network failure, read the affected resource before you repeat a mutation. Project names are unique within an organization. General entry creation is not idempotent. The timer stop workflow and the remote-import deduplication workflow are the exceptions.

We use cookies to improve your experience, analyze traffic, and personalize content.