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

@milesjyoung/zoho-client

v1.0.2

Published

Reusable Zoho CRM helper for cloud jobs and shared business logic. The client is designed so you can keep a refresh token in your cloud secret store and inject it into each runtime instead of baking credentials into app code.

Downloads

28

Readme

Zoho Helper Module

Reusable Zoho CRM helper for cloud jobs and shared business logic. The client is designed so you can keep a refresh token in your cloud secret store and inject it into each runtime instead of baking credentials into app code.

What It Gives You

  • Refresh-token based auth with in-memory access-token caching
  • Safe concurrent token refresh handling
  • Generic authenticated request helper
  • COQL query helper
  • Reusable per-module CRUD/search helpers
  • Environment-variable defaults for quick local use
  • Async refresh-token provider support for cloud secret managers

Install Shape

This repo currently exports a CommonJS module:

const { createZohoClient } = require("./src");

Getting The Initial Refresh Token

Before this module can run in a cloud environment, you need to complete Zoho's OAuth consent flow once and capture a refresh token. That refresh token is the long-lived secret you store in your cloud secret manager.

Typical setup flow:

  1. Create or open your Zoho OAuth client in the Zoho API Console.
  2. Make sure the client has the CRM scopes your app needs, such as record read and update scopes.
  3. Run the user consent flow in a browser to get an authorization code.
  4. Exchange that one-time code for an access_token and refresh_token.
  5. Store the refresh_token in your cloud secret manager and pass it into this module with refreshToken or refreshTokenProvider.

Example token exchange request (use ZohoCRM.modules.all, ZohoCRM.coql.READ at https://api-console.zoho.com/):

curl -i --request POST \
  --url "https://accounts.zoho.com/oauth/v2/token" \
  --header "Accept: application/json" \
  --data-urlencode "grant_type=authorization_code" \
  --data-urlencode "client_id=$ZOHO_CLIENT_ID" \
  --data-urlencode "client_secret=$ZOHO_CLIENT_SECRET" \
  --data-urlencode "code=$ZOHO_GRANT_TOKEN"

The response should include a refresh_token. Capture that once and store it securely. After that, this module handles access-token refresh automatically.

Basic Usage

const { createZohoClient } = require("./src");

const zoho = createZohoClient({
  clientId: process.env.ZOHO_CLIENT_ID,
  clientSecret: process.env.ZOHO_CLIENT_SECRET,
  refreshToken: process.env.ZOHO_REFRESH_TOKEN,
  defaultModule: "Deals",
});

const deals = await zoho.module("Deals").coqlWhere({
  fields: ["id", "Deal_Name", "Stage"],
  where: "Stage = 'Closed Won'",
  limit: 50,
});

await zoho.module("Deals").update([
  {
    id: "5725767000001234567",
    Stage: "Closed Won",
  },
]);

await zoho.module("Deals").updateOne("5725767000001234567", {
  Stage: "Closed Won",
});

await zoho.module("Deals").updateField(
  "5725767000001234567",
  "Stage",
  "Closed Won"
);

Fetch A Single Deal By ID

const { createZohoClient } = require("./src");

const zoho = createZohoClient({
  clientId: process.env.ZOHO_CLIENT_ID,
  clientSecret: process.env.ZOHO_CLIENT_SECRET,
  refreshTokenProvider: async () => getSecretValue("zoho-refresh-token"),
});

const dealResponse = await zoho.module("Deals").get("5725767000001234567");
const deal = dealResponse.data?.[0];

console.log(deal);

If you prefer using the lower-level request helper directly:

const dealResponse = await zoho.request({
  method: "get",
  path: "/crm/v6/Deals/5725767000001234567",
});

const deal = dealResponse.data?.[0];

Cloud Secret Manager Example

Pass a function when the refresh token lives in AWS Secrets Manager, GCP Secret Manager, Doppler, 1Password, or another provider:

const zoho = createZohoClient({
  clientId: process.env.ZOHO_CLIENT_ID,
  clientSecret: process.env.ZOHO_CLIENT_SECRET,
  refreshTokenProvider: async () => {
    return getSecretValue("zoho-refresh-token");
  },
});

API

createZohoClient(options)

Supported options:

  • clientId
  • clientSecret
  • refreshToken
  • refreshTokenProvider
  • accountsBaseUrl
  • apiBaseUrl
  • crmVersion
  • defaultModule
  • timeoutMs
  • refreshBufferMs

Environment fallback is supported for:

  • ZOHO_CLIENT_ID
  • ZOHO_CLIENT_SECRET
  • ZOHO_REFRESH_TOKEN
  • ZOHO_ACCOUNTS_URL
  • ZOHO_API_BASE_URL
  • ZOHO_CRM_VERSION
  • ZOHO_DEFAULT_MODULE
  • ZOHO_TIMEOUT_MS
  • ZOHO_REFRESH_BUFFER_MS

Top-level helpers

await zoho.request({ method: "get", path: "/crm/v6/Deals" });
await zoho.coql("select id, Deal_Name from Deals where Stage = 'Closed Won' limit 0, 25");
await zoho.getRecordsByCoqlWhere({
  moduleName: "Contacts",
  fields: ["id", "Email"],
  where: "Email is not null",
});

Module facade

const contacts = zoho.module("Contacts");

await contacts.get("5725767000001234567");
await contacts.list({ perPage: 50, fields: ["id", "Last_Name", "Email"] });
await contacts.search({ email: "[email protected]" });
await contacts.create({ Last_Name: "Nguyen", Email: "[email protected]" });
await contacts.update([{ id: "5725767000001234567", Phone: "555-0100" }]);
await contacts.updateOne("5725767000001234567", { Phone: "555-0100" });
await contacts.updateField("5725767000001234567", "Phone", "555-0100");
await contacts.upsert([{ Email: "[email protected]", Last_Name: "Nguyen" }]);
await contacts.delete(["5725767000001234567"]);

Suggested Next Step

If you want this reused across many projects, the next clean move is to publish this as its own package or place it in a shared internal library repo with:

  • a small test suite around token refresh and request retries
  • project-specific wrappers like createCompanyCamZohoThreadClient()
  • typed definitions if your consumers are in TypeScript