npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zoho-typegen

v0.1.5

Published

Generate TypeScript interfaces from Zoho CRM module metadata. Unofficial community tool.

Downloads

700

Readme

zoho-typegen

Generate TypeScript interfaces from Zoho CRM module metadata — including subforms, custom fields and picklist union types.

Unofficial community tool. Not affiliated with or endorsed by Zoho Corporation.


Why

Zoho's own TypeScript SDK doesn't generate types for custom fields or picklist values as union literals. This tool calls the Zoho CRM Metadata API, reads every module's field definitions, and writes per-module .ts files with accurate interfaces. Including Subforms!

For example, a picklist field becomes a proper union type — not just string:

Lead_Source?: 'Cold Call' | 'Employee Referral' | 'Online Store' | 'Partner' | 'Web Site' | 'Word of Mouth' | 'Other';

Custom fields are included automatically. No manual type maintenance.


Prerequisites

You need a valid Zoho CRM access token before using this tool. If you don't have one yet, set up a Zoho OAuth client at accounts.zoho.com/developerconsole and follow Zoho's OAuth guide to get an access token.

The token format expected by getToken() is the full header value:

Zoho-oauthtoken 1000.xxxxxxxxxxxxxxx

Quick Start

1. Install:

npm install --save-dev zoho-typegen

2. Create zoho-typegen.config.js in your project root:

export default {
  getToken: () => process.env.ZOHO_ACCESS_TOKEN,
  outputDir: './src/types/zoho',
};

3. Run:

npx zoho-typegen

That's it. Per-module .ts files and a barrel index.ts are written to outputDir.


Installation

Project devDependency (recommended):

npm install --save-dev zoho-typegen

Global:

npm install -g zoho-typegen

Token & Auth

getToken is a function, not a string — because Zoho access tokens are short-lived (~1 hour) and typically live in a database, not an env file. You implement the function; the tool calls it.

// From an environment variable (simple scripts)
getToken: () => process.env.ZOHO_ACCESS_TOKEN,

// From a file written by your token-refresh cron
getToken: () => fs.readFileSync('.zoho_token', 'utf-8').trim(), // requires: import fs from 'fs'

// From a SQL database (async is fine)
getToken: async () => {
  const row = await db.query('SELECT value FROM tokens WHERE key = $1', ['zoho']);
  return row.value;
},

// From a settings collection in a Meteor app
getToken: () => Settings.findOne({ key: 'zoho_access_token' })?.value,

The tool does not handle token refresh. Pass a valid, already-refreshed token. If getToken() returns an expired token mid-run, some modules will fail with INVALID_TOKEN — just re-run after refreshing.

Required OAuth Scopes

When creating your Zoho OAuth client, make sure the token has at least these scopes:

ZohoCRM.settings.modules.READ
ZohoCRM.settings.fields.READ

Or the single combined scope:

ZohoCRM.settings.READ

These are read-only metadata scopes — the tool never reads, writes, or modifies any CRM records.


Config File Reference

Create zoho-typegen.config.js (ESM) or zoho-typegen.config.ts in your project root. See zoho-typegen.config.example.ts (included in the package) for a full copy-paste template.

| Option | Type | Default | Description | | --------------------- | --------------------------------- | ---------------- | ---------------------------------------------- | | getToken | () => string \| Promise<string> | required | Returns a valid Zoho CRM access token | | outputDir | string | './types/zoho' | Where to write the generated .ts files | | picklistValues | 'display' \| 'actual' | 'display' | Which picklist value to use for union literals | | excludeModules | string[] | [] | Module api_names to always skip | | includeModules | string[] | [] (all) | Only generate these modules | | includeUserHidden | boolean | false | Include user_hidden modules | | includeSystemHidden | boolean | false | Include system_hidden modules |


CLI Reference

zoho-typegen generate (default command)

Fetch all module fields and write TypeScript interface files.

zoho-typegen [generate] [options]

Options:
  --modules <names...>      Only generate these modules (space-separated api_names)
  --exclude <names...>      Skip these modules (space-separated api_names)
  --output <dir>            Output directory (overrides config outputDir)
  --picklist <mode>         Picklist value mode: display (default) or actual
  --include-user-hidden     Include user_hidden modules (Tasks, Events, etc.)
  --include-system-hidden   Include system_hidden modules (Notes, Attachments, etc.)
  -h, --help                Display help

Examples:

# Generate all modules (reads config file)
npx zoho-typegen

# Generate only Leads and Contacts
npx zoho-typegen --modules Leads Contacts

# Regenerate one module after a field change
npx zoho-typegen --modules CustomModule12

# Skip a known-broken module
npx zoho-typegen --exclude Approvals

# Write to a custom output directory
npx zoho-typegen --output ./generated/crm-types

CLI flags override config file values.


zoho-typegen list

List all modules in your CRM org with their API flags. Use this to see which modules will be included or skipped before running generate.

npx zoho-typegen list

Example output:

Found 52 modules:

api_name                                      api_supported   viewable   status          generated_type
───────────────────────────────────────────── ─────────────── ────────── ─────────────── ──────────────
Leads                                         true            true       visible         default
Contacts                                      true            true       visible         default
Deals                                         true            true       visible         default
Accounts                                      true            true       visible         default
Tasks                                         true            true       user_hidden     default
Events                                        true            true       user_hidden     default
Notes                                         true            true       system_hidden   default
Approvals                                     false           true       visible         default
...

Generated Output

Each included module gets its own .ts file. A barrel index.ts re-exports everything.

src/types/zoho/Leads.ts:

// Generated by zoho-typegen. Do not edit.

export interface ZohoLeads {
  id: string;
  First_Name?: string;
  Last_Name: string;
  Email?: string;
  Phone?: string;
  Lead_Source?:
    | 'Cold Call'
    | 'Employee Referral'
    | 'Online Store'
    | 'Partner'
    | 'Public Relations'
    | 'Web Site'
    | 'Word of Mouth'
    | 'Other';
  Rating?: 'Acquired' | 'Active' | 'Market Failed' | 'Project Cancelled' | 'Shut Down';
  Annual_Revenue?: number;
  No_of_Employees?: number;
  Created_Time?: string;
  Modified_Time?: string;

  // Custom fields
  Budget?: number;
  Referral_Source?: string;
  Custom_Status?: 'New' | 'Reviewed' | 'In Progress' | 'Closed';

  // Subform
  Invoiced_Items?: Array<{
    id: string;
    Product_Name?: string;
    Quantity?: number;
    Unit_Price?: number;
    Total?: number;
  }>;
}

src/types/zoho/index.ts:

export type { ZohoLeads } from './Leads.js';
export type { ZohoContacts } from './Contacts.js';
export type { ZohoDeals } from './Deals.js';
// ...

Import in your app:

import type { ZohoLeads, ZohoContacts } from './types/zoho';

function processLead(lead: ZohoLeads) {
  if (lead.Lead_Source === 'Web Site') { ... }
}

Module Filtering

The tool uses Zoho's own API flags to decide which modules to include — no hardcoded module names.

| Flag | Default behavior | Override | | ------------------------- | --------------------------------------------------- | ------------------------- | | api_supported: false | Skipped — Zoho returns NOT_SUPPORTED | Not overridable | | viewable: false | Skipped — Zoho returns NO_PERMISSION | Not overridable | | status: 'user_hidden' | Skipped (Tasks, Events, old deprecated modules) | --include-user-hidden | | status: 'system_hidden' | Skipped (Notes, Attachments) | --include-system-hidden |

Only modules with generated_type: 'default' or 'custom' are included. Linking modules, and web modules are excluded. Subforms types will be included within the attached module.


Picklist Values: display vs actual

Zoho picklist fields have two values: display_value (the label shown in the UI) and actual_value (an internal key).

display (default): Uses the label the user sees in the CRM.

Lead_Source?: 'Cold Call' | 'Employee Referral' | 'Online Store' | ...

actual: Uses the internal Zoho key. Avoid this — if a picklist option is ever renamed in the CRM UI, the actual_value stays stale while display_value updates to match. Using actual also breaks for any org where options were created with generic keys like option1, option2.

Lead_Source?: 'Cold_Call' | 'Employee_Referral' | 'Online_Store' | ...

Use actual only if your integration reads actual_value from the API response and the values in your org are meaningful (not Zoho placeholders like option1, option2).

Note: -None- is always stripped from picklist unions. It's represented by the field being optional (?) instead.


Known Issues

Approvals module — Returns invalid JSON from Zoho's settings API in most orgs (a Zoho-side bug). Add it to excludeModules if you see parse errors:

excludeModules: ['Approvals'],

Actions_Performed, Home, Workqueues — Similar issue. Gracefully skipped with a warning in the console.


Programmatic API

You can import and call the core functions directly if you prefer not to use the CLI:

import { fetchModules, fetchAllModuleFields, writeModuleFiles } from 'zoho-typegen';

const token = await getYourToken();
const baseUrl = 'https://www.zohoapis.com/crm/v8';

const allModules = await fetchModules(token, baseUrl);
const results = await fetchAllModuleFields(token, baseUrl, allModules, 500);
writeModuleFiles('./src/types/zoho', results, { picklistValues: 'display' });

Requirements

  • Node.js 18+
  • A valid Zoho CRM access token with metadata read permissions

License

MIT © Rupin Wildhunt


Disclaimer: This is an unofficial community tool. It is not affiliated with, endorsed by, or officially supported by Zoho Corporation. Zoho and Zoho CRM are trademarks of Zoho Corporation Pvt. Ltd.