Zoho Projects provides a comprehensive set of REST APIs to manage your projects, connect third party applications, and transfer or retrieve data from Zoho Projects.
API Root Endpoint
https://projects.zoho.comZoho Projects APIs require a mandatory header.
Authorization: The OAuth access token to authenticate the user accessing data.
Example
$ curl -X GET https://projects.zoho.com/api/v3/portal/{portal_id}/tasks
-H "Authorization: Bearer 1000.03xxxxxxxxxxxxxxxxxa5317.dxxxxxxxxxxxxxxxxxfa"Version-3 (V3) builds on the existing Zoho Projects API by introducing a more consistent structure across endpoints and extending support for common integration needs. Updates to areas like date formats, filtering, custom fields, and pagination make it easier to work with data in a predictable way. In this section, you'll find what's new in v3, what has been updated, and what to review when moving from v2.
V3 API - Quick Example
GET /api/v3/portal/{portal_id}/projects
Authorization: Bearer {token}Response
{
"page_info": {
"page": 1,
"per_page": 100,
"page_count": 100,
"has_next_page": true
},
"projects": [...]
}V3 introduces a more consistent and structured way to work with the Zoho Projects API. It simplifies how data is formatted, how requests are constructed, and how responses are handled, making integrations easier to build and maintain. These updates also bring more clarity when working with filters, custom fields, and large datasets.
V3 Improvements at a Glance
// 1. Dates → ISO 8601
"due_date": "2024-05-26T00:00:00.000Z"
// 2. Filtering → one request
"filter": {
"criteria": [
{
"field_name": "status",
"criteria_condition": "all_open"
}
],
"pattern": "1"
}
// 3. Custom fields → api_name
"cf_priority_level": "High"
// 4. Request = Response
"assignee": { "zpuid": "...", "name": "John Doe" }
// 5. Pagination → page-based
"page_info": {
"page": 1,
"per_page": 100,
"page_count": 100,
"has_next_page": true
}All date and time values follow a single ISO 8601 format across endpoints. This ensures consistent parsing and removes the need to handle multiple formats.
| Type | V2 | V3 |
|---|---|---|
| Date only | "05-26-2014" (MM-DD-YYYY) |
"2024-05-26" (YYYY-MM-DD) |
| Datetime | "05-13-2014 05:57 PM" (12-hour) |
"2024-05-26T11:25:58.000Z" (ISO 8601) |
| Human-readable | "May 26, 2014" |
removed |
| Epoch | 1399620397255 |
removed |
| Date input format | MM-DD-YYYY |
YYYY-MM-DD |
The *_long epoch fields are removed. ISO 8601 timestamps are universally parseable.
You can define multiple conditions within a single request using a structured filter object. Filtering is processed entirely on the server, so only relevant records are returned.
- Supported conditions:
isis_notcontainsstarts_withbeforeafteris_emptyis_not_emptybetween
- Pattern logic: Combine conditions using
AND,OR, and grouping - e.g."(1 OR 2) AND 3" - Custom field support: Use the
api_nameof any custom field as the criteriafield_name
For the complete syntax reference, see the Filter Guide.
Advanced Filter - Overdue & Assigned
{
"filter": {
"criteria": [
{
"field_name": "due_date",
"criteria_condition": "today"
},
{
"field_name": "assignee",
"criteria_condition": "is",
"value": ["user_zpuid"]
}
],
"pattern": "1 AND 2"
}
}Custom fields now use clear and consistent api_name values. This makes it easier to reference them across requests, filters, and responses without additional mapping.
| V2 | V3 | |
|---|---|---|
| In requests | UDF_CHAR1, UDF_LONG2 |
expected_date, priority_level |
| In responses | Same UDF_ keys, no context | Same api_name, consistent everywhere |
- Stable references - field identifiers don't shift when other fields are added or removed
- Works everywhere - same
api_namein requests, responses, and filter criteria
For full details, see Custom Fields.
V3 Custom Field in Response
{
"expected_date": "2024-05-26"
}V3 Custom Field in Filter
{
"criteria": [
{
"field_name": "expected_date",
"criteria_condition": "is",
"value": ["2024-05-26"]
}
]
}The same field structure is used in both requests and responses. This improves predictability and reduces the need for transformation logic when handling API data.
| Aspect | V2 /restapi | V3 /api/v3 |
|---|---|---|
| Content Type | application/x-www-form-urlencoded | application/json |
| Body Style | Flat, form-encoded parameters | JSON body, nested objects |
| Dates | Mixed formats (MM-DD-YYYY, epoch, text) | ISO 8601 everywhere |
| Related Data | Flat fields (person_responsible, assignee_name) | Grouped objects (assignee, status) |
| List Responses | No pagination metadata | page_info block with has_next_page |
V3 Request (JSON)
POST /api/v3/portal/{portal_id}/projects/{project_id}/tasks
Content-Type: application/json
{
"name": "Task Name",
"assignee": { "zpuid": "user_id" },
"due_date": "2024-05-26",
"priority": "High"
}V3 Response
{
"page_info": {
"page": 1,
"per_page": 100,
"page_count": 100,
"has_next_page": true
},
"tasks": [
{
"id": "12345",
"name": "Task Name",
"due_date": "2024-05-26T00:00:00.000Z",
"assignee": {
"zpuid": "...",
"name": "John Doe",
"email": "..."
},
"status": {
"id": "...",
"name": "Open",
"color": "#...",
"is_closed_type": false
}
}
]
}Pagination is now page-based, making it easier to work with large datasets.
- Use page and per_page to control results
- has_next_page indicates if more records are available
- Avoids duplicate or skipped records
- No need for manual offset calculations
For full details and examples, see Pagination.
All endpoints in v3 follow a consistent URL pattern. The base URL is simplified and standardized, and trailing slashes are no longer required. This makes it easier to construct and predict endpoint URLs across the API.
| V2 | V3 | |
|---|---|---|
| Base URL | /restapi/portal/{portal_id}/projects/ | /api/v3/portal/{portal_id}/projects |
| Trailing slashes | Some endpoints require trailing / |
No trailing slashes |
| Operation | V2 | V3 |
|---|---|---|
| List tasks | GET /restapi/portal/{portal_id}/projects/{project_id}/tasks/ | GET /api/v3/portal/{portal_id}/projects/{project_id}/tasks |
- If you're migrating from V2, update all endpoint URLs - the
/restapi/prefix is replaced with/api/v3/.
| Area | V2 (/restapi) | V3 (/api/v3) |
|---|---|---|
| URL Pattern | /restapi/portals/ | /api/v3/portals |
| Date Format | "05-26-2014" or "May 26, 2014" or 1399620397255 |
"2024-05-26" (date only) or "2024-05-26T11:25:58.000Z" (ISO 8601) |
| Pagination | index + range (offset-based) |
page + per_page with has_next_page |
| HTTP Method for Updates | POST | PATCH |
| Custom Fields | UDF_ prefix (e.g. UDF_CHAR1) |
api_name (e.g. "expected_date") |
| Request / Response Schema | Fields sent in requests often differed from response field names | Request and response use the same field structure throughout |
| API Coverage | Limited modules and endpoints | Additional modules and endpoints, significantly expanding the overall API surface area |
V3 Update Task Example
PATCH /api/v3/portal/{portal_id}/projects/{project_id}/tasks/{task_id}
Content-Type: application/json
{
"assignee": {
"zpuid": "user_id"
},
"due_date": "2024-05-26",
"cf_priority_level": "High"
}Zoho Projects currently supports the following methods.
Zoho Projects uses HTTP status codes to indicate success or failure of API calls. Status codes 2xx indicate success, 4xx indicate error in the information provided, and 5xx indicate server side errors. The following table lists some commonly used HTTP status codes.
| Status Code | Description |
|---|---|
| 200 | OK |
| 201 | Created |
| 202 | Accepted |
| 204 | No content |
| 206 | Partial Data |
| 207 | Multi-status |
| 400 | Bad request |
| 401 | Unauthorized |
| 402 | Payment Required |
| 403 | Forbidden (Unauthorised access) |
| 405 | Method not allowed (Method called is not supported for the API invoked) |
| 409 | Conflict |
| 429 | Too Many Requests |
| 500 | Internal error |
| 501 | Not Supported |
Besides HTTP status codes and their corresponding error messages, error responses for Zoho Projects APIs also include a machine-parsable errorCode param to simplify error handling.
The different errorCodes and their uses are described below
Please check if the URL you are trying to access is correct.
Resolution: The request URL specified is incorrect. Specify a valid request URL.
URL_RULE_NOT_CONFIGURED
This errorCode appears if the OAuthToken is invalid or has expired.
Resolution: Regenerate OAuthToken and try again.
INVALID_OAUTHTOKEN
The HTTP request specified has an invalid input parameter.
Resolution: The request URL input parameter specified is incorrect. Specify a valid request input parameter URL.
INVALID_INPUTSTREAM
The http request method type is not a valid one
Resolution: You have specified an invalid HTTP method to access the API URL. Specify a valid request method.
INVALID_METHOD
The HTTP request specified has an invalid parameter value.
Resolution: The request URL input parameter value specified is incorrect. Specify a valid request input parameter value.
INVALID_PARAMETER_VALUE
Server encountered an unexpected error. Contact
Resolution: support@zohoprojects.com
INTERNAL_SERVER_ERROR
Zoho Projects APIs are governed by rate limits to ensure fair usage and optimal performance of all users.
- Each API can be invoked up to 200 times within a 2-minute window.
- The limit is applied per API endpoint.
Each API response includes the following headers to help you monitor your usage:
RateLimit: Total allowed requests in the current window (e.g., 200).RateLimit-Remaining: Remaining requests available in the current window.RateLimit-Window: Duration of the rate limit window (e.g., 120 seconds).RateLimit-Window-Unit: Time unit for the rate limit window (e.g., seconds).Retry-After: Time (in seconds) to wait before retrying the request after the rate limit has been exceeded.
Retry-After key is returned only when the rate limit has been exceeded.
If the number of requests exceeds the allowed limit:
- The specific API will be temporarily blocked for 10 minutes.
- During this period, all further requests to that API will fail.
- A
Retry-Afterheader will be included in the response, indicating the remaining time (in seconds) before the API becomes available again.
- The restriction applies only to the API that exceeds the limit, not all APIs.
- After the 10-minute cooldown, the API will become available automatically.
- Continuous violations may impact application performance and reliability.
To avoid hitting rate limits:
- Implement retry mechanisms using the
Retry-Afterheader. - Use exponential backoff instead of immediate retries.
- Avoid sending unnecessary or duplicate requests.
- Use batch APIs (if available) to reduce the number of calls.
- Cache frequently used data whenever possible.
Request
GET /api/v3/portal/{portal_id}/projectsRate Limit Info
RateLimit = 200
RateLimit-Remaining = 199
RateLimit-Window = 120
RateLimit-Window-Unit = seconds
Retry-After = 540 (seconds remaining)v3 uses page-based pagination on all list endpoints. Pass page and per_page as query parameters to control which page of results is returned.
| Parameter | Type | Description |
|---|---|---|
page |
Integer | Page number (starting from 1). Defaults to 1 if omitted. |
per_page |
Integer | Number of records per page. Defaults to 100 if omitted. Supported values: 1-200. |
Every list response includes a page_info block. The has_next_page flag tells your client precisely when to stop fetching — no offset calculations, no risk of duplicate or skipped records.
| Field | Type | Description |
|---|---|---|
page |
Integer | Current page number |
per_page |
Integer | Records per page |
page_count |
Integer | Total number of records in the result set |
has_next_page |
Boolean | true if more pages exist, false if this is the last page |
Request
GET /api/v3/portal/{portal_id}/projects/{project_id}/tasks?page=2&per_page=50page_info Response
{
"page_info": {
"page": 2,
"per_page": 50,
"page_count": 10,
"has_next_page": true
}
}Understand, locate, and use API names for modules, fields, and related apis in Zoho Projects.
An API name is a unique identifier assigned to every module and field in Zoho Projects.
While display names (labels shown in the UI) can be renamed and may include spaces or special characters, API names provide a consistent reference that remains unchanged across API requests and responses.
| Aspect | Display Name | API Name |
|---|---|---|
| Purpose | Label shown in the UI | Identifier used in APIs |
| Example | Start Date | start_date |
| Stability | Can be changed | Remains constant |
| Used In | Forms, views, layouts | Requests, responses, filters |
API names are used in all programmatic interactions with Zoho Projects.
API names appear as keys in request payloads and response data. Fields such as priority, status, and department are referenced using their API names rather than display labels.
This applies to operations such as creating, updating, retrieving, and filtering records.
API names for modules and fields in Zoho Projects can be accessed through the product or using APIs.
API names for custom fields are available directly within the Fields section in Zoho Projects, alongside other field details.
- Navigate to Setup > Customization > Fields.
- Select the required module.
- Use the Search Fields option to locate a specific field from the Fields list.
- Copy the API name to use it in the API operations.
The Modules API returns metadata for all modules in a portal, including their API names. The Fields API returns metadata for all fields in a module, including API names, data types, and whether a field is custom. Together, they provide a complete reference of available modules and fields for API usage.
- Refer to Get Modules for the list of modules and their API names.
- Refer to Get Fields Info for field-level details including API names.
Send custom field values when creating or updating records through Zoho Projects APIs.
Custom fields are configured within module layouts to capture additional information based on business needs. Use the corresponding field API names to pass values in the request payload.
For example, a checkbox custom field can be used to track a project condition, and its value can be submitted as true or false in the API request.
- Custom field API names are currently supported only in the Tasks and Projects APIs.
- Use the Custom Fields metadata API to retrieve field details such as API names and field types before passing values.
Zoho Projects supports various custom field types, such as text, numeric, URL, date, and time. Below are the field types available in the Create and Update APIs.
- Send all inputs as an input stream (application/json).
- Use API names for custom fields.
Captures text in a single line. Maximum length: 200 characters
JSON Schema
{ "key": "string"}Example
{"title": "Project Ara"}Captures text in multiple lines. Use "\n" to separate lines. Maximum length: 1,000 characters
JSON Schema
{ "key": "string"}Example
{"description": "The respective team\n is a prototype."}Allows selection of a single option from a predefined list. Maximum options: 50
JSON Schema
{ "key": "string"}Example
{"Material": "Vinyl"}Allows selection of multiple options from a predefined list. You can add or remove values dynamically, or replace the existing values. Maximum selectable options: 100
- The add and remove options optimize the update process for Multi-Select fields, eliminating the additional GET call to retrieve existing values before updating.
- You can directly add or remove values in an Update API request or use the Create API format.
Sample Input of Multi-Select Field in Create APIs
{ "key": [ "C", "D" ] }Example
{ "parts_required": [ "HDD", "CD" ] }Sample Input of Multi-Select Field in Update APIs
{ "key": [{ "add": [ "A", "B" ], "remove": [ "E", "F" ]}] }Example
{ "parts_required": [{ "add": ["processor", "GPU"], "remove": ["POWER-CORD", "RAM"] }] }Allows selection of a single user.
JSON Schema
{ "key": { "zpuid": "user id" }}Example
{ "reporter": { "zpuid": "123454321" }}Allows selection of multiple users from a predefined list. You can add or remove values dynamically, or replace the existing values. Maximum selectable users: 500
- The add and remove options optimize the update process for Multi-User fields, eliminating the additional GET call to retrieve existing values before updating.
- You can directly add or remove values in an Update API request or use the Create API format.
Sample Input of Multi-User Field in Create APIs
{ "key": [ { "zpuid": "User Id 5" }, { "zpuid": "User Id 6" } ] }Example
{ "user_group": [ { "zpuid": "7845996622" },{ "zpuid": "7876456433" } ] }Sample Input of Multi-User Field in Update APIs
{ "key": [ { "add": [{ "zpuid": "User Id 2" },{ "zpuid": "User Id 3" }],"remove": [ { "zpuid": "User Id 4" }, { "zpuid": "User Id 5" } ] }] }Example
{ "user_group": [ { "add": [{ "zpuid": "712554144112" },{ "zpuid": "71255413512" }],"remove": [ { "zpuid": "778946456" }, { "zpuid": "71346753132" } ] }] }Captures date in the yyyy-MM-dd format (ISO 8601).
JSON Schema
{ "key": "string"}Example
{"due_date": "2022-10-17","start_date":"2019-09-17","end_date": "2024-12-17"}Captures the time in HH:MM format.
JSON Schema
{ "key": "string"}Example
{"start_time": "23:30","end_time": "13:30"}Captures date and time in ISO 8601 format. Use yyyy-MM-dd'T'HH:mm:ss'Z' for UTC or yyyy-MM-dd'T'HH:mm:ss[+|-]HH:mm for other time zones. (ISO 8601 Time Stamp format).
JSON Schema
{ "key": "string"}Example
{"start_time": "2022-12-16T18:56:00.000Z"}Captures boolean values (true or false) for a condition.
JSON Schema
{ "key": "boolean"}Example
{"patent_applied": true}Captures currency values with currency code, formatted amount, currency ID, and raw amount. Maximum length: 100 characters
JSON Schema
{ "currency": { "currency_code": "string", "formatted_amount": "string", "amount": "number (required)" }}Example
{ "cost_per_item": { "currency_code": "USD", "formatted_amount": "$ 5,353.54", "amount": 325.50 }}Captures percentage values as numbers. Maximum length: 20 characters
JSON Schema
{ "key": "number"}Example
{"completion_percentage": 10}Captures whole numbers. Maximum length: 19 digits
JSON Schema
{ "key": "number"}Example
{"tests_passed": 35 }Captures decimal values. Maximum length: 17 digits
JSON Schema
{ "key": "number"}Example
{"accuracy": 21.05}Captures email addresses. Maximum length: 200 characters
JSON Schema
{ "key": "string"}Example
{"email":"chris@zylker.com"}Captures phone numbers (Maximum length: 15 characters, including + and ()).
JSON Schema
{ "key": "string"}Example
{"mobile":"1234567890"}Captures web links. If no protocol is specified, https:// is used by default. Maximum length: 200 characters
JSON Schema
{ "key": "string"}Example
{"link":"https://projects.zoho.com"}The filter query parameter in Zoho Projects v3 enables retrieving only records that match defined conditions. This approach avoids fetching all records and applying filtering on the client side. This guide explains how to construct filter payloads, available conditions, and supported value formats.
- Pass the
filterparameter as a URL-encoded JSON string - Combine one or more conditions using a pattern expression
- Status and date presets are currently supported on specific modules only; support for the other modules will be provided soon.
Filter Example
{
"criteria": [
{
"field_name": "name",
"criteria_condition": "contains",
"value": ["review"]
}
],
"pattern": "1"
}URL-Encoded Filter in GET Request
GET /api/v3/portal/{portal_id}/projects/{project_id}/tasks?filter=%7B%22criteria%22%3A%5B%7B%22field_name%22%3A%22name%22%2C%22criteria_condition%22%3A%22contains%22%2C%22value%22%3A%5B%22review%22%5D%7D%5D%2C%22pattern%22%3A%221%22%7DThe filter payload is organized into key components that together represent how the conditions are defined and applied within a request : criteria and pattern.
| Property | Data Type | Description |
|---|---|---|
| criteria | Array required | Each property within the filter payload represents a specific part of a condition, contributing to how fields, operators, and values are interpreted during filtering. |
| field_name | String required | API name of the field to filter (e.g. status, due_date, name). Use the Get Field Info API to retrieve valid field names for a module. |
| criteria_condition | String required | Filter operation. Available conditions depend on the field type. See Conditions Reference. |
| value | Array<String> optional | Required for most conditions. Always an array. Omit for presets (today, is_empty). between requires exactly 2 values. |
| pattern | String required | Defines how criteria are combined using AND / OR logic. References criteria by their 1-based index in the array order (e.g. first criterion = 1, second = 2). Example: "(1 AND 2) OR 3". |
The pattern shows how criteria are combined and evaluated together. Each condition is referenced by its position in the list (starting from 1), and operators like AND, OR are used to define the relationship between them. Parentheses () can be used to group conditions and control how they are applied. The pattern is always required, with "1" used when only a single condition is present.
| Pattern | Meaning |
|---|---|
"1" |
Single criterion |
"1 AND 2" |
Both must match |
"1 OR 2" |
Either can match |
"1 AND 2 AND 3" |
All three must match |
"(1 AND 2) OR 3" |
1 & 2 together, or 3 alone |
The value field represents the input used to evaluate a condition and is always structured as an array of strings. It is required for most conditions, while presets do not include a value. Range-based conditions such as between using exactly two values, and the format varies based on the field type.
| Data Type | Format | Example | Notes |
|---|---|---|---|
| Text | String | ["review"] |
Single value for most conditions |
| Date (specific) | YYYY-MM-DD |
["2024-11-04"] |
Single date value |
| Date (range) | YYYY-MM-DD |
["2024-11-01", "2024-11-30"] |
Exactly 2 values for between / not_between |
| User | ZPUID | ["4000000006061"] |
Single value for most conditions |
| Pick List | Option name | ["High"] |
Use the display name, not the ID |
| Multi Pick List | Option ID | ["4000000046001"] |
Use the option ID, not the display name |
| Check Box | "true" / "false" or "1" / "0" |
["true"] |
Both formats accepted |
| Numeric | Numeric string | ["100"] |
Numbers passed as strings |
- Only
isandis_notsupport multiple values (e.g.["high", "medium"]). iswith multiple values = OR logic (matches any).is_notwith multiple values = AND logic (excludes all).- All other conditions accept a single value (or exactly 2 for
between/not_between). - Preset conditions (
today,is_empty, etc.) do not require avaluearray.
AND Pattern
{
"criteria": [
{
"field_name": "assignee",
"criteria_condition": "is",
"value": ["4000000006061"]
},
{
"field_name": "due_date",
"criteria_condition": "is",
"value": ["2026-12-31"]
}
],
"pattern": "1 AND 2"
}OR Pattern
{
"criteria": [
{
"field_name": "priority",
"criteria_condition": "is",
"value": ["high"]
},
{
"field_name": "milestone",
"criteria_condition": "is_empty"
}
],
"pattern": "1 OR 2"
}Nested Pattern
{
"criteria": [
{
"field_name": "priority",
"criteria_condition": "is",
"value": ["high"]
},
{
"field_name": "due_date",
"criteria_condition": "is",
"value": ["2026-12-31"]
},
{
"field_name": "assignee",
"criteria_condition": "is",
"value": ["4000000006061"]
}
],
"pattern": "(1 AND 2) OR 3"
}Used for text-based fields such as name, email, and custom fields, where matching is based on keywords or exact values. All comparisons are case-insensitive.
| Condition | API Value | What it does | Value |
|---|---|---|---|
| Contains | contains |
Matches if the field has the substring anywhere | ["review"] |
| Doesn't contain | not_contains |
Excludes records containing the substring | ["test"] |
| Starts with | starts_with |
Matches the beginning of the field value | ["API"] |
| Ends with | ends_with |
Matches the end of the field value | ["v2"] |
| Is | is |
Exact match. Multiple values = OR logic | ["High"] or ["High", "Medium"] |
| Is not | is_not |
Excludes exact matches. Multiple values = AND logic | ["Low", "None"] |
contains,not_contains,starts_with, andends_withaccept only a single value. Onlyisandis_notsupport multiple values in the array.
Used for numeric and date fields, where values are evaluated based on comparisons like greater than, less than, or within a range.
| Condition | API Value | What it does | Value |
|---|---|---|---|
| Is | is |
Exact match. Multiple values = OR logic | ["100"] or ["100", "200"] |
| Is not | is_not |
Excludes exact matches. Multiple values = AND logic | ["0"] |
| Less than | less_than |
Field value is less than the given value | ["50"] |
| Less than or equal | less_than_or_equal |
Field value is less than or equal | ["50"] |
| Greater than | greater_than |
Field value is greater than the given value | ["50"] |
| Greater than or equal | greater_than_or_equal |
Field value is greater than or equal | ["50"] |
| Between | between |
Field value within range (inclusive) | ["10", "100"] |
| Not between | not_between |
Field value outside range | ["10", "100"] |
- For date fields, use
YYYY-MM-DDformat. Single value:["2024-11-01"]. Range:["2024-11-01", "2024-11-30"].
Includes ready-to-use conditions based on dates, evaluated relative to the current date without requiring manual input.
| Condition | What it matches |
|---|---|
today |
Current date |
yesterday |
Previous day |
tomorrow |
Next day |
till_yesterday |
All dates up to yesterday |
overdue |
Past due date |
today_overdue |
Due today & overdue |
| Condition | What it matches |
|---|---|
this_week |
Current week |
last_week |
Previous week |
next_week |
Upcoming week |
next_7_days |
Next 7 days |
| Condition | What it matches |
|---|---|
this_month |
Current month |
last_month |
Previous month |
next_month |
Upcoming month |
next_30_days |
Next 30 days |
| Condition | What it matches |
|---|---|
unscheduled |
No date set |
Includes predefined conditions that group records based on their status, such as open or closed.
| Condition | Description |
|---|---|
all_open |
All open statuses |
all_closed |
All closed statuses |
- To filter by a specific status, use
isoris_notwith the status ID. Example:"value": ["4000000012345"].
Used for fields related to users, including assignments, reporting structure, and user-specific states. (requires ZPUID in the value array):
| Condition | API Value | What it does |
|---|---|---|
| Is | is |
Records assigned to the given user(s). Multiple values = OR logic |
| Is not | is_not |
Excludes records assigned to the given user(s) |
Used to identify fields that do not have any value assigned.
| Condition | Description |
|---|---|
is_empty |
Field has no value |
- Useful for finding incomplete records, such as tasks with no due date or unassigned tasks.
- For date fields, use
unscheduledinstead ofis_emptyto filter records with no date set.
Text: Contains
{
"criteria": [
{
"field_name": "name",
"criteria_condition": "contains",
"value": ["review"]
}
],
"pattern": "1"
}Multi-Value IS
{
"criteria": [
{
"field_name": "waiting_for",
"criteria_condition": "is",
"value": ["frontend", "backend"]
}
],
"pattern": "1"
}Date: Between
{
"criteria": [
{
"field_name": "start_date",
"criteria_condition": "between",
"value": ["2024-11-01", "2024-11-30"]
}
],
"pattern": "1"
}Numeric: Greater Than
{
"criteria": [
{
"field_name": "percentage_completion",
"criteria_condition": "greater_than",
"value": ["50"]
}
],
"pattern": "1"
}Date Preset: Today
{
"criteria": [
{
"field_name": "end_date",
"criteria_condition": "today"
}
],
"pattern": "1"
}Date Preset: This Week
{
"criteria": [
{
"field_name": "end_date",
"criteria_condition": "this_week"
}
],
"pattern": "1"
}Date Preset: This Month
{
"criteria": [
{
"field_name": "end_date",
"criteria_condition": "this_month"
}
],
"pattern": "1"
}Status Preset: All Open
{
"criteria": [
{
"field_name": "status",
"criteria_condition": "all_open"
}
],
"pattern": "1"
}User: Is
{
"criteria": [
{
"field_name": "assignee",
"criteria_condition": "is",
"value": ["4000000006061"]
}
],
"pattern": "1"
}Overdue + Assigned to Me
{
"criteria": [
{
"field_name": "due_date",
"criteria_condition": "is",
"value": ["2026-12-31"]
},
{
"field_name": "owner",
"criteria_condition": "is",
"value": ["4000000006061"]
}
],
"pattern": "1 AND 2"
}Empty Field Check
{
"criteria": [
{
"field_name": "description",
"criteria_condition": "is_empty"
}
],
"pattern": "1"
}Unscheduled Date Field
{
"criteria": [
{
"field_name": "end_date",
"criteria_condition": "unscheduled"
}
],
"pattern": "1"
}Ready-made filter payloads for the most common requests. Copy a payload, URL-encode it, and pass it as the filter query parameter.
These filters work across modules such as tasks, issues, and custom modules.
Returns all open tasks in a single request.
Uses status with the custom_condition operator and the ${ALL_OPEN} value.
Filter by Open Status
{
"criteria": [
{
"field_name": "status",
"criteria_condition": "custom_condition",
"value": ["${ALL_OPEN}"]
}
],
"pattern": "1"
}Returns all closed tasks in a single request.
Uses status with the custom_condition operator and the ${ALL_CLOSED} value.
Filter by Closed Status
{
"criteria": [
{
"field_name": "status",
"criteria_condition": "custom_condition",
"value": ["${ALL_CLOSED}"]
}
],
"pattern": "1"
}Returns tasks in a specific status.
Uses status with the is condition and the status ID as the value.
Filter by Status
{
"criteria": [
{
"field_name": "status",
"criteria_condition": "is",
"value": ["268026000001877009"]
}
],
"pattern": "1"
}Returns tasks owned by a specific user.
Uses owner with the is condition and the user's ZPUID as the value.
Filter by Owner
{
"criteria": [
{
"field_name": "owner",
"criteria_condition": "is",
"value": ["268026000002340076"]
}
],
"pattern": "1"
}Returns tasks whose name contains the given text.
Uses name with the contains condition and the search text as the value.
Filter by Name
{
"criteria": [
{
"field_name": "name",
"criteria_condition": "contains",
"value": ["test"]
}
],
"pattern": "1"
}Returns tasks created after a specific point in time.
Uses created_time with the greater_than condition and a YYYY-MM-DD value.
Filter by Created Time
{
"criteria": [
{
"field_name": "created_time",
"criteria_condition": "greater_than",
"value": ["2026-03-01"]
}
],
"pattern": "1"
}Returns tasks last updated after a specific date.
Uses last_updated_time with the greater_than condition and a YYYY-MM-DD value.
Filter by Last Modified Time
{
"criteria": [
{
"field_name": "last_updated_time",
"criteria_condition": "greater_than",
"value": ["2026-03-01"]
}
],
"pattern": "1"
}These filters are available in the Tasks module only.
Returns only subtasks (tasks that have a parent task).
Uses has_parents with value true. Set false to return only top-level tasks. Accepts "true" / "false" or "1" / "0".
Filter by Subtask
{
"criteria": [
{
"field_name": "has_parents",
"criteria_condition": "is",
"value": ["true"]
}
],
"pattern": "1"
}Returns the subtasks of a specific parent task.
Uses parent_task with the is condition and the parent task ID as the value.
Filter by Parent Task
{
"criteria": [
{
"field_name": "parent_task",
"criteria_condition": "is",
"value": ["268026000003251123"]
}
],
"pattern": "1"
}Returns tasks that belong to a task list whose name contains the given text.
Uses module_name set to tasklist to filter on the related module's name field.
Filter by Task List
{
"criteria": [
{
"module_name": "tasklist",
"field_name": "name",
"criteria_condition": "contains",
"value": ["Codex"]
}
],
"pattern": "1"
}Zoho Projects APIs use OAuth 2.0 for authentication. This page gives you an overview of the authentication process. For complete details on OAuth 2.0 flows, registration, token management, and more, refer to Zoho OAuth 2.0 documentation.
To access Zoho Projects APIs, your application needs an access token obtained through one of the OAuth 2.0 flows. At a high level, the steps are:
- Register your application in the Zoho API console.
- Get consent from user to access their data and obtain an access token.
- Call Zoho Projects APIs using the access token.
Access tokens expire periodically. The expiry duration is returned as expires_in (seconds) in the access token response.
To maintain uninterrupted access, you can request for an optional refresh token, store it, and use it to generate new access tokens as needed.
- Access tokens are required for every API request.
- Refresh tokens can be used to generate new access tokens without requiring user re-authorization.
- Users can revoke an application's access at any time, which invalidates the associated tokens.
For more details on token management, refer to Zoho OAuth 2.0 documentation.
Zoho supports OAuth flows for different application types (server-based, client-based, mobile & desktop-based, limited input devices, and self client). You can choose the flow that matches your application.
For detailed information, refer to the OAuth documentation.
Zoho operates data centers in multiple regions. If your application serves users across regions, you must enable Multi DC support in the API console and use region-specific endpoints for both OAuth and Zoho Projects API calls.
Zoho Projects APIs require OAuth scopes to define the level of access your application needs. When requesting for access token, request only the scopes your application requires. These will be displayed to the users when asking for consent.
| Scope | Description |
|---|---|
| ZohoProjects.projects.READ | Access project data (read-only) |
| ZohoProjects.projects.ALL | Full access to projects |
| ZohoProjects.tasks.ALL | Full access to tasks |
| ZohoProjects.timesheets.ALL | Full access to time logs |
To request multiple scopes, separate them with commas:
scope=ZohoProjects.projects.READ,ZohoProjects.tasks.ALL
For more details about scope format, see OAuth Scopes.
To authenticate your API calls, include the access token in the Authorization header of every API request with the prefix Bearer.
Authorization: Bearer {access-token-value}
curl -X GET "https://projects.zoho.com/api/v3/portals" -H "Authorization: Bearer 1000.abc123def456..."
Use this method to generate the organization-specific grant token if your application does not have a domain and a redirect URL. You can also use this option when your application is a standalone server-side application performing a back-end job.
- Go to Zoho Developer Console and log in with your Zoho Projects username and password.
- Choose Self Client from the list of client types, and click Create Now.
- Click OK in the pop up to enable a self client for your account.
- Now, your client ID and client secret are displayed under the Client Secret tab.
- Click the Generate Code tab and enter the required scope separated by commas. Refer to our list of Scopes, for more details. The system throws an 'Enter a valid scope' error when you enter one or more incorrect scopes.
- Select the Time Duration for which the grant token is valid. Please note that after this time, the grant token expires.
- Enter a description and click Create.
- The organization-specific grant token code for the specified scope is displayed. Copy the grant token.
When making API calls, you must use the base URL corresponding to your user's data center. The access token response identifies the user's data center through the location and api_domain values - use it to pick the matching Zoho Projects base URL from the table below.
| Data center | API base URL |
|---|---|
| United States (US) | https://projects.zoho.com |
| European Union (EU) | https://projects.zoho.eu |
| India (IN) | https://projects.zoho.in |
| Australia (AU) | https://projects.zoho.com.au |
| Japan (JP) | https://projects.zoho.jp |
| Canada (CA) | https://projects.zohocloud.ca |
| China (CN) | https://projects.zoho.com.cn |
| Saudi Arabia (SA) | https://projects.zoho.sa |
| United Kingdom (UK) | https://projects.zoho.uk |
| United Arab Emirates (UAE) | https://projects.zoho.ae |
| Singapore (SG) | https://projects.zoho.sg |
Never hardcode a single region's URL. Resolve the user's data center from the location / api_domain value in the access token response, then use the corresponding Zoho Projects base URL from the table above. See Multi-DC Support.