Intervals → FreshBooks Time Entry Sync
Copy weekly time entries from Intervals to FreshBooks.
Reading from Intervals: Browser automation via MCP chrome-devtools
Writing to FreshBooks: API via scripts/freshbooks-api.sh
Prerequisites
- •Chrome/Chromium running with
--remote-debugging-port=9222 - •Intervals weekly timesheet open:
https://bhi.intervalsonline.com/time/ - •chrome-devtools MCP server configured
- •FreshBooks API credentials configured in
~/.config/freshbooks/credentials.json
Workflow
Phase 1: Verify Prerequisites
- •Call
list_pagesto find Intervals browser tab - •Find Intervals tab (URL contains
intervalsonline.com/time/) - •If missing, inform user and stop
Phase 2: Read from Intervals
- •Select the Intervals tab using
select_page - •Run
scripts/read-intervals.jsusingevaluate_script - •Display the entries to user for review
The script reads from the summary table which has this structure:
- •
td.col-timesheet-clientprojectcontains "Client\nProject" - •Following cells contain: Billable, Mon, Tue, Wed, Thu, Fri, Sat, Sun, Total
Output format:
{
success: true,
week: "January 05, 2026",
entries: [
{ client: "Technomic", project: "Ignite App...", billable: true,
hours: { mon: 7.5, tue: 4.5, wed: 4.5, thu: 0, fri: 4.5, sat: 0, sun: 0 },
totalHours: 21 }
],
grandTotal: 47.75
}
Phase 3: Map Entries
For each Intervals entry, determine the FreshBooks destination:
- •Client is always required for invoicing (defaults to "EXSquared")
- •Project is optional - use when work is for a specific project
- •If unmapped, ask user for the FreshBooks mapping
- •Update
references/project-mappings.mdwith new mappings
Mapping examples:
| Intervals Client | Intervals Project | FB Client | FB Project |
|---|---|---|---|
| Technomic | Ignite App... | EXSquared | Technomic |
| EWG - Neuron | Feature Enhancement | EXSquared | EWG |
| EX Squared Services | Meeting | EXSquared | (none) |
| EX Squared Services | Biz Dev / Sales | EXSquared | (none) |
Phase 4: Create FreshBooks Time Entries via API
Use scripts/freshbooks-api.sh to create time entries:
# List available projects and clients ./scripts/freshbooks-api.sh projects ./scripts/freshbooks-api.sh clients # Create a time entry ./scripts/freshbooks-api.sh create-time-entry \ --project "<name>" | --client "<name>" \ --date <YYYY-MM-DD> \ --hours <hours> \ [--note "<note>"]
For each Intervals entry with hours on a given day:
- •Check mapping type (project or client)
- •Call
create-time-entryfor each day with hours > 0 - •Include a note (e.g., the Intervals project name or work type)
Examples:
# With project (client defaults to EXSquared) ./scripts/freshbooks-api.sh create-time-entry \ --project "Technomic" \ --date "2026-01-06" \ --hours 7.5 \ --note "Development" # Client only - no project (e.g., internal meetings) ./scripts/freshbooks-api.sh create-time-entry \ --date "2026-01-06" \ --hours 1.0 \ --note "Meeting" # Different client (rare) ./scripts/freshbooks-api.sh create-time-entry \ --client "Rocksauce Studios" \ --date "2026-01-06" \ --hours 1.0
Phase 5: Verify
- •
List created entries:
bash./scripts/freshbooks-api.sh list-time-entries --from "2026-01-05" --to "2026-01-11"
- •
Display summary of entries created
- •
Open or refresh FreshBooks in the browser for visual review:
- •Use
list_pagesto find FreshBooks tab - •If found:
select_pagethennavigate_pagewithtype: "reload" - •If not found:
new_pagewith FreshBooks week URL
codeURL format: https://my.freshbooks.com/#/time-tracking/week?week=YYYY-MM-DD (where YYYY-MM-DD is the Monday of the week)
- •Use
Scripts
read-intervals.js
Reads the Intervals weekly summary table. No configuration needed.
Run via evaluate_script - returns structured entry data.
freshbooks-api.sh
Shell script for FreshBooks API operations. Supports 1Password op:// references in credentials.
Commands:
- •
projects- List all FreshBooks projects - •
clients- List all FreshBooks clients - •
project-id <name>- Get project ID by name - •
client-id <name>- Get client ID by name - •
create-time-entry- Create a time entry- •
--client, -c <name>- FreshBooks client (default: EXSquared) - •
--project, -p <name>- FreshBooks project (optional) - •
--date, -d <YYYY-MM-DD>- Date of the entry (required) - •
--hours, -h <hours>- Hours worked (required) - •
--note, -n <note>- Description (optional)
- •
- •
list-time-entries- List time entries- •
--from, -f <YYYY-MM-DD>- Start date - •
--to, -t <YYYY-MM-DD>- End date
- •
Credentials: ~/.config/freshbooks/credentials.json
{
"client_id": "op://Private/Freshbooks API/username",
"client_secret": "op://Private/Freshbooks API/credential",
"redirect_uri": "https://localhost/callback"
}
First-time setup:
./scripts/freshbooks-oauth.sh authorize # Get auth URL ./scripts/freshbooks-oauth.sh exchange <code> # Exchange code for tokens ./scripts/freshbooks-oauth.sh me # Test connection
Key Technical Details
Intervals Summary Table
- •Rows:
trcontainingtd.col-timesheet-clientproject - •Client/Project cell: text split by
\n(Client first, Project second) - •Hour cells follow: index 2-8 for Mon-Sun, index 9 for Total
FreshBooks API
Time Entry endpoint: POST /timetracking/business/{business_id}/time_entries
Payload:
{
"time_entry": {
"is_logged": true,
"duration": 27000,
"note": "Development",
"started_at": "2026-01-06T09:00:00.000Z",
"project_id": 12447219,
"identity_id": 123456
}
}
- •
durationis in seconds (7.5 hours = 27000 seconds) - •
started_atis the date of the entry - •
project_idis looked up by project name - •
identity_idis the user's FreshBooks identity
Hour Format
- •Intervals: decimal hours (e.g., "7.5")
- •API: seconds (multiply by 3600)
Common Issues
- •
Project not found: Run
./scripts/freshbooks-api.sh projectsto see available project names. - •
Token expired: The script auto-refreshes tokens, but if it fails, run
./scripts/freshbooks-oauth.sh refresh. - •
Week mismatch: Make sure you're reading the correct week from Intervals.
- •
1Password CLI: If using
op://references, ensure you're signed in (op signin).