Back

Step by Step Guide to Building a Harvest API Integration in Python

Aug 15, 20245 minute read

Introduction

Hey there, fellow developer! Ready to dive into the world of Harvest API integration? You're in for a treat. Harvest's API is a powerhouse for time tracking and project management data. In this guide, we'll walk through building a robust integration that'll have you pulling and pushing data like a pro.

Prerequisites

Before we jump in, make sure you've got:

  • A Python environment (3.6+ recommended)
  • requests library installed (pip install requests)
  • Harvest API credentials (we'll cover this in a sec)

Authentication

First things first, let's get you authenticated:

  1. Head to your Harvest account settings
  2. Create a new Personal Access Token
  3. Grab your Account ID from the same page

Now, let's set up those headers:

headers = { 'Harvest-Account-ID': 'YOUR_ACCOUNT_ID', 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'User-Agent': 'Your App Name ([email protected])' }

Basic API Request Structure

Harvest's API is RESTful and pretty straightforward. Here's a quick GET request:

import requests base_url = 'https://api.harvestapp.com/v2/' endpoint = 'time_entries' response = requests.get(f'{base_url}{endpoint}', headers=headers)

Handling Responses

Parsing responses is a breeze:

if response.status_code == 200: data = response.json() # Do something with data else: print(f"Error: {response.status_code}") print(response.text)

Key API Endpoints

You'll probably use these endpoints the most:

  • /time_entries
  • /projects
  • /clients
  • /users

CRUD Operations

Let's create a time entry:

new_entry = { 'project_id': 12345, 'task_id': 6789, 'spent_date': '2023-05-20', 'hours': 2.5, 'notes': 'Worked on API integration' } response = requests.post(f'{base_url}time_entries', headers=headers, json=new_entry)

Reading, updating, and deleting follow similar patterns. Check out the Harvest API docs for specifics.

Pagination and Filtering

Harvest uses cursor-based pagination. Here's how to handle it:

def get_all_entries(): entries = [] url = f'{base_url}time_entries' while url: response = requests.get(url, headers=headers) data = response.json() entries.extend(data['time_entries']) url = data['links']['next'] return entries

For filtering, just add query parameters to your URL.

Rate Limiting

Harvest's pretty generous with rate limits, but it's good practice to handle them:

if 'Retry-After' in response.headers: retry_after = int(response.headers['Retry-After']) time.sleep(retry_after)

Best Practices

  • Log errors comprehensively
  • Cache frequently accessed data
  • Use async requests for heavy operations (check out aiohttp)

Example Use Case

Let's build a quick time tracking report:

from collections import defaultdict def generate_time_report(): entries = get_all_entries() project_times = defaultdict(float) for entry in entries: project_times[entry['project']['name']] += entry['hours'] for project, hours in project_times.items(): print(f"{project}: {hours:.2f} hours") generate_time_report()

Conclusion

And there you have it! You're now equipped to build a solid Harvest API integration. Remember, the API is your oyster - there's so much more you can do with it. Happy coding, and may your time tracking be ever efficient!

For more details, check out the official Harvest API documentation.