Permissions
The permission object
| Attribute | Type | Description |
|---|---|---|
id |
integer | Unique ID for the permission. Use this ID in permission_ids when creating or updating a custom role or when replacing a user’s direct permissions. |
name |
string | The permission’s resource:action:scope claim, a stable machine key. |
label |
string | Human-readable label for the permission, matching the wording used in the web app. Falls back to name when no label is defined; never blank. Not localized. |
created_at |
datetime | Date and time the permission was created. Use the ISO 8601 Format. |
updated_at |
datetime | Date and time the permission was last updated. Use the ISO 8601 Format. |
Required permissions
The account must have custom profiles enabled. You must have permission to manage all users in order to interact with the /v2/permissions endpoint. Insufficient permissions will result in a 403 Forbidden status code.
List all permissions
Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes
Harvest-Api-Stability: beta.
Returns the account’s permission catalogue, sorted by ascending ID. The catalogue is the set of permissions the account can grant, and Forecast permissions are excluded.
The response contains an object with a permissions property that contains an array of up to per_page permission objects. Each entry in the array is a separate permission object. If no more permissions are available, the resulting array will be empty. Several additional pagination properties are included in the response to simplify paginating your permissions.
The claim strings are the same as the permissions_claims array returned for a user, except that this catalogue excludes Forecast permissions and, on an account without Time Off, omits pto:* claims that permissions_claims can still list.
GET /v2/permissions
| Parameter | Type | Description |
|---|---|---|
updated_since |
datetime | Only return permissions whose updated_at is later than this timestamp. A blank value is ignored. |
cursor |
string | A cursor from a previous response’s links or next_page value. Takes precedence over page. |
page |
integer | The page number to use in pagination. Omitting this parameter, or passing 1, uses cursor-based pagination. |
per_page |
integer | The number of records to return per page. Can range between 1 and 2000. (Default: 2000) |
Omitting page, passing page=1, or passing an explicit cursor uses cursor-based pagination. Page-number mode begins at page=2. The first cursor page reports page as 1 and a next_page; middle cursor pages report null for page, next_page, and previous_page; the last cursor page reports the total page count and a previous page. Both modes return the same ordered list.
Example Request:
curl "https://api.harvestapp.com/v2/permissions" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "User-Agent: MyApp ([email protected])"
Example Response:
{
"permissions": [
{
"id": 3,
"name": "timers:write:own",
"label": "Log and edit their own time",
"created_at": "2026-01-05T09:00:00Z",
"updated_at": "2026-01-05T09:00:00Z"
},
{
"id": 7,
"name": "projects:read:all",
"label": "View all projects across the account",
"created_at": "2026-01-05T09:00:00Z",
"updated_at": "2026-01-05T09:00:00Z"
}
],
"per_page": 2000,
"total_pages": 1,
"total_entries": 54,
"next_page": null,
"previous_page": null,
"page": 1,
"links": {
"first": "https://api.harvestapp.com/v2/permissions?page=1&per_page=2000&ref=first",
"next": null,
"previous": null,
"last": "https://api.harvestapp.com/v2/permissions?page=1&per_page=2000&ref=last"
}
}Errors
The following status codes are returned for the permission catalogue endpoint:
| Status | Description |
|---|---|
400 |
A malformed page, per_page, or updated_since value: Invalid page parameter: …, Invalid per_page parameter: …, or Invalid updated_since datetime provided: …. |
401 |
Missing or invalid credentials. |
403 |
The account is inactive (Account inactive), the account does not have custom profiles enabled (Custom profiles feature is not enabled for this account), or the caller is not authorized (Not authorized!). |
422 |
An empty or malformed cursor: Invalid cursor parameter …. |
500 |
An unexpected error occurred. |