- How do I install and configure spatie/laravel-harvest-sdk in a Laravel app?
- Install it with Composer using composer require spatie/laravel-harvest-sdk, then publish the config file with php artisan vendor:publish --tag="laravel-harvest-sdk-config". Add HARVEST_ACCOUNT_ID, HARVEST_ACCESS_TOKEN, and HARVEST_USER_AGENT to your .env file, then resolve the client with app(Harvest::class) or the Harvest facade. In production, inject those values through your secrets manager rather than committing them to a .env file.
- Which Harvest API endpoints does this Laravel SDK actually cover?
- The README describes it as a partial implementation rather than a complete Harvest client. Documented usage centers on the authenticated user lookup via users()->me(), user listing, project listing, and paginated time entries with from, to, and userId filters, returning typed DTOs such as UserData, ProjectData, and TimeEntryData. Invoices, estimates, expenses, tasks, roles, webhooks, and custom reporting are not documented as covered, so validate each roadmap item against the actual source before committing to it. Pull requests for missing endpoints are explicitly welcome.
- What Laravel and PHP versions does spatie/laravel-harvest-sdk support?
- Release 2.1.0 added Laravel 13 support, which is a healthy lifecycle signal for a small package. Check the PHP and Laravel constraints in the package's composer.json rather than inferring them from the README or release notes, and confirm that combination is exercised in the GitHub Actions test workflow. Pin an exact version in composer.json and treat minor upgrades as reviewable changes so a framework bump never surprises you mid-sprint.
- Does this SDK handle Harvest OAuth token refresh, or does it use a personal access token?
- Configuration is built around a static HARVEST_ACCOUNT_ID and HARVEST_ACCESS_TOKEN pair, which matches a long-lived personal access token workflow. OAuth authorization and token refresh are not described in the available documentation, so assume you own the refresh lifecycle until a spike proves otherwise. If your integration must ship as a multi-tenant OAuth app, plan to manage token storage, expiry, and refresh outside the package and inject a fresh token per request.
- How do I fetch Harvest time entries with date and user filters in Laravel?
- Time entries are exposed through the Harvest client resolved from the container or facade, and the documented filters include from, to, and userId with paginated results mapped to TimeEntryData objects. Resolve the client in a dedicated service class, pass the date range and user identifier explicitly, and convert the DTOs into your own domain objects at that boundary. Also confirm how pagination terminates on your account size, because silent truncation of a collect() call is the most common surprise with thin API wrappers.
- Should I call the Harvest facade directly from controllers, jobs, and services?
- No, keep the SDK behind an internal HarvestGateway or repository interface that declares only the methods your product actually needs. Calling Spatie\Harvest classes directly spreads a low-adoption third-party dependency through your domain code and makes replacement expensive. With a gateway in place, the SDK becomes a replaceable implementation detail and swapping it later is a single class change plus a container binding.
- How do I call Harvest endpoints the SDK does not support yet?
- Add a raw HTTP adapter for the uncovered endpoints and route it through the same HarvestGateway interface as the SDK-backed implementation. That keeps fallback calls authenticated, observable, and version-pinned alongside the rest of your Harvest traffic. Instrument fallback usage with telemetry so you can see how much of your integration sits outside the package, and contribute the missing endpoint upstream if it stabilizes.
- Does the SDK handle Harvest rate limits, retries, and pagination errors?
- The available documentation does not describe rate-limit handling, retry or backoff behavior, or how pagination failures are surfaced. Treat those as your responsibility: wrap the gateway with a retry and backoff policy sized to Harvest's documented limits, and verify with a spike whether partial failures throw or silently truncate results. Until proven otherwise, assume errors are not swallowed and add explicit assertions in your contract tests.
- How do I test code that uses spatie/laravel-harvest-sdk?
- Test your own HarvestGateway implementation rather than the package internals, and bind a fake or stub implementation of that interface in your test container so feature tests never hit the Harvest API. For the adapter itself, write contract tests against representative Harvest payloads, including the is_running field added in 1.0.1 and similar DTO evolutions, so payload shape changes fail loudly. Note that the package is lightly battle-tested, so your own recorded fixtures are more trustworthy than assumptions about response structure.
- What are the alternatives to spatie/laravel-harvest-sdk, and how hard is it to replace?
- The main alternatives are building a thin client on Saloon or Laravel's HTTP client against the official Harvest API docs, which gives you full endpoint coverage and explicit control over auth, retries, and pagination. This package's value is Laravel-native glue: container binding, a facade, publishable config, and typed DTOs that remove hand-rolled array mapping. Because of its partial coverage and low adoption, limit the blast radius by pinning the version and hiding it behind an interface, so an exit costs you one gateway class rather than a refactor.