Skip to content

harvest-forecast-py

Python client for the Harvest Forecast API — async and sync, with full coverage

harvest-forecast-py is a fully-typed Python client for the Harvest Forecast API. It covers every resource, mutation, aggregate, and meta endpoint, with both async and sync clients, automatic retry, pagination, and date-windowing handled internally.


Features

  • Full API Coverage


    All resources, mutations, aggregates, and meta endpoints from the Forecast API.

  • Async & Sync Clients


    ForecastClient for async/await code, SyncForecastClient for synchronous code — generated via unasync.

  • Fully Typed


    Pydantic v2 models for all responses, type hints throughout, py.typed marker included.

  • Automatic Retry


    Configurable retry policy with exponential backoff and jitter for transient failures (429, 5xx, network errors).

  • Pagination & Windowing


    Handles Forecast's pagination and the 2520-day assignment date range limit internally.

  • Structured Exceptions


    Typed exception hierarchy mapping HTTP status codes to specific errors.


How it works

┌───────────┐      ┌─────────────────────┐      ┌──────────────┐
│  Your App │ ───▶ │  harvest_forecast   │ ───▶ │ Forecast API │
└───────────┘      └─────────────────────┘      └──────────────┘
                           │                            │
                           │  typed Pydantic models     │
                           │ ◀──────────────────────────┘

Your application calls harvest_forecast client methods, which build authenticated HTTP requests to the Forecast API, handle pagination and date-windowing, retry transient failures, and return fully-typed Pydantic models.


Installation

# with pip
pip install harvest-forecast-py

# with uv
uv add harvest-forecast-py

Python 3.12+

harvest-forecast-py requires Python 3.12 or newer. Runtime dependencies are httpx, pydantic v2, and tenacity.


Quick Start

import asyncio
from harvest_forecast import ForecastClient

async def main() -> None:
    async with ForecastClient(
        access_token="your-personal-access-token",
        account_id="123456",
        user_agent="my-app (you@example.com)",
    ) as client:
        people = await client.list_people()
        for person in people:
            print(person.id, person.first_name, person.last_name)

asyncio.run(main())
from harvest_forecast import SyncForecastClient

with SyncForecastClient(
    access_token="your-personal-access-token",
    account_id="123456",
    user_agent="my-app (you@example.com)",
) as client:
    people = client.list_people()
    for person in people:
        print(person.id, person.first_name, person.last_name)

Next Steps


Disclaimer

This project is unofficial and not affiliated with, endorsed by, or sponsored by Harvest Inc. or its subsidiaries. "Harvest" and "Forecast" are trademarks of their respective owners. This software is provided "as-is", without any warranty express or implied.