Harvest API integration for session-log → time-entry + report pulls — PARKED
DARE.CO.UK · PARKED SKETCH · 2026-05-20
Mirrored from ~/.claude/.../memory/project_harvest_api_integration_parked.md. This is a design sketch parked for future build — read for context, not as a current deliverable.
Dan 2026-05-20 asked if Harvest’s API supports two-way: push dev-session logs into Harvest as time entries (annotated with what we worked on) + pull down reports (revenue, time per project, expense summaries). Yes — Harvest has a documented REST API v2 with personal access tokens. Resume when one of the build triggers fires.
Dan, 2026-05-20:
“can you also make a note to see if the api is open for getharvest.com — we log expenses and time into it, I would love to be able to carry session logs into it for the business, and pull down reports”
Quick answer — yes, the API is open
Harvest publishes REST API v2 with documentation at https://help.getharvest.com/api-v2/ (verified 200 today). Authentication via Personal Access Tokens (or OAuth 2.0 for multi-user apps). Tokens minted at https://id.getharvest.com/developers (verified 200).
Capabilities relevant to Dan’s two asks:
| What Dan wants | Harvest API endpoint |
|---|---|
| Push session logs as time entries | POST /v2/time_entries — date · hours · project_id · task_id · notes (free-text where session log goes) |
| Pull down reports — revenue | GET /v2/reports/uninvoiced + GET /v2/reports/expenses |
| Pull down reports — time per project | GET /v2/reports/time/projects + GET /v2/reports/time/clients |
| Pull expenses for tax/accounting | GET /v2/expenses |
| List projects/tasks to map session work onto | GET /v2/projects + GET /v2/tasks |
The build shape (mirrors gsc_pull.py + would-be ebay_pull.py)
Same shape we’ve now codified as the portfolio-standard API integration pattern:
~/bin/harvest_push.py # converts session report → time entry
├─ reads ~/Downloads/dare_session_report_<date>.md
├─ parses date, total hours, project tag (which client/project the work was for)
├─ POST /v2/time_entries with notes = session-report URL + headline
└─ idempotent — re-running same day updates the entry, doesn't dupe
~/bin/harvest_pull.py # pulls reports → markdown
├─ GET /v2/reports/uninvoiced (revenue accrued, not yet invoiced)
├─ GET /v2/reports/time/projects (week + month + quarter rollups)
├─ GET /v2/expenses (recent expense entries with receipts)
└─ writes ~/Downloads/harvest_pull_<date>.md
# Optional Phase B:
~/bin/harvest_session_link.sh # appended to dare_session_report → auto-push
Credentials
Harvest auth needs:
- Personal Access Token — minted at id.getharvest.com/developers (Dan does this once, takes ~1 min)
- Account ID — shown alongside the token on the same page
- Both stored in 1Password as custom-named concealed fields per feedback_1password_custom_concealed_fields.md:
- Suggested item name: Harvest API
- Custom fields: account_id (concealed) + personal_access_token (concealed)
- References: op://Code Shared/Harvest API/account_id + op://Code Shared/Harvest API/personal_access_token
No OAuth dance needed for personal tokens — simpler than GSC or eBay setup.
Cost
| Item | Cost |
|---|---|
| Harvest account | Dan’s existing subscription (already paying — this is just adding the API surface) |
| API calls | $0 within rate limits |
| Rate limit | 100 requests / 15-second window per account — way more than enough |
| Marginal cost | $0 |
Build estimate (when triggered)
| Step | Effort | Notes |
|---|---|---|
| 1. Personal access token + 1Password storage | 5 min | Dan does it |
2. harvest_pull.py — basic reports pull |
60 min | Test against live, no sandbox needed |
3. harvest_push.py — session-log → time entry |
75 min | Project/task mapping needs a small lookup table (which dare/audrey/etc project = which Harvest project) |
| 4. Wire into existing session-report chain | 20 min | Optional auto-trigger after dare_session_report.py finishes |
Total: ~2.5 hours for full bidirectional integration.
Compelling angle — bidirectional value
Most portfolio API integrations are one-way (pull data into the toolkit). Harvest is rare in that it’s bidirectional and the push side has unique leverage:
- Push direction (logs → time entries): session reports already capture WHAT was done, WHEN, and HOW LONG. Currently that lives in dev-reports + memory + git history. Pushing into Harvest means the same information becomes billable / invoiceable / categorisable for the business — zero extra effort, full traceability back to the source session report.
- Pull direction (reports → markdown): monthly/quarterly revenue rollups become surfaceable in the same dev-reports catalog where session work lives. The link between “we did this” and “we earned that” becomes visible alongside everything else.
The downstream effect: the time-tracking step (Harvest) stops being a separate ritual Dan has to remember; it becomes automatic when the session report renders. The data already exists; Harvest just becomes its accounting interface.
Resume conditions (build when ANY hold)
- Dan complains about manual Harvest time-entry overhead — same friction signal as the eBay sketch
- A client engagement starts that needs detailed time logging — auto-push of session reports as time entries becomes load-bearing
- Tax-time approaches and Dan wants automated expense + time rollups in the catalog
- The eBay integration ships first — Harvest then becomes the second instance of the OAuth-pull-render template (eBay being the first), so cost-per-additional-integration drops
Skip / defer if
- Manual Harvest entry remains low-friction (it’s a fast UI; not all API integrations beat the UI for occasional users)
- Dan prefers to keep dev-reports (project work) and Harvest (billable time) deliberately separated — they may be different abstractions worth keeping disjoint
Sibling memories
project_ebay_seller_api_integration_parked.md— same shape (parked OAuth-pull-render scaffold); building either lifts the template for the otherfeedback_1password_custom_concealed_fields.md— token storage discipline (Harvest API/personal_access_token)feedback_test_links_before_shipping.md— the Harvest API docs URLs were HEAD-checked before this memo was written (all 4 returned 200)feedback_check_devreports_before_infra_gap_analysis.md— when resuming, check~/bin/harvest_*+~/Downloads/harvest_pull_*firstfeedback_toolkit_as_storytelling_substrate.md— pushing session reports into Harvest makes them part of the financial compounding substrate too, not just the editorial one
The aphorism
The session report already knows what we did. Harvest just needs to know how long. The integration is the bridge, not the source.