The Harvest V2 API is a REST API that allows you to interact with your Harvest account programmatically. You can track time, log expenses, create projects, and more.

API Requests

Harvest requires applications to authenticate all requests with OAuth2 or Personal Access Tokens. The following HTTP methods are supported:

  • GET
  • POST

When issuing a GET request, parameters should be included in the URL query string:

curl https://api.harvestapp.com/v2/tasks?page=2&per_page=10 \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "User-Agent: MyApp (yourname@example.com)"

When issuing a POST or PATCH request, parameters should be included in the request body. Request parameters can either be formatted in JSON or submitted as form data. When submitting request parameters as JSON, you must pass application/json in the Content-Type header.

We also require that each request include a User-Agent header with both:

  • The name of your application
  • A link to your application or email address

We use this information to get in touch if you’re doing something wrong (so we can warn you before you’re blocked) or something awesome (so we can congratulate you). Here are examples of acceptable User-Agent headers:

  • User-Agent: Trello (http://trello.com/contact)
  • User-Agent: John's Harvest Integration (john@example.com)

If you don’t include a User-Agent header, you’ll get a 400 Bad Request response.


curl -X POST https://api.harvestapp.com/v2/tasks \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "User-Agent: MyApp (yourname@example.com)" \
  -H "Content-Type: application/json" \
  -d "{\"name\":\"My New Task\"}"

Form data

curl -X POST https://api.harvestapp.com/v2/tasks \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "User-Agent: MyApp (yourname@example.com)" \
  -d name="My New Task"

API Responses

Harvest formats response bodies in JSON and uses HTTP response codes to indicate the success or failure of an API request. The following are the HTTP status codes that you may encounter when using the API along with a brief explanation of when they occur.

Code Explanation
200 Your request was successful.
201 A new object has been created. Its representation will be returned in the response body.
403 The object you requested was found but you don’t have authorization to perform your request.
404 The object you requested can’t be found.
422 There were errors processing your request. Check the response body for additional information.
429 Your request has been throttled. Refer to the Rate Limiting section for details.
500 There was a server error. Contact support@getharvest.com for help.

Rate Limiting

We have an API throttle that blocks accounts that exceed our API rate limits. We reserve the right to tune the limitations, but they are always set high enough to allow a well-behaving interactive program to do its job.

  • The rate limit for general API requests is 100 requests per 15 seconds.
  • The rate limit for Reports API requests is 100 requests per 15 minutes.

For batch processes and API developers who still need to perfect their code, this throttle may be an inadvertent blocker. Just wait a bit, and try again. Since the throttle is reset with each call, the throttle will lift itself in a few minutes and API calls may resume.

When the rate limit is exceeded Harvest will send an HTTP 429 status code. The number of seconds until the throttle is lifted is sent via the Retry-After HTTP header, as specified in RFC 2616.

Please remember to write your application carefully, caching when possible. In case of abuse you may be blocked, disallowing further API access.


When you encounter a value surrounded by curly braces, you should replace it with a value appropriate to your context. For example, if your Harvest project’s ID is 1234 and the documentation provides the following URL:


you would replace the {PROJECT_ID} with the actual project ID, like so:


We also make use of shell variables in our example requests (e.g. $ACCESS_TOKEN). If your operating system supports shell variables, you can set shell variables like this:

USER_AGENT="MyApp (yourname@example.com)"

Then, you can reference them by prefixing them with a $:

curl -X POST https://api.harvestapp.com/v2/company \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "User-Agent: $USER_AGENT"

This should allow you to copy/paste most of the example requests without needing to change anything aside from IDs.

Data Types

Type Example Description
boolean true Either true or false.
string "foo" A double-quoted sequence of characters.
integer 42 A non-negative integer value.
decimal 6.8 A decimal value. The supported precision is field-dependent.
date "2017-12-31" An ISO 8601 formatted string containing just the date portion.
datetime "2017-12-31T14:59:22Z" An ISO 8601 formatted string containing a UTC date and time.
time "14:59"
A string containing a 12-hour or 24-hour time depending on the Time Format configured for your account. You can check this on the Settings page in your Harvest account or the clock attribute the Company API.
array [ 1, 2, 3 ] A JSON array.
object { name: "value" } A JSON object.

Still have questions? We’re happy to help!

Contact Us