Gusto Sync Runs

The sync run object

A sync run posts Harvest time entries to Gusto for a date range or a Gusto payroll. It is created by creating a sync run and read by retrieving a sync run.

Attribute Type Description
id integer Unique ID for the sync run.
status string Status of the run: queued, running, completed, completed_with_errors, or failed.
run_type string The run type, always time_sheet.
date_range_start date First day of the inclusive date range.
date_range_end date Last day of the inclusive date range.
gusto_payroll_uuid string The source Gusto payroll’s UUID, or null.
workweek_anchor string The FLSA workweek start day recorded when the run was queued.
initiated_by_user_id integer The ID of the user who created the run, or null.
created_at datetime Date and time the run was created.
started_at datetime Date and time the run started, or null until it starts.
completed_at datetime Date and time the run completed, or null until it completes.
terminal_error_message string The error that ended the run, or null.
created_count integer Number of entries posted.
skipped_count integer Number of entries skipped because there was nothing to do or they were held.
error_count integer Number of entries that failed in Gusto.

The counts report the run’s latest recorded outcome for each entry.

The sync preview object

A preview reports the entries that a sync run would post, without creating the run.

Attribute Type Description
date_range_start date First day of the inclusive date range, from the sent dates or the payroll’s period.
date_range_end date Last day of the inclusive date range, from the sent dates or the payroll’s period.
gusto_payroll_uuid string The source Gusto payroll’s UUID, or null.
locked_filtered_count integer Number of entries dropped because their Gusto pay period is locked.
api_errors array Messages from upstream Gusto reads that failed. Empty when every read succeeds.
projects array Teammate and project groups with the entries that would sync.

Each projects entry contains:

Attribute Type Description
user_mapping_id integer The user mapping to select when creating the run.
user_id integer The Harvest teammate’s ID.
project_id integer The project to select when creating the run.
dominant_state string The group’s state: syncable, all_synced, all_deleted_needs_delete, all_exempt, all_owner, all_contractor_not_hourly, all_flsa_unverified, all_flsa_conflict, or mixed.
entry_count integer Number of the group’s entries a sync would post, update, or delete.
total_hours decimal Total hours across those entries.
state_counts object Number of entries per state, counting every entry in the group: syncable, already_synced, edited, deleted_needs_delete, data_error, exempt, owner, contractor_not_hourly, flsa_unverified, and flsa_conflict.
job_required boolean true when creating the run needs a gusto_job_uuid for this group.
suggested_job_uuid string The suggested Gusto job for the group, or null.
available_jobs array The group’s available Gusto jobs: each entry has a uuid and a title.

suggested_job_uuid is the job already posted for the group, or the only available job, or null.

Required permissions

Managing Gusto sync runs requires permission to write company settings. Callers without it receive a 403 Forbidden status code with Not authorized!.

The Gusto integration must be enabled for the account. Accounts without it receive a 403 Forbidden status code with Gusto integration is not enabled for this account.

Every request must include OAuth2 bearer, personal access token, or basic auth credentials and a User-Agent header. Requests with a body require a JSON Content-Type.

Retrieving a sync run does not require an active Gusto connection. Previewing and creating one do.

Preview a sync run

Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes Harvest-Api-Stability: beta.

Previews a time-sheet sync for a date range or a Gusto payroll. Returns a sync preview object and a 200 OK response code. This request does not create a run.

POST /v2/integrations/gusto/sync_runs/preview
Parameter Type Description
gusto_payroll_uuid string Optional. Selects a Gusto payroll. When present, the payroll’s period determines the range and the sent dates do not set it. A blank or non-string value, or a payroll without a pay period, returns 422.
date_range_start date Optional. First day of the inclusive range, as an ISO-8601 date. Defaults to six days before today.
date_range_end date Optional. Last day of the inclusive range, as an ISO-8601 date. Defaults to today.

A malformed date, a start date after the end date, or a range longer than 90 days returns 422.

Example Request:

curl -X POST "https://api.harvestapp.com/v2/integrations/gusto/sync_runs/preview" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyApp ([email protected])" \
  -d '{"date_range_start": "2026-10-13", "date_range_end": "2026-10-19"}'

Example Response:

{
  "date_range_start": "2026-10-13",
  "date_range_end": "2026-10-19",
  "gusto_payroll_uuid": null,
  "locked_filtered_count": 0,
  "api_errors": [],
  "projects": [
    {
      "user_mapping_id": 7001,
      "user_id": 1782959,
      "project_id": 14308069,
      "dominant_state": "syncable",
      "entry_count": 3,
      "total_hours": 12.5,
      "state_counts": {
        "syncable": 3,
        "already_synced": 0,
        "edited": 0,
        "deleted_needs_delete": 0,
        "data_error": 0,
        "exempt": 0,
        "owner": 0,
        "contractor_not_hourly": 0,
        "flsa_unverified": 0,
        "flsa_conflict": 0
      },
      "job_required": true,
      "suggested_job_uuid": "9f8e7d6c-5b4a-3928-1706-e5f4d3c2b1a0",
      "available_jobs": [
        {
          "uuid": "9f8e7d6c-5b4a-3928-1706-e5f4d3c2b1a0",
          "title": "Designer"
        }
      ]
    }
  ]
}

Create a sync run

Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes Harvest-Api-Stability: beta.

Creates and queues a time-sheet sync run for a date range or a Gusto payroll. Returns a sync run object, a 201 Created response code, and a Location header pointing to the run.

POST /v2/integrations/gusto/sync_runs
Parameter Type Description
gusto_payroll_uuid string Optional. Selects a Gusto payroll. When present, the payroll’s period determines the range and the sent dates do not set it. A blank or non-string value, or a payroll without a pay period, returns 422.
date_range_start date Optional. First day of the inclusive range, as an ISO-8601 date. Defaults to six days before today.
date_range_end date Optional. Last day of the inclusive range, as an ISO-8601 date. Defaults to today.
projects array Required. A non-empty array with one object per teammate and project pair. Duplicate pairs are reduced to the first occurrence.
projects[].user_mapping_id integer Required. The user mapping for the pair, as a JSON integer or a string of decimal digits.
projects[].project_id integer Required. The project for the pair, as a JSON integer or a string of decimal digits.
projects[].gusto_job_uuid string Optional. The Gusto job to post the pair’s entries to. Required for an eligible employee pair that has jobs, except when the pair only needs a delete.

An invalid date range returns 422. An array element that is not an object, a non-integer user_mapping_id or project_id, or a non-string gusto_job_uuid returns an indexed 422. Pairs that are not eligible in the range, or have no entries left to sync, return one 422 listing every such pair. A missing gusto_job_uuid where one is required returns 422 with Pick a Gusto Job for every selected project. A gusto_job_uuid is not checked against the pair’s available jobs when the run is created: an unknown job is accepted, and its entries are reported as skipped when the run processes them. Creating a run while another run is active returns 409 with A Gusto time-sync run is already in progress.

Example Request:

curl -X POST "https://api.harvestapp.com/v2/integrations/gusto/sync_runs" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyApp ([email protected])" \
  -d '{"date_range_start": "2026-10-13", "date_range_end": "2026-10-19", "projects": [{"user_mapping_id": 7001, "project_id": 14308069, "gusto_job_uuid": "9f8e7d6c-5b4a-3928-1706-e5f4d3c2b1a0"}]}'

Example Response:

{
  "id": 4201,
  "status": "queued",
  "run_type": "time_sheet",
  "date_range_start": "2026-10-13",
  "date_range_end": "2026-10-19",
  "gusto_payroll_uuid": null,
  "workweek_anchor": "Sunday",
  "initiated_by_user_id": 1782884,
  "created_at": "2026-10-19T14:30:00Z",
  "started_at": null,
  "completed_at": null,
  "terminal_error_message": null,
  "created_count": 0,
  "skipped_count": 0,
  "error_count": 0
}

Retrieve a sync run

Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes Harvest-Api-Stability: beta.

Retrieves an existing sync run. Returns a sync run object and a 200 OK response code.

GET /v2/integrations/gusto/sync_runs/{SYNC_RUN_ID}

This request takes no parameters.

Example Request:

curl "https://api.harvestapp.com/v2/integrations/gusto/sync_runs/4201" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "User-Agent: MyApp ([email protected])"

Example Response:

{
  "id": 4201,
  "status": "completed",
  "run_type": "time_sheet",
  "date_range_start": "2026-10-13",
  "date_range_end": "2026-10-19",
  "gusto_payroll_uuid": null,
  "workweek_anchor": "Sunday",
  "initiated_by_user_id": 1782884,
  "created_at": "2026-10-19T14:30:00Z",
  "started_at": "2026-10-19T14:30:05Z",
  "completed_at": "2026-10-19T14:30:41Z",
  "terminal_error_message": null,
  "created_count": 3,
  "skipped_count": 0,
  "error_count": 0
}

Errors

The Gusto sync run endpoints return the following status codes:

Status Description
401 Credentials are missing or invalid.
403 The Gusto integration is not enabled for the account (Gusto integration is not enabled for this account), or the caller cannot write company settings (Not authorized!).
404 The sync run does not exist or belongs to another company.
409 The account has no active Gusto connection (Connect Gusto before …), or another time-sheet sync run is active (A Gusto time-sync run is already in progress.).
422 A date range, Gusto payroll, or project selection is invalid. This includes a range longer than 90 days, a payroll without a pay period, a malformed projects element (indexed), ineligible pairs (listed in one message), and a missing required Gusto job.
502 The Gusto connection must be reconnected (Reconnect Gusto before …), or a Gusto read failed (We couldn’t finish …: <upstream message>).
503 Gusto is rate-limiting requests (Gusto is rate-limiting us right now…).

Still have questions? We’re happy to help!

Contact Us