This tool syncs time entries from one Harvest account (source agency) to another Harvest account (contractor company) for specified employees. Features a modern web dashboard with billing period selection, duplicate detection, and activity history.
Disclaimer: This application is an independent, unofficial project and is not affiliated with, endorsed, or sponsored by Harvest. Harvest is a registered trademark of its respective owner.
- AI Agent Primer - Comprehensive project overview, architecture, and development guide for AI agents
- Harvest API v2 Reference - Complete Harvest API v2 documentation with endpoints, examples, and best practices
When contractors work for an agency but need to track their time in both the agency's Harvest account (for the agency's records) and their own company's Harvest account (for invoicing), this script automates the process of copying time entries between the two accounts.
-
Install dependencies:
npm install
-
Configure environment variables:
Copy
.env.exampleto.envand fill in your Harvest credentials:cp .env.example .env
Then edit
.envand add:AGENCY_HARVEST_TOKEN- Personal Access Token for the source agency's Harvest accountAGENCY_HARVEST_ACCOUNT_ID- Source agency's Harvest Account IDCONTRACTOR_HARVEST_TOKEN- Personal Access Token for your company's Harvest accountCONTRACTOR_HARVEST_ACCOUNT_ID- Your company's Harvest Account IDAGENCY_NAME- Name of the source agency (for display purposes)CONTRACTOR_NAME- Name of your company (for display purposes)EMPLOYEE_1_NAME- Full name of first employee to sync (e.g., "John Doe")EMPLOYEE_2_NAME- Full name of second employee to sync (optional)
-
Personal Access Token and Account ID:
- Log into your Harvest account
- Click on your profile picture in the top right corner
- Select "Developers" from the dropdown menu
- Click "Create New Personal Access Token"
- Give it a name (e.g., "Harvest Sync Tool")
- Copy both the Token and the Account ID that are displayed together on this page
- Important: Both values are shown on the same page when you create the token
-
Test your connection:
Before running the sync, test that your credentials are working:
npm testThis will verify that both Harvest accounts are accessible with the provided credentials.
The easiest way to use Harvest Sync is through the web dashboard:
npm startThis will:
- Start the web server on port 8118
- Automatically open your browser to http://localhost:8118
- Provide a visual interface for previewing and syncing time entries
Dashboard Features:
- Multi-Page Navigation: Dashboard, History, and Settings pages
- Connection Status: See if both Harvest accounts are connected
- Billing Period Selection: Choose Year, Month, and Half (Full Month, First Half 1st-15th, Second Half 16th-end)
- Sync All Time Option: Checkbox to sync all entries from 2000-01-01 to today
- Preview with Duplicate Detection: Shows accurate status (Pending vs Duplicate) before syncing
- Hours by Worker: Summary cards showing total hours per employee for selected period
- Line Items Table: Detailed view with project codes, task names, hours (hh:mm format), and status badges
- Activity History: Clickable history items to review past operations
- Settings Page: Configure API credentials, target users, and display preferences
- Results Display: See detailed summaries with Created vs Duplicate status
You can also use the command line scripts directly:
Before syncing any data, use preview mode to generate an HTML report showing exactly what will be synced:
# Preview last 7 days (default)
npm run preview
# Preview specific date range
node syncAgencyToDestination-preview.js 2025-01-01 2025-01-31
# Preview a single day
node syncAgencyToDestination-preview.js 2025-01-15 2025-01-15This will generate an HTML file (e.g., sync-preview-2025-01-15T10-30-45.html) that you can open in your browser. The report shows:
- Summary of total entries, hours, and projects
- Which projects will be created vs. already exist
- Which tasks are new
- All time entries grouped by user and project
- Detailed breakdown of what will happen when you run the actual sync
Review the HTML report carefully before running the actual sync!
node syncAgencyToDestination.js [FROM_DATE] [TO_DATE]Examples:
# Sync last 7 days (default if no dates provided)
npm run sync
# Sync specific date range
node syncAgencyToDestination.js 2025-01-01 2025-01-31
# Sync a single day
node syncAgencyToDestination.js 2025-01-15 2025-01-15Dates should be in YYYY-MM-DD format.
- Fetches users from both source and contractor Harvest accounts
- Identifies the configured employees in both accounts
- Retrieves time entries from the source agency for the specified date range
- Fetches existing entries from contractor account for duplicate detection
- For each time entry:
- Checks if the project exists in the contractor account (matches by code if available, otherwise by name)
- Checks if the task exists in the contractor account
- Compares against existing contractor entries to detect duplicates
- Marks as "Pending" (will be synced) or "Duplicate" (already exists)
- Returns detailed preview with accurate status for each entry
- Fetches users from both source and contractor Harvest accounts
- Identifies the configured employees in both accounts
- Retrieves time entries from the source agency for the specified date range
- For each time entry:
- Checks if the project exists in the contractor account
- If not, creates the project
- Ensures the task exists in the contractor account
- Assigns the task to the project
- Assigns the user to the project
- Attempts to create the time entry in the contractor account
- If entry already exists (422 error), marks as "Duplicate" and skips
- Otherwise marks as "Created"
- Returns summary with final status for each entry
- The tool will not delete or modify existing time entries
- Preview mode checks for duplicates before syncing and shows accurate status
- Sync mode automatically skips duplicate entries (same user, project, task, date, hours, notes)
- Projects are matched by code if available, otherwise by name
- Projects are created with default settings (billable by project, no budget)
- Tasks are created as billable by default
- The tool processes only time entries for the employees configured in
.env - Time is displayed in hh:mm format (e.g., 1:08 for 1 hour 8 minutes)
- Check that your Personal Access Tokens are correct
- Make sure the tokens haven't expired
- Your account may not have sufficient permissions
- You need Administrator or Manager access to create projects and time entries
- Make sure the configured employees exist in both Harvest accounts
- Check that their names match exactly (first name + last name) in both accounts
- Harvest allows 100 requests per 15 seconds
- The script includes basic error handling but may need to be run again if rate limited
- Consider adding delays between requests if you encounter rate limiting
The main script is syncAgencyToDestination.js. Key functions:
harvestRequest()- Makes authenticated requests to Harvest APIgetAgencyTimeEntries()- Fetches time entries from source agencycreateContractorProject()- Creates a new project in contractor accountensureTaskExists()- Creates a task if it doesn't existcreateContractorTimeEntry()- Creates a time entry in contractor accountsyncTimeEntries()- Main orchestration function
The preview script is syncAgencyToDestination-preview.js which generates HTML reports without writing data.
Preview report styles are managed using SCSS:
- Edit styles: Modify
assets/styles/preview-report.scss - Compile CSS: Run
npm run build:cssto compile SCSS to CSS - Watch mode: Run
npm run watch:cssfor automatic compilation during development - Generated files: Compiled CSS is saved to
assets/styles/preview-report.css
The preview script automatically loads the compiled CSS when generating HTML reports.
