Welcome back to another week of Kaizen!
In our
sample project, we used the
file-based persistence method, a simple setup where the access and refresh tokens are stored in a local file. While this method is great for getting started, it might not always fit your business requirements.
That is why our SDKs offer multiple ways to persist your tokens.
This week, we will explore why token persistence matters for your app’s secure operation, and how to implement custom token persistence methods, including a practical example using SQLite.
Why does token persistence matter?
When a user logs in via OAuth, Zoho returns two tokens:
- An access token (valid for one hour), used to access Zoho CRM data.
- A refresh token, used to get a new access token when the current one expires.
If your app does not store these tokens properly, your users will be forced to log in again every time they make an API call. Or every time their access token gets expired. That is not inconvenient; it is a poor user experience.
When you use Zoho CRM SDKs, this is all handled for you behind the scenes. When you first authenticate with Zoho, the SDK stores your access and refresh tokens. Later, when a token expires, the SDK automatically uses the refresh token to get a new one. All you have to do is configure and initialize the SDK, and you are ready to start making API calls using the different methods offered by our SDKs!
From the user’s perspective, it means:
- They do not have to log in every time.
- Their sessions are automatically renewed without interruption.
- Token revocation can be done centrally.
From a developer’s perspective:
- You can control how and where tokens are stored.
- You have control to enforce policies like session timeouts or token cleanup.
Supported token persistence options
The Zoho CRM SDKs support three token persistence mechanisms:
File Persistence:
As we have already seen in last week's Kaizen, in this method, the tokens are stored in a local file of your choice. This can be configured while configuring and initializing the SDK. While this is simple and great for internal and local use, it might not always meet the needs of a growing business. For instance, if the file gets deleted or corrupted, you lose the tokens. It also poses a security risk, as storing tokens in files may expose them to unauthorised access if the file is not properly secured.
Database Persistence:
This stores tokens in a MySQL database, making it better suited for production environments. It is more robust and can handle larger-scale user management.
Using this persistence method, you can only provide the following connection parameters - host, DB name, table name, username, password, and port number.
Custom Persistence:
But what if neither of these options fits your needs? Maybe you are working in an environment without traditional storage like
AWS's Secret Manager, or you prefer any other Database, or running a microservice in a container where local storage is more practical. That is where Custom Token Persistence comes in.
Custom Token Persistence
Custom persistence means you can implement your own logic for storing and retrieving OAuth tokens, instead of relying on the SDK’s default mechanism. To do this, you should create a class that implements the TokenStore interface and override a standard set of methods, each handling a specific part of the token lifecycle.
Here’s what your custom class must implement:
Method
| Purpose | Return Type |
find_token(self, token) | Given a token, return a full Token (OAuthToken) object from storage. Used before making any CRM API call. | Token(OAuthToken) object |
save_token(self, token) | Called right after Zoho returns a new access/refresh token. Your implementation must persist it. | None |
delete_token(self, id) | Delete a specific token using its unique ID. | None |
get_tokens(self) | Return all stored tokens. | A list of Token(OAuthToken) objects |
delete_tokens() | Delete all stored tokens. Useful during cleanup or logout. | None |
find_token_by_id(id) | Retrieve a token by its unique identifier. | Token(OAuthToken) object |
The token object is an instance of
OAuthToken. The SDK will invoke these methods automatically as part of its flow. You just have to focus on where and how to store the tokens. With this, you can persist tokens to any storage as long as your class handles these methods correctly.
Understanding the token object
Before we dive deeper into custom token persistence, let's clarify what this token (OAuthToken) object is and how you should work with it.
The token object is an instance of
OAuthToken. This class bundles all the credentials and details the SDK needs to authenticate your API requests. Here’s what it holds:
- access_token
- refresh_token
- client_id
- client_secret
- redirect_url
- expires_in
- user_signature
- id
- api_domain
Implementing Custom Token Persistence with SQLite
Now that we've covered the basics of token persistence and how Zoho SDK supports custom stores, let’s dive into a practical, real-world example using SQLite as the backend for storing tokens.
SQLite is a lightweight, file-based database engine. It is perfect when you want a persistent store without the complexity of a full database server.
The CustomStoreSQLite Class
This class implements all six required methods of the TokenStore interface using SQLite as the backend.
1. Initialization and Table Setup
When you create a CustomStoreSQLite object, it immediately checks if the token table exists in the SQLite database file zohooauth.db. If the DB or the table is missing, its __init__() method creates one with all the necessary columns to store token details like id, user_name, client_id, client_secret, refresh_token, access_token, grant_token, expiry_time, redirect_url and api_domain.
def __init__(self):
""" Initializes the SQLite database and sets up the oauthtoken table if needed. """ self.db_name = 'zohooauth.db' if not self.check_table_exists(): connection = sqlite3.connect(self.db_name) cursor = connection.cursor() cursor.execute("CREATE TABLE oauthtoken (id varchar(10) NOT NULL,user_name varchar(255), client_id " "varchar(255), client_secret varchar(255), refresh_token varchar(255), access_token " "varchar(255), grant_token varchar(255), expiry_time varchar(20), redirect_url varchar(" "255), api_domain varchar(255), primary key (id))") cursor.close() |
This means the first time your app runs, it sets up its own database schema automatically.
2. Saving a Token - save_token(self, token)
Purpose:
This method is called every time Zoho returns a new token, whether after a login or a token refresh. Your implementation is responsible for safely persisting this token, typically by upserting (inserting or updating) a row in your database that uniquely identifies the token’s user and client combination.
Expected behaviour:
The method must store the token in your custom database or storage system.
- If a matching token already exists (based on user, refresh token, or client credentials), it should be updated.
- If no match exists, a new entry must be created.
- Tokens should not be duplicated. Multiple users should be managed separately.
Input Parameters: An instance of Token(OAuthToken) class containing details like access token, refresh token, user signature, client ID/secret, etc.
Return value: None. But must raise exceptions on failure.
Sample Implementation using SQLite:
Here is the logic used in the implementation of save_token() method:
- If the user name is available, use it to update the token.
- If no user name but the access token is available in the table, update by the access token.
- If there is a refresh or grant token with the same client credentials, then update accordingly.
- If none of these match, insert as a new row.
def save_token(self, token):
if not isinstance(token, OAuthToken): return cursor = None connection = None try: connection = sqlite3.connect(self.db_name) oauth_token = token query = "update oauthtoken set " if oauth_token.get_user_signature() is not None: name = oauth_token.get_user_signature().get_name() if name is not None and len(name) > 0: query = query + self.set_token(oauth_token) + " where user_name='" + name + "'" elif oauth_token.get_access_token() is not None and len(oauth_token.get_access_token()) > 0 and \ self.are_all_objects_null([oauth_token.get_client_id(), oauth_token.get_client_secret()]): query = query + self.set_token( oauth_token) + " where access_token='" + oauth_token.get_access_token() + "'" elif ((oauth_token.get_refresh_token() is not None and len(oauth_token.get_refresh_token()) > 0) or (oauth_token.get_grant_token() is not None and len( oauth_token.get_grant_token()) > 0)) and oauth_token.get_client_id() is not None \ and oauth_token.get_client_secret() is not None: if oauth_token.get_grant_token() is not None and len(oauth_token.get_grant_token()) > 0: query = query + self.set_token( oauth_token) + " where grant_token='" + oauth_token.get_grant_token() + "'" elif oauth_token.get_refresh_token() is not None and len(oauth_token.get_refresh_token()) > 0: query = query + self.set_token( oauth_token) + " where refresh_token='" + oauth_token.get_refresh_token() + "'" query = query + " limit 1" try: cursor = connection.cursor() cursor.execute(query) if cursor.rowcount <= 0: if oauth_token.get_id() is not None or oauth_token.get_user_signature() is not None: if oauth_token.get_refresh_token() is None and oauth_token.get_grant_token() is None \ and oauth_token.get_access_token() is None: raise SDKException(Constants.TOKEN_STORE, Constants.GET_TOKEN_DB_ERROR1) if oauth_token.get_id() is None: newId = str(self.generate_id()) oauth_token.set_id(newId) query = "insert into oauthtoken (id,user_name,client_id,client_secret,refresh_token,access_token," \ "grant_token,expiry_time,redirect_url,api_domain) values (?,?,?,?,?,?,?,?,?,?);" val = (token.get_id(), token.get_user_signature().get_name() if token.get_user_signature() is not None else None, token.get_client_id(), token.get_client_secret(), token.get_refresh_token(), token.get_access_token(), token.get_grant_token(), token.get_expires_in(), token.get_redirect_url(), token.get_api_domain()) cursor.execute(query, val) except Error as e: raise e finally: connection.commit() cursor.close() if cursor is not None else None connection.close() if connection is not None else None except Exception as ex: raise SDKException(Constants.TOKEN_STORE, Constants.SAVE_TOKEN_DB_ERROR, cause=ex) |
3: Fetching a Token - find_token(self, token)
Purpose:
This is the method the SDK calls whenever it needs to make an API call on behalf of a user, but has only partial token information.
Depending on the token flow - Grant Token, Refresh Token, Access Token, or ID-based - only a specific token or ID may be provided during the API call. In such cases, find_token(self, token) method locates and return the complete OAuthToken object from storage if a matching one exists. If no matching token exists in the storage, this method will return None, and the SDK will proceed to generate a new token with the provided details and save it using the save_token(self, token) method.
Expected behavior:
- Based on the available details in the input token (user name, access token, refresh or grant token), this method should query storage and return a complete token object.
- If no match is found, it should return None.
Input Parameters: A partially filled Token(OAuthToken) object.
Return value: A fully populated Token object if found, or None.
Sample Implementation using SQLite:
The find_token(self, token) method implementation does the following:
- Dynamically builds a WHERE clause based on available attributes.
- Queries the database for a matching record.
- Fetches the matching record, if any, and populates the Token object with the full set of stored values (access token, refresh token, expiry time, etc.).
- Returns the Token object if a matching record is found, or return None.
Without this method, your app wouldn’t know which token to use during API calls. For example, consider the case when a user reopens your app after hours. You have their refresh token stored. The SDK calls find_token(self, token) to get the full token and proceeds without requiring a fresh login.
def find_token(self, token):
cursor = None connection = None try: connection = sqlite3.connect(self.db_name) if isinstance(token, OAuthToken): oauth_token = token query = "select * from oauthtoken" if oauth_token.get_user_signature() is not None: name = oauth_token.get_user_signature().get_name() if name is not None and len(name) > 0: query = query + " where user_name='" + name + "'" elif oauth_token.get_access_token() is not None and self.are_all_objects_null( [oauth_token.get_client_id(), oauth_token.get_client_secret()]): query = query + " where access_token='" + oauth_token.get_access_token() + "'" elif oauth_token.get_refresh_token() is not None or oauth_token.get_grant_token() is not None and \ oauth_token.get_client_id() is not None and oauth_token.get_client_secret() is not None: if oauth_token.get_grant_token() is not None and len(oauth_token.get_grant_token()) > 0: query = query + " where grant_token='" + oauth_token.get_grant_token() + "'" elif oauth_token.get_refresh_token() is not None and len(oauth_token.get_refresh_token()) > 0: query = query + " where refresh_token='" + oauth_token.get_refresh_token() + "'" query = query + " limit 1" cursor = connection.cursor() cursor.execute(query) result = cursor.fetchone() if result is None: return None self.set_merge_data(oauth_token, result) except Exception as ex: raise SDKException(Constants.TOKEN_STORE, Constants.GET_TOKEN_DB_ERROR1, cause=ex) finally: cursor.close() if cursor is not None else None connection.close() if connection is not None else None return token |
4: Deleting a Token - delete_token(self, id)
Purpose:
Delete a specific token record from storage based on a unique token ID. It is commonly used when a user logs out or an admin revokes access for a user.
Expected behaviour:
- Locate the token record by its unique ID.
- Delete the corresponding record from storage.
Input Parameters: The token ID to be deleted.
Return values: None
Sample Implementation using SQLite:
def delete_token(self, id):
cursor = None try: connection = sqlite3.connect(self.db_name) try: cursor = connection.cursor() query = "delete from oauthtoken where id= " + id + ";" cursor.execute(query) connection.commit() except Error as ex: raise ex finally: cursor.close() if cursor is not None else None connection.close() if connection is not None else None except Error as ex: raise SDKException(code=Constants.TOKEN_STORE, message=Constants.DELETE_TOKEN_DB_ERROR, cause=ex) |
5: Deleting All Tokens - delete_tokens(self)
Purpose: Delete all tokens from storage, typically used for global logout or cleanup scenarios.
Expected behaviour: Remove all token records from storage in a single operation.
Input Parameters: None
Return Values: None
Sample Implementation using SQLite:
def delete_tokens(self):
cursor = None try: connection = sqlite3.connect(self.db_name) try: cursor = connection.cursor() query = "delete from oauthtoken;" cursor.execute(query) self.connection.commit() except Error as ex: raise ex finally: cursor.close() if cursor is not None else None connection.close() if connection is not None else None except Error as ex: raise SDKException(code=Constants.TOKEN_STORE, message=Constants.DELETE_TOKENS_DB_ERROR, cause=ex) |
6: Fetch all tokens - get_tokens(self)
Purpose: Retrieve all currently stored tokens.
Expected behaviour:
- Query storage for all token records.
- Construct and return a list of token objects
Input Parameters: None
Return Value: A list of Token objects representing all stored tokens.
Sample Implementation using SQLite:
def get_tokens(self):
cursor = None try: connection = sqlite3.connect(self.db_name) tokens = [] try: cursor = connection.cursor() query = "select * from oauthtoken;" cursor.execute(query) results = cursor.fetchall() for result in results: oauth_token = object.__new__(OAuthToken) self.set_oauth_token(oauth_token) self.set_merge_data(oauth_token, result) tokens.append(oauth_token) return tokens except Error as ex: raise ex finally: cursor.close() if cursor is not None else None connection.close() if connection is not None else None except Error as ex: raise SDKException(code=Constants.TOKEN_STORE, message=Constants.GET_TOKENS_DB_ERROR, cause=ex) |
7. Finding a Token by ID - find_token_by_id(self, id)
Purpose: Retrieve a specific token by its unique id.
Expected behaviour:
- Search storage for a token with the given ID.
- If found, return the complete token object; if not, return None.
Input Parameters: The unique identifier of the token (id)
Return Values: Returns a fully populated Token(OAuthToken) object if found; otherwise, returns None.
Sample Implementation using SQLite:
This method should follows a similar pattern to find_token, but use the unique id as the search key.
def find_token_by_id(self, id):
cursor = None try: connection = sqlite3.connect(self.db_name) try: query = "select * from oauthtoken where id='" + id + "'" oauth_token = object.__new__(OAuthToken) self.set_oauth_token(oauth_token) cursor = connection.cursor() cursor.execute(query) results = cursor.fetchall() if results is None or len(results) <= 0: raise SDKException(Constants.TOKEN_STORE, Constants.GET_TOKEN_BY_ID_DB_ERROR) for result in results: self.set_merge_data(oauth_token, result) return oauth_token except Error as ex: raise ex finally: cursor.close() if cursor is not None else None connection.close() if connection is not None else None except Error as ex: raise SDKException(code=Constants.TOKEN_STORE, message=Constants.GET_TOKEN_BY_ID_DB_ERROR, cause=ex)
|
Please find the complete custom_store_sqlite.py file
here.
How to use this in your project
To start using this custom token persistence class in your own Python project, follow these steps:
- Download the custom_store_sqlite.py and place this inside your project directory.
- Import the class in the script where you initialize the SDK. In our sample project, this is the record.py file.
from store.custom_store_sqlite import CustomStoreSQLite - In the SDK configuration, use the CustomStoreSQLite method instead of the FireStore method:
def init(self, client_id, code, location, redirect_url):
environment = DataCenter.get(location) client_secret = "17565609051856218813123b9a98de52c301722b7d" logger = Logger.get_instance(level=Logger.Levels.INFO, file_path="./logs.txt") store = CustomStoreSQLite() token = OAuthToken(client_id=client_id, client_secret=client_secret, grant_token=code, redirect_url=redirect_url) Initializer.initialize(environment=environment, token=token, logger=logger, store=store) |
That’s it! With this, all token operations (save, fetch, delete) will be routed through your custom store backed by SQLite.
The above video demonstrates this is in action. You can see what the database looks like when populated.
More Custom Persistence Implementations
The advantage of using Zoho CRM SDKs is that it doesn't box you in. You are free to implement token persistence in a way that fits your business logic, team expertise, or project requirements. Whether you prefer SQLite, NoSQL, or something entirely different, the SDK gives you full control through the TokenStore interface.
In the SQLite example above, we walked through how to implement a custom store using a persistent file-based database. You need to implement all the methods as explained in the previous section, no matter where you decide to persist your tokens.
To make things easier, we have included two additional reference implementations:
- An in-memory store, where tokens are stored in a dictionary
- A list-based store, which keeps token records as simple lists
Each one fully implements the required methods of the TokenStore interface.
SQLite In-Memory DB
This implementation uses SQLite's in-memory mode (using ":memory:") to store tokens in RAM. Here, we have implemented all the required methods from the TokenStore interface: find_token(), save_token(), delete_token(), get_tokens(), delete_tokens() and find_token_by_id().
Please find the
custom_store_in_memory.py file
here.
List-Based Persistence Using Simple Lists
The second reference implementation is a list-based token store that keeps token records in an in-memory Python list of lists. Each inner list represents a token’s attributes, such as ID, user signature, client ID, access token, refresh token, and so on.
This custom store fully implements all required methods from the TokenStore interface.
Please find the
custom_store_list.py file
here.
We hope this was useful and gives you enough info to build your own token persistence methods tailored to your needs. We used Python SDK here, but you can apply the same logic with any of our other SDKs. It is all the same logic, just different programming languages. Just remember to implement the required methods exactly as expected by the SDK, as explained here.
Give it a try, and please let us know how it goes or if you hit any bumps! Comment below, or send an email to
support@zohocrm.com. We will be waiting to hear from you!
Happy coding!
We are excited to be approaching the 200th post in our Kaizen series! As we get closer to this milestone, we would love to hear from you. Have questions, suggestions, or topics you would like us to cover in our future Kaizen posts? Your feedback helps us make the series even better.
Please take a moment to share your thoughts with us using this form - we'd really appreciate it!
Recent Topics
Price Managment
I have been in discussions with Zoho for some time and not getting what I need. Maybe someone can help explain the logic behind this for me as I fail to understand. When creating an item, you input a sales rate and purchase rate. These rates are just
Related to zoho survey
Hi team. I want to know something regarding zoho survey question builder. I have two questions each of dropdown (One answer) - question type. In the first question, there are 16 answer choices and in the second question, there are 3 answer choices. For
60 Days Into Zoho - Tiktok Branding Startup -7 Questions?!
Wsp Everybody I co-own a TikTok Branding / Consulting Startup & have been using Zoho for the past 60 days - Am now looking to make our overall operations & processes more Efficient & Effective! Curious to know how others are using the platform & what's
Text Message
When trying to sent a text message, it says its an error i should contact a zoho agent
Zoho POS is now available for Canadian retailers
Hey everyone, We're excited to introduce the all-new Canadian edition of Zoho POS, which helps retail businesses simplify and manage their end-to-end business operations. Start by signing up and exploring the 15-day free trial. Sign up now How does Zoho
Payroll In Canada
Hi, When can we expect to have payroll in Canada with books
Mass update to change or shift all project dates and keep project structure + shift all sub-tasks dates with main tasks
Most users would expect that if they change the start date of their project then that will be reflected inside the actual project and any project structure would be retained. Additionally if a task list with associated sub-tasks is moved, most users would expect that those sub-tasks would also be moved along with their parent task. This is not the case. For a total Project shift of dates: * the start and end date from > "Edit Project" page can have a radio button added to "shift all project tasks
Closing Accounting Periods - Invoice/Posting dates
Hi, I have seen in another thread but I'm unsure on how the 'transaction locking' works with regards to new and old transactions. When producing monthly accounts if I close December 24 accounts on 8th Jan 25 will transaction locking prevent me from posting
In-person ZUG Meetups for Real Estate Professionals - US Q1 2026
The Real Estate Zoho User Group is going on a multi-city, in-person meetup tour across the US, and we’d love to see you there! These meetups are a great opportunity to: Connect with fellow real estate professionals using Zoho Share challenges and discover
Zoho CRM custom fields not showing in zoho creator
Hi Team, I have created a Products form with Zoho CRM integration and connected it to Products module of CRM. But when I see the reports of Products in Zoho creator then I am not able to see custom fields of Products module. Only standard fields of Products
Sending email notifications based on language
Hello. I would like to know how we can bypass the default notifications (which are just in English) for when a ticket is created/replied to/closed, to be in other languages, based on the language field in the ticket? I can create other email templates,
Zoho Error: This Operation has been restricted. Please contact support-as@zohocorp.com for further details
Hello There, l tried to verify my domain (florindagoreti.com.br) and its shows this error: This Operation has been restricted. Please contact support-as@zohocorp.com for further details. Screenshot Given Below - please check what went wrong. Thanks
Download a file from within a zoho creator widget
I have a widget running in Zoho Creator , it displays uploaded documents in a table file, and I have added a download link in the view. ( The widget is created with html, css and javascript). I do not succeed in getting the download working. Do I have
Correlated subqueries not supported in Zoho Analytics. This creates huge limitations
Running into a major limitation in Zoho Analytics: correlated subqueries simply don’t work, even in completely standard SQL patterns inside a JOIN. Example: LEFT JOIN "Bills" b
ON d."Id" = b."Deal ID"
AND EXISTS (
SELECT 1
FROM "Bill
Zoho / Outlook Calendar sync
The current Marketplace -> Microsoft -> Meetings integration needs 2 changes. 1. The current language for the Two-Way sync option should be changed. It currently states, "Sync both your Zoho CRM Calendar and Office 365 Calendar meetings with each other."
Email content just contain 'OK' ,not what we expect
create campaign API URL: https://campaigns.zoho.com/api/v1.1/createCampaign req params: {'campaignname': 'General_Outreach_d0cfc415-43aa-4b96-bb09-558e76a3dda3_50_20251117_214806_660', 'from_email': 'admin@allinmedia.ai', 'subject': 'ALL IN MEDIA', 'list_details':
Possible to connect Zoho CRM's Sandbox with Zoho Creator's Sandbox?
We are making some big changes on our CRM so we are testing it out in CRM's Sandbox. We also have a Zoho Creator app that we need to test. Is it possible to connect Zoho CRM's Sandbox to Zoho Creator's Sandbox so that I can perform those tests?
Reopen ticket
Hello! Can I reopen a ticket just using the API ticket/sendReply ? What's the rules to do it? I'm trying but it doesn't reopen the ticket, it just send the reply
Allow Admins to Transfer Ownership of Their Own Files & Folders
Hi Zoho WorkDrive Team, Hope you are doing well. We would like to request an important enhancement to the ownership-transfer functionality in Zoho WorkDrive, specifically regarding administrator capabilities. As administrators, we have the ability to
Tip#46: Capture accurate log hours
Hello everyone, Use the newly introduced timer settings that will streamline the usage of timers and help admins or workspace owners to manage the time entries of the workspace users better. Check out the below mentioned timer settings added to the Timesheet
Moving to app-specific authentication for Google integrations
Hello everyone, We’re making an important change to how Google integrations work in our platform. Until now, we used a common Google project across Zoho to enable integrations like Google Drive, Calendar, and more. Going forward, we’ll be moving to an
Lost the ability to sort by ticket owner
Hi all, in the last week or so, we have lost the ability to sort tickets by Ticket Owner. Unlike the other columns which we can hover over and click on to sort, Ticket Owner is no longer clickable. Is it just us, or are other customers seeing this too?
How Can i put a form in Zobot
Hi,how can i integrate a form which has a multiple options to choose from.the form should be opened or displayed by zobot after it meets a requirement in the conversation. Thanks in advance !
Playback and Management Enhancements for Zoho Quartz Recordings
Hello Zoho Team, We hope you're all doing well. We would like to submit a feature request related to Zoho Quartz, the tool used to record and share browser sessions with Zoho Support. 🎯 Current Functionality As of now, Zoho Quartz allows users to record
Zoho Analytics - Feature Request For Time Based Data Source Fetch
Hi Analytics Team, I have a client using Zoho CRM and they want a weekly report at 4:30pm every Friday, emailed to the sales team showing a pie chart of Closed Won Deals for that week. This is easy to achieve in Analytics but not so easy to ensure the
Which user's capacity is used for Shared Mailbox storage?
We use shared mailboxes at our company, and their size is increasing daily. Which user(s)'s total mailbox limit is being used up by this space?
Inserting the current date / time
I'd like to use Zoho Notebook as a log - so it would be great to be able to insert the current date and time at the beginning (or end) of each my log/journal entries - or wherever I want. Something simple, like pressing a button/icon to insert it wherever my text cursor is. It could be formatted like "Mon Dec 11, 2017 - 11:43p".
Migrate data from old to new account
Hy, Have one Old Zoho Notebook Account with Data , want to migrate that whole Data to New Zoho Notebook Account which is in Zoho One . Is that possible ? If Yes then how?
Campaign editor overrides href value
I've been trying to insert a deep link in an email campaign so recipients can directly open a native app on their device. My deep link looks something like "myapp://". The options to insert links in the campaign editor are limited to strict urls, emails,
how to add subform over sigma in the CRM
my new module don't have any subform available any way to add this from sigma or from the crm
Bug Report and Suggestions for Improvement in Zoho Applications
Hi Zoho Team, I’d like to report a few bugs and improvement suggestions I’ve noticed while using Zoho products: Zoho Cliq Video Call: The camera sometimes turns off automatically during video calls. This seems to be a bug — please check and fix it. Zoho
Canvas Flex Box containers should not require a width/height.
Flexbox containers are often used as organizational concepts, to ease re-flow on mobile etc. - I cannot use % for flexbox W or H - I cannot omit W or H This means that the content cannot dictate, and a Flexbox container cannot be used merely as an organizational
Zoho Desk Android app update: Filter enhancement, Save Filters
Hello everyone! We have now enhanced the filter section on the ticket listing screen of Zoho Desk Android app as it is on the web(desk.zoho.com). Also, we have introduced an option to save filters for tickets on the mobile app. You can easily apply, rename,
Very long loading times | bad performance [ZOHO DC: EU]
Hello there, we have recently noticed that the loading times have become extremely long when retrieving tickets and ticket details. For example, I open any ticket and get the following view. The subject and standard information (ticket owner, status etc.)
Zia Profile Summary now supports six languages and responds faster
After numerous customer requests, we’ve expanded Zia Profile Summary to do more than just summarize resumes quickly. It can now summarize them in six different languages and deliver results even faster. What’s New 1. Extended language support Zia can
Introducing Zoho Show Android 3.0
Good ideas need the right space to grow. They deserve tools that move as fast as your thoughts and make creating feel effortless. And that is why we are bringing you Zoho Show Android 3.0! From a brand-new look and smoother navigation to improved collaboration
Properly Capture Dropdowns & Hover Elements When Recording a Window/Tab
Hi Zoho WorkDrive Team, Hope you are doing great. We encountered a limitation when recording a selected window or browser tab: Certain UI elements, such as dropdown lists, hover menus, and overlays, are not captured unless we record the entire screen.
Peppol integration zoho invoicefu
Hi, Belgium will require Peppol invoicing as of 2026. I found that this is being prepared for Zoho books, to be released in Sep 2025. Will Zoho Invoice get this functionality too? I like the Invoice app for my part-time side business as bike mechanic
Allow Recording Only a Selected Portion of the Screen
Hi Zoho WorkDrive Team, Hope you are doing well. We would like to request a more flexible recording option in Zoho WorkDrive. At the moment, we can record either the entire screen or a specific window/tab — but not a custom selected portion of the screen
Restricting Calendar View to Working Hours
Hi: I'm trying to implement a calendar which displays all of my customer appointments. Currently, the calendar shows all 24 hours of the day. Is there a way to restrict the hours to simply the times my business is open? Thanks!
Next Page