Remote Tracker API
Connect Harvest, preview remote work, check mappings, and import confirmed entries while provider credentials stay hidden.
The Remote Tracker API connects an organization to Harvest through a personal access token. Synchronization is a reviewed two-step flow: preview remote entries first, then confirm the rows and mappings you want to import.
/v1/work/tracker/harvestEvery endpoint needs the dedicated tracker:remote scope. This keeps provider credentials and remote-import authority separate from ordinary tracker:read and tracker:write access.
Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
GET | /harvest | Read safe connection and sync status |
POST | /harvest/connect | Validate and store Harvest credentials |
PATCH | /harvest/settings | Configure scheduled sync |
DELETE | /harvest | Remove credentials and sync configuration |
POST | /harvest/sync/preview | Fetch, normalize, deduplicate, and map remote entries |
POST | /harvest/sync/confirm | Import reviewed preview rows |
GET | /harvest/sync/history | List completed and failed Harvest import jobs |
Credential Boundary
Harvest accessToken is write-only. The connect endpoint accepts it, but status, settings, history, preview, and confirmation responses never return it. Responses also omit refresh tokens, provider payloads, internal hashes, and stored connection metadata.
Keep Harvest credentials in a server-side secret manager. Do not place them in browser storage, URLs, analytics events, error trackers, or application logs.
Connect Harvest
POST /v1/work/tracker/harvest/connect
| Field | Type | Needed | Description |
|---|---|---|---|
accessToken | non-empty string | Yes | Harvest personal access token; accepted once and never returned |
accountId | string, 1–100 characters | Yes | Harvest account identifier associated with the token |
curl -X POST "https://api.conduitt.io/v1/work/tracker/harvest/connect" \
-H "Authorization: Bearer $CONDUITT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accessToken": "${HARVEST_ACCESS_TOKEN}",
"accountId": "${HARVEST_ACCOUNT_ID}"
}'Conduitt calls Harvest to validate the credential before it stores the credential. Invalid credentials return 400 and do not echo the token.
{
"data": {
"connected": true,
"accountName": "Northwind Advisory",
"lastSyncAt": null,
"lastSyncStatus": "idle",
"lastSyncEntriesImported": 0,
"syncEnabled": false,
"syncIntervalMinutes": 60
}
}When no connection exists, status returns:
{ "data": { "connected": false } }Configure Scheduled Sync
PATCH /v1/work/tracker/harvest/settings
{
"syncEnabled": true,
"syncIntervalMinutes": 60
}You must send syncEnabled. syncIntervalMinutes is optional and must be an integer from 15 to 1,440. The response uses the same safe connection shape as the status endpoint.
Preview Remote Work
POST /v1/work/tracker/harvest/sync/preview
{
"dateFrom": "2026-07-01",
"dateTo": "2026-07-12"
}Both fields are optional YYYY-MM-DD dates. If you omit them, Conduitt requests the most recent 30 days. When you send both, dateFrom must not be later than dateTo.
Preview does not create work entries. It returns:
| Field | Description |
|---|---|
provider | Always harvest_api for this integration |
totalEntries | Entries returned by Harvest |
newEntries | Rows whose import hash is not already stored |
duplicateEntries | Rows already present for this organization and source |
rows | Normalized work rows available for review |
unmappedClients | Harvest client names without a confident Conduitt match |
unmappedProjects | Harvest project names without a confident Conduitt match |
clientMapping | Proposed map from the remote name to the Conduitt client UUID |
projectMapping | Proposed map from the remote name to the tracker project UUID |
dateRange | Effective from and to dates sent to Harvest |
Each normalized row has this shape:
{
"date": "2026-07-10",
"durationMinutes": 90,
"description": "Invoice approval workflow",
"project": "Website redesign",
"client": "Northwind Advisory",
"billable": true,
"rate": 175,
"currency": "USD",
"user": "Ada Lovelace",
"externalId": "41820519"
}Check unmappedClients, unmappedProjects, billable state, rates, and descriptions before confirmation. A preview is point-in-time. Run it again if you delay the review or if native tracker data changes.
Confirm an Import
POST /v1/work/tracker/harvest/sync/confirm
Send the reviewed rows plus optional corrected mappings. A request can contain up to 10,000 rows.
{
"rows": [
{
"date": "2026-07-10",
"durationMinutes": 90,
"description": "Invoice approval workflow",
"project": "Website redesign",
"client": "Northwind Advisory",
"billable": true,
"rate": 175,
"currency": "USD",
"user": "Ada Lovelace",
"externalId": "41820519"
}
],
"clientMapping": {
"Northwind Advisory": "74957d67-9132-42b5-9238-b6fe520611d5"
},
"projectMapping": {
"Website redesign": "a97b0cda-1c68-4fae-b84e-46d4340f63c6"
}
}The clientMapping and projectMapping values can be a UUID or null. Conduitt revalidates every non-null UUID against the active organization at confirmation time. A caller therefore cannot link imported work to another organization's client or project.
{
"data": {
"importJobId": "2745108d-2a9a-4bd8-9df4-e92a4dfcd0d9",
"importedCount": 1,
"skippedCount": 0
}
}Import hashes are unique per organization and source. If you confirm rows again that Conduitt already stored, it skips them and does not create duplicates. Use the returned counts and the sync history. Do not assume that Conduitt inserted every row you sent.
Sync History
GET /v1/work/tracker/harvest/sync/history?limit=50&offset=0
History returns status, row counts, start and completion timestamps, and audit identifiers. It omits credentials, row payloads, mappings, validation details, and internal error text.
{
"data": [
{
"id": "2745108d-2a9a-4bd8-9df4-e92a4dfcd0d9",
"status": "imported",
"rowCountTotal": 12,
"rowCountValid": 10,
"rowCountInvalid": 0,
"rowCountDeduped": 2,
"startedAt": "2026-07-12T14:00:00.000Z",
"completedAt": "2026-07-12T14:00:02.000Z",
"createdAt": "2026-07-12T14:00:00.000Z",
"updatedAt": "2026-07-12T14:00:02.000Z"
}
],
"meta": { "limit": 50, "offset": 0, "total": 1 }
}Disconnect Harvest
DELETE /v1/work/tracker/harvest
Disconnect removes the stored credential and sync settings. Previously imported work entries and history remain available for billing and audit continuity.
Failure and Retry Behavior
- A missing connection returns
404for settings, preview, confirm, or disconnect. - Invalid Harvest credentials return
400during connect. - Invalid dates, rows, or cross-organization mappings return
400or422before import. - Harvest network or service failures can return
5xx. Retry preview with backoff because it has no write side effect. - Do not blindly retry confirmation after a timeout. Check sync history and list entries first. Duplicate hash detection makes replay safe for unchanged rows, but Conduitt still recommends a review step.
- A failed confirmation marks its import job
failed. It does not leave the job inprocessing.