Skip to content

Zoho Projects#

Zoho Projects supports native CSV import and OAuth-backed portal sync. Both methods create the same reviewable import session and use one Zoho-owned task projector; the sync also imports active portal/client users and task actors into the user-mapping flow.

Capability Method Status
CSV_IMPORT Upload a Zoho Projects task CSV export Built
SYNC Pull projects/tasks from one selected portal Built
USER_IMPORT Import active portal/client users during sync Built during /imports/sync
WEBHOOK Verify Zoho Projects events Not built

The routes live under /api/v1/providers/zoho-projects/... and use the shared provider-parameterized handlers. Organization data requires an organization-scoped user token; see Authentication.

OAuth Application Setup#

Create a Server-based Application in the Zoho API Console. Configure the exact callback for the environment running this service:

# Local API
http://127.0.0.1:8057/api/v1/providers/zoho-projects/oauth/callback

# TeamBoost integrations testing API
https://tb-test-integrations.atlas-labs.org/api/v1/providers/zoho-projects/oauth/callback

The URI in Zoho and ZOHO_PROJECTS_REDIRECT_URI must match character for character. If users in multiple data centers will connect, enable those data centers in the application's Multi-DC settings and choose Use the same OAuth credentials for all data centers; this adapter currently configures one service-wide client secret.

Configure these values in the service environment/secret manager, never in source control:

ZOHO_PROJECTS_CLIENT_ID=<server-app-client-id>
ZOHO_PROJECTS_CLIENT_SECRET=<server-app-client-secret>
ZOHO_PROJECTS_REDIRECT_URI=https://<api-host>/api/v1/providers/zoho-projects/oauth/callback
ZOHO_PROJECTS_SCOPES=ZohoProjects.portals.READ,ZohoProjects.projects.READ,ZohoProjects.tasklists.READ,ZohoProjects.tasks.READ,ZohoProjects.users.READ

The callback requires Zoho's paired location and accounts-server values. Supported locations are US, EU, IN, AU, JP, CA, SA, and UK. The pair is checked against exact regional Accounts origins; the token's API domain is separately allowlisted. Projects requests use the exact regional projectsapi origin selected for that validated location. There is no silent US fallback and no provider-supplied URL is followed.

Authorizing a Portal#

Start authorization through the generic route:

GET /api/v1/providers/zoho-projects/oauth/authorize?organization_id=<id>

The response contains a short-lived signed state and authorizationUrl. Open the URL in a browser and approve access. Zoho redirects directly to this service with code, state, location, and accounts-server; the callback exchanges the one-time code and stores the token/portal/routing bundle encrypted for that organization. Access and refresh tokens are never returned.

If the Zoho user can access exactly one portal, that portal is selected. If multiple portals are visible, start again with the intended portal id signed into state:

GET /api/v1/providers/zoho-projects/oauth/authorize?organization_id=<id>&targetAccountId=<portal-id>

The selected id must match an accessible portal. The adapter never chooses the first of multiple portals. The portal id can be read from the portal/API URL or portal settings in Zoho Projects; it is not a client secret.

Swagger test sequence#

At https://tb-test-integrations.atlas-labs.org/docs:

  1. Use Authorize to set the TeamBoost user Bearer token.
  2. Run GET /api/v1/providers/zoho-projects/oauth/authorize with the TeamBoost organization_id (and targetAccountId only when multiple portals are accessible).
  3. Copy authorizationUrl from the response into the browser and complete Zoho consent. Do not try to reuse the returned authorization code.
  4. Run POST /api/v1/providers/zoho-projects/credentials/verify?organization_id=<id>.
  5. Run POST /api/v1/providers/zoho-projects/imports/sync?organization_id=<id>.
  6. Inspect the returned import session, user mappings, projected drafts, projection errors, and mapping notes. This creates a review session; it does not execute TeamBoost tasks.

If step 3 reports multiple portals, obtain the intended portal id and repeat from step 2 with targetAccountId. A failed/consumed authorization code cannot be replayed.

API Sync Behavior#

POST /api/v1/providers/zoho-projects/credentials/verify?organization_id=<id>
POST /api/v1/providers/zoho-projects/imports/sync?organization_id=<id>

Credential verification confirms that the current token can still see the stored portal. Before verify/sync, an expiring access token is refreshed through the same regional Accounts origin; Zoho refresh responses may omit the existing refresh token, API domain, and scopes, so the validated encrypted values are retained.

One sync:

  • pages through all projects in the selected portal;
  • pages through every project's task lists and tasks via V3, hydrating task-list ids into task-group names;
  • pages through active portal users and active client users via V3.1;
  • joins directory users[].id to task actor zpuid, while retaining task-only actors;
  • uses up to 200 records per page and refuses malformed/repeated pagination;
  • retries network errors, 429, and transient 5xx responses at most four times, honoring a bounded Retry-After; auth and other 4xx failures are terminal.

Zoho documents per-endpoint rate limits. A sync that exhausts the bounded retry policy fails loudly; it does not create a partial import session.

API User Mapping#

V3.1 directory ids and task actor zpuid values are the durable mapping key. E-mail and display name remain matching hints. The first task owner in source order is selected as the normalized owner; every owner remains in the lossless source record and multiple owners add a review note.

  • a present but unmapped owner creates a blocking projection error;
  • a mapped owner becomes ownerId;
  • a mapped creator becomes creatorId;
  • an unmapped creator leaves creatorId unset with a non-blocking note.

Exporting a Compatible CSV#

In Zoho Projects, open the task view to export, choose CSV as the file type, and leave password protection disabled. The parser accepts native plain-text CSV, including the optional Export with file information preamble. It does not accept encrypted Office workbooks or Excel files renamed with a .csv extension.

Include these selected columns:

  • Task Name
  • Owner
  • Custom Status
  • Priority
  • Created By
  • Project Name
  • Task ID
  • Task System ID
  • Task List Name
  • Last Modified Time
  • Created Time

Additional selected columns are retained losslessly. The parser finds the task header after the optional file-information preamble.

Importing From CSV#

POST /api/v1/providers/zoho-projects/imports/csv?organization_id=<id>
curl -X POST "https://<host>/api/v1/providers/zoho-projects/imports/csv?organization_id=590789" \
  -H "Authorization: Bearer <user-token>" \
  -F "file=@zoho-projects-task-export.csv"

Task System ID is the stable provider identity; Task ID is the human identifier. A row also requires Task Name, Created Time, and Last Modified Time. Malformed rows are returned in rowErrors; a missing required header fails with invalid_csv_format.

CSV dates are MM-DD-YYYY without a time zone/time-of-day. They become midnight UTC with date_only precision recorded in source context. A literal - is absent. CSV actors are name-only and matched through sourceName; the parser treats each actor cell as one opaque display name rather than guessing a multi-owner delimiter.

Projection Field Coverage#

Zoho Projects source TeamBoost draft field Behavior
task name title Error if shorter than 2 characters
task type Defaults to OTHER with a mapping note
description description Optional
status/custom status status Open/to-do → NOT_STARTED; active/in-progress → IN_PROGRESS; completed/closed/done → COMPLETED; canceled → CANCELED; Blocked/On HoldBLOCKED; unknown values are unset
priority priority urgent/critical/high/medium/low map directly; none/blank/unknown → UNKNOWN
first owner / zpuid ownerId Resolved through the proposed user mapping
creator / zpuid creatorId Resolved when possible; no fallback id is invented
project name projectTitle Optional
task-list name taskGroupTitle Optional
API tags labels Each returned tag name is retained as a label; CSV tag cells stay lossless but unmapped because their delimiter is not provider-proven
start date plannedStartDate CSV date-only or API ISO-8601
due date plannedEndDate CSV date-only or API ISO-8601
selected CSV fields or complete V3 task/context descriptionJson Preserved for review/trace

Duration/work values, phases, and relationships remain in descriptionJson; they are not converted into TeamBoost duration or dependencies. API tags also map to labels, while CSV tags remain only in descriptionJson.

Not Built Yet#

  • Standalone user import outside /imports/sync.
  • Webhook registration, signature verification, timestamp/replay protection, and event processing.