Install
openclaw skills install zohoprojectManage Zoho Projects — list portals/projects, create/update/complete tasks, add comments, log time, manage milestones, and query your task list. Requires ZOHO_ACCESS_TOKEN and ZOHO_PORTAL_ID environment variables.
openclaw skills install zohoprojectUse the Zoho Projects V3 REST API (base: https://projectsapi.zoho.com/api/v3) to manage projects, tasks, milestones, and time logs.
Every request must include:
Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN
Access tokens expire hourly. If you get a 401, tell the user their token has expired and they need to refresh it using their refresh token (see Setup below). Store the refreshed token with:
openclaw config set skills.entries.zoho-projects.apiKey NEW_TOKEN
| Variable | Description |
|---|---|
ZOHO_ACCESS_TOKEN | OAuth2 access token from Zoho (expires hourly) |
ZOHO_PORTAL_ID | Your portal ID (get it from the List Portals call below) |
ZOHO_REFRESH_TOKEN | (optional) Stored refresh token for auto-renewal |
ZOHO_CLIENT_ID | (optional) OAuth client ID for token refresh |
ZOHO_CLIENT_SECRET | (optional) OAuth client secret for token refresh |
ZOHO_DC | (optional) Data center domain, e.g. zoho.eu or zoho.com (default: zoho.com) |
ZohoProjects.portals.READ,ZohoProjects.projects.ALL,ZohoProjects.tasks.ALL,ZohoProjects.milestones.ALL,ZohoProjects.timesheets.ALL,ZohoProjects.bugs.ALLcurl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=authorization_code" \
-d "client_id=$ZOHO_CLIENT_ID" \
-d "client_secret=$ZOHO_CLIENT_SECRET" \
-d "redirect_uri=https://localhost" \
-d "code=YOUR_GRANT_TOKEN"
access_token as ZOHO_ACCESS_TOKEN and refresh_token as ZOHO_REFRESH_TOKENZOHO_PORTAL_IDIf you get a 401 Unauthorized error, refresh the token:
curl -X POST "https://accounts.${ZOHO_DC:-zoho.com}/oauth/v2/token" \
-d "grant_type=refresh_token" \
-d "client_id=$ZOHO_CLIENT_ID" \
-d "client_secret=$ZOHO_CLIENT_SECRET" \
-d "refresh_token=$ZOHO_REFRESH_TOKEN"
Parse the access_token from the JSON response and update ZOHO_ACCESS_TOKEN.
List Portals (use this to find your ZOHO_PORTAL_ID)
curl -s "https://projectsapi.zoho.com/api/v3/portals" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
List all projects
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Get a specific project
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Create a project
curl -s -X POST "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Project Name",
"description": "Optional description",
"start_date": "2026-03-24T00:00:00Z",
"end_date": "2026-06-30T00:00:00Z"
}'
Update a project (PATCH updates only specified fields)
curl -s -X PATCH "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Name", "status": "active"}'
Get my tasks (across all projects)
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/mytasks" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Optional query params: ?status=open | status=closed | due_date=2026-03-24
List tasks in a project
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Optional: ?status=open&sort_column=due_date&sort_order=asc
Get task details
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks/$TASK_ID" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Create a task
curl -s -X POST "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Task name",
"description": "Task details",
"due_date": "2026-04-15T00:00:00Z",
"priority": "high"
}'
Priority values: none, low, medium, high
Update / complete a task
curl -s -X PATCH "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks/$TASK_ID" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "closed"}'
Use "status": "open" to reopen a task.
Delete a task
curl -s -X DELETE "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks/$TASK_ID" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Add a comment to a task
curl -s -X POST "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks/$TASK_ID/comments" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": "Your comment here"}'
List milestones in a project
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/milestones" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
Create a milestone
curl -s -X POST "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/milestones" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Milestone name",
"end_date": "2026-05-01T00:00:00Z",
"flag": "internal"
}'
Log time on a task
curl -s -X POST "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/tasks/$TASK_ID/logs" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-03-24T00:00:00Z",
"hours": "02:30",
"notes": "Worked on API integration",
"bill_status": "Billable"
}'
Get time logs for a project
curl -s "https://projectsapi.zoho.com/api/v3/portal/$ZOHO_PORTAL_ID/projects/$PROJECT_ID/logs" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
2026-03-24T00:00:00Z| python3 -m json.tool after curl commands to pretty-print JSON responses.ZOHO_DC to the correct domain (e.g., zoho.eu) and use projectsapi.zoho.eu as the API base URL instead.id or id_string field to use in subsequent calls.?status=open and format the results as a readable list.