# Python -------------------------------------------------------------------------------- title: "Introduction" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.683Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/introduction/" service: "All Services" related: - Project Directory Structure (/en/cli/v1/project-directory-structure/introduction/) - Catalyst SDK for AppSail (/en/serverless/help/appsail/key-concepts/catalyst-configurations/#implementing-catalyst-sdk-in-appsail/) -------------------------------------------------------------------------------- # Lead Manager App Using AppSail ### Introduction This tutorial will help you build a **Python Flask** application web application called **Lead Manager**. This web app will allow you to connect with your {{%link href="https://www.zoho.com/in/crm/" %}}Zoho CRM account{{%/link%}} and enable you to manage leads in your organization. You will be able to access, add, edit, or delete leads in the {{%link href="https://help.zoho.com/portal/en/kb/crm/sales-force-automation/leads"%}}Leads module{{%/link%}} in your CRM account directly from this application. The connection to Zoho CRM is established using {{%link href="/en/api/oauth2/overview-and-terminology/#OverviewandTerminology" %}}OAuth 2.0 authentication protocol{{%/link%}}. We will generate an {{%badge%}}OAuth Access Token{{%/badge%}} for the *Lead Manager* application and use it to authorize the connection to access CRM data. The authentication requirement in this tutorial is handled using {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication{{%/link%}}. We will also implement a {{%link href="/en/sdk/java/v1/connectors/connectors/" %}}Catalyst Connector{{%/link%}} to manage this access to the CRM account. The connector will refresh the {{%badge%}}Access Token{{%/badge%}} automatically each time it expires using a {{%badge%}}Refresh Token{{%/badge%}}, and will maintain a constant connection between the client and the CRM account. These tokens can be generated after registering the client application in the {{%link href="https://api-console.zoho.com/" %}}Zoho API console{{%/link%}} and obtaining the required credentials. The client application will look like this: <br /> The Lead Manager application employs components from the following Catalyst services: - {{%link href="/en/serverless/" %}}**Catalyst Serverless**{{%/link%}}: - {{%link href="/en/serverless/help/appsail/introduction/" %}}AppSail{{%/link%}}: To host the independent *Python Flask* application. We will be building the front-end of the app as well as the back-end logic, and bundling them together to deploy them on AppSail. - {{%link href="/en/cloud-scale/" %}}**Catalyst CloudScale**{{%/link%}}: - {{%link href="/en/cloud-scale/help/data-store/introduction/" %}}Data Store{{%/link%}}: To store the {{%badge%}}Refresh Token{{%/badge%}} and {{%link href="/en/cloud-scale/help/authentication/user-management/users/introduction/" %}}UserID of the Catalyst user{{%/link%}} fetched by the function resource. The {{%badge%}}Refresh Token{{%/badge%}} is fetched from this table by the function, whenever a new {{%badge%}}Access Token{{%/badge%}} needs to be generated. - {{%link href="/en/cloud-scale/help/zcql/introduction/" %}}ZCQL{{%/link%}}: To fetch data from the *Data Store* through querying. - {{%link href="/en/cloud-scale/help/authentication/introduction/" %}}Catalyst Authentication{{%/link%}}: To implement a {{%link href="/en/cloud-scale/help/authentication/social-logins/configuring-social-logins/#enable-zoho-social-login" %}}Zoho social login{{%/link%}} in the client application’s login page, in addition to the standard login option, we will be implementing the {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication type{{%/link%}} in this tutorial. We will use the {{%link href="https://console.catalyst.zoho.com" %}}Catalyst web console{{%/link%}} and the {{%link href="/en/cli/v1/cli-command-reference/" %}}Catalyst Command Line Interface{{%/link%}} (CLI) to build this application. {{%info%}}{{%bold%}}Info:{{%/bold%}} You will be given the code for the files to be included in the function and client components in this tutorial. You will just need to copy the provided code and paste it into the appropriate files as directed.{{%/info%}} ### Application Architecture The Lead Manager application’s architecture is depicted below: <br /> The entire workflow of the application will be explained in more detail when you {{%link href="/en/tutorials/leadmanager-appsail/flask/code-app" %}}code your front end logic{{%/link%}}, which we recommend you check out as you follow along the steps. -------------------------------------------------------------------------------- title: "Prerequisites" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.690Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/prerequisites/" service: "All Services" related: - Catalyst Tools VS Code Plugin (/en/catalyst-extensions/vs-code-extension/introduction/) -------------------------------------------------------------------------------- # Prerequisites Before you begin building the application, you must have the following prerequisites installed on your system: 1. **Catalyst CLI**: Catalyst CLI contains a host of tools that enable you to initialize, develop, test, and deploy the components of your application from your local machine. We will be working with Catalyst CLI in this tutorial. You must perform these actions: - {{%bold%}}Install Catalyst CLI{{%/bold%}}: Catalyst CLI is installed through NPM. You must therefore have NPM and Node.js installed on your system before you install the CLI. Refer to the {{%link href="/en/getting-started/installing-catalyst-cli/" %}}{{%bold%}}Install Catalyst CLI help page{{%/bold%}}{{%/link%}} for details on the pre-requisites and the steps to install it. - {{%bold%}}Login Catalyst CLI{{%/bold%}}: After you install Catalyst CLI, you must authenticate the CLI with your Catalyst account before using it. Refer to the {{%link href="/en/cli/v1/login/login-from-cli/" %}}{{%bold%}}CLI Login help page{{%/bold%}}{{%/link%}} for the steps to login from Catalyst CLI and the various options available for it. 2. **Zoho CRM Account**: Because the Leads module is available in all editions of Zoho CRM, you can have a configured Zoho CRM account of any edition to establish a connection with the Lead Manager application. If you don’t have a Zoho CRM account, you can sign up for it {{%link href="https://www.zoho.com/in/crm/" %}}here{{%/link%}}. 3. **Install Python 3.9**: Catalyst currently supports any version of Python up to 3.9. If you have a higher version already installed in your system, ensure that you have Python 3.9 installed as well. You can download the package from this {{%link href="https://www.python.org/downloads/release/python-3913/" %}}page{{%/link%}}. 4. **Any IDE tool for Python and client code development** You can use any IDE to work with the function and the client code. Some popular choices include Visual Studio Code, PyCharm, IDLE, and Sublime Text. Download and install an IDE of your choice in your system. {{%info image="/images/tutorials/todo-list/vscode.png"%}}If you are a Visual Studio Code IDE user, you can install the {{%bold%}}Catalyst Tools{{%/bold%}} extension, and use your IDE itself in place of the CLI. You can find more details about the Catalyst VS Code extension from this {{%link href="/en/catalyst-extensions/vs-code-extension/introduction/" %}}help section{{%/link%}}.{{%/info%}} -------------------------------------------------------------------------------- title: "Create a Project" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.690Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/create-project/" service: "All Services" related: - Project Directory Structure (/en/cli/v1/project-directory-structure/introduction/) - Catalyst SDK for AppSail (/en/serverless/help/appsail/key-concepts/catalyst-configurations/#implementing-catalyst-sdk-in-appsail/) -------------------------------------------------------------------------------- # Create a Project Let’s {{%link href="/en/getting-started/catalyst-projects/#creating-a-catalyst-project" %}}create a Catalyst project{{%/link%}} from the Catalyst console. 1. Log in to the {{%link href="https://console.catalyst.zoho.com/baas/index" %}}Catalyst console{{%/link%}} and click **Create New Project**. <br /> 2. Enter the project’s name as "**LeadManager**" in the pop-up window. <br /> Your project will be created. You can open the project by clicking **Access Project**. <br /> -------------------------------------------------------------------------------- title: "Create a Table" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.690Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/create-table/" service: "All Services" related: - Data Store (/en/cloud-scale/help/data-store/introduction/) - ZCQL (/en/cloud-scale/help/zcql/introduction) -------------------------------------------------------------------------------- # Create a Table Next, let’s create a table in the **Data Store**. This table is used to store the *Refresh Token* and {{%badge%}}userID{{%/badge%}} values, which are retrieved whenever an *Access Token* needs to be generated. To create a table: 1. Navigate to the {{%link href="/en/cloud-scale/" %}}Catalyst Cloud Scale{{%/link%}} service section in the console and click **Start Exploring**. <br /> 2. Click **Create a new Table**. <br /> 3. Enter the table’s name as "{{%badge%}}Token{{%/badge%}}" and click **Create**. <br /> {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure that you enter the name exactly as instructed because the application's code contains the same name.{{%/note%}} The table will be created. <br /> Now, let’s create two columns in the table to store the {{%badge%}}userID{{%/badge%}} and the {{%badge%}}refresh token{{%/badge%}} respectively. {{%info%}}{{%bold%}}Info:{{%/bold%}} You can learn about the various data types supported by Catalyst and the other properties of a column from the {{%link href="/en/cloud-scale/help/data-store/introduction/" %}}Data Store help documentation{{%/link%}}.{{%/info%}} 4. Click **New Column** in the *Schema View* section. <br /> 5. Enter the column’s name as "refresh_token". Select the data type as Encrypted Text. <br /> 6. Click **Create**. <br /> 7. Now click the **New Column** button again to create the second column. Name it "{{%badge%}}userId{{%/badge%}}", and select **BigInt** as its data type. <br /> 8. Click **Create**. <br /> The required columns have been created. ### Configure Scopes and Permissions To allow any user of the Lead Manager application to view or manage leads from the client application, you must enable an additional {{%link href="/en/cloud-scale/help/data-store/scopes-and-permissions" %}}table permission{{%/link%}} that will allow the user to fetch and store new *Refresh Tokens*, if needed. To enable the required permissions: 1. Click the **Scopes and Permissions** tab. <br /> 2. Enable the **Insert** permission for the **App User** role under the *Table Permissions* section. Ensure you do not change any other permission setting. <br /> The Data Store component is now configured for the application. -------------------------------------------------------------------------------- title: "Enable Zoho Social Login" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.690Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/enable-auth/" service: "All Services" related: - Authentication (/en/cloud-scale/help/authentication/introduction/) - Embedded Authentication (/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/) - Enable Social Login (/en/cloud-scale/help/authentication/social-logins/configuring-social-logins/) - Public Sign Up (/en/cloud-scale/help/authentication/public-signup/) -------------------------------------------------------------------------------- # Enable Zoho Social Login Using Embedded Authentication The Lead Manager application contains a login page where you must provide valid credentials to access your Zoho CRM account. You need to implement a signup functionality for this application. The functionality should also provide the option to login to the account using {{%link href="/en/cloud-scale/help/authentication/social-logins/configuring-social-logins/#enable-zoho-social-login" %}}Zoho Social Logins{{%/link%}}. We will be implementing the {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication type{{%/link%}} to complete this requirement. To configure the Zoho social login for the Lead Manager application from the console: 1. Navigate to the **Authentication** component under the *Security & Identity* section, and click **Setup** in the **Native Catalyst Authentication** tab. <br /> 2. Select **Embedded Authentication**, and click **Next**. <br /> 3. You can copy and use the scripts provided in the **Configuration** step to setup your login functionality. However, since we are only going to be using *Zoho social login*, you need to enable the **Public Signup toggle** first. <br /> 4. Click **Yes, Proceed** in the dialog box after going through it. <br /> 5. Click the **Zoho** button to enable the social login. <br /> 6. Provide "{{%badge%}}LeadManagerApp{{%/badge%}}" as the *Client Name* and click **Enable**. <br /> 7. Click **Next**. <br /> 8. We will not be configuring any additional authentication settings for our application. Click **Finish**. <br /> **Embedded Authentication** has been enabled for the application, and users can now login to the app using the **Zoho social login**. <br /> -------------------------------------------------------------------------------- title: "Initialize the Project" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.690Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/init-project/" service: "All Services" related: - Catalyst CLI (/en/cli/v1/cli-command-reference/) - Initialize Resources (/en/cli/v1/initialize-resources/introduction/) - Catalyst AppSail Help (/en/serverless/help/appsail/introduction/) - Project Directory (/en/cli/v1/project-directory-structure/introduction/) -------------------------------------------------------------------------------- # Initialize the Project You can now begin working on your Catalyst project from the CLI. The first step is to initialize the project in an empty directory. This will be the home directory of your project, and all of the project files will be saved in it. You can learn more about this from the {{%link href="/en/cli/v1/project-directory-structure/introduction/" %}}Project Directory Structure help page{{%/link%}}. You can learn about initializing a project in detail from the {{%link href="/en/cli/v1/initialize-resources/introduction/" %}}CLI help documentation{{%/link%}}. For this application, you will be initializing the {{%link href="/en/serverless/help/appsail/introduction/" %}}AppSail{{%/link%}} component alone. The *AppSail* component will be initialized in the **Node.js** programming stack. 1. Create a folder for the project on your local machine and navigate to it from the terminal. 2. Initialize a project by executing the following command from that directory: {{%cli%}}catalyst init{{%/cli%}} 3. Navigate using the **arrow keys** and select your preferred portal and click **Enter**. If you have no other organizations associated with the account, then the default will be selected automatically. <br /> {{%info%}}{{%bold%}}Info:{{%/bold%}} You can find out more about Catalyst’s multi-org portal feature in this {{%link href="/en/getting-started/catalyst-organizations/#access-the-multi-org-portal" %}}help document{{%/link%}}.{{%/info%}} 4. The CLI will now ask you to associate a Catalyst project with the directory. Associate it with the project that we created earlier from the console. Select **LeadManager** from the list and click **Enter**. <br /> 5. Select **AppSail** using the space bar, then click **Enter** to initialize. <br /> 6. The CLI will prompt you to choose between {{%link href="/en/serverless/help/appsail/catalyst-managed-runtimes/key-concepts/" %}}Catalyst-Managed Runtime{{%/link%}} and {{%link href="/en/serverless/help/appsail/custom-runtimes/container-registry-services/" %}}Docker Image{{%/link%}}. Because you are creating this project from one of the Catalyst-Managed Runtime, select **Catalyst-Managed Runtime** and click **Enter**. <br/> 7. The CLI will initiate the *AppSail* service. - As you are creating your own project, enter "{{%badge%}}n{{%/badge%}}" and click **Enter** for the prompt asking if you wish to get started with a list of recommended projects. <br /> - Enter "{{%badge%}}Y{{%/badge%}}" in the prompt to initialize the *AppSail* service in your current directory. <br /> 8. Enter "{{%badge%}}LeadManagerApp{{%/badge%}}" as the name of your AppSail service, and enter your project directory path as the build path of your AppSail service. <br /> 9. Choose the latest runtime of **Python** as the programming stack, and click **Enter**. <br /> The AppSail service has been initialized for your Lead Manager application. <br /> The directory will be created in the standard structure, and it will contain the {{%link href="/en/serverless/help/appsail/key-concepts/catalyst-configurations/#the-app-configjson-file" %}}{{%badge%}}app-config.json{{%/badge%}}{{%/link%}} file which includes the configuration of your AppSail service , along with the standard project configuration files such as the {{%link href="/en/cli/v1/project-directory-structure/catalyst-json/" %}}{{%badge%}}catalyst.json{{%/badge%}}{{%/link%}} file and a hidden {{%badge%}}.catalystrc{{%/badge%}} file. This is the structure of the **LeadManager** project’s directory initialized with the *AppSail* service. <br /> ### Deploy the Application You need to deploy the application to the console to fetch the required **application URL**. We need this URL when we register the client in the {{%link href="https://api-console.zoho.com/" %}}Zoho API console{{%/link%}} to get the required {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values. {{%info%}}{{%bold%}}Info:{{%/bold%}} We will be re-deploying the application service once we have completed coding and adding the {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values to the application.{{%/info%}} Enter the following CLI command to deploy the application: {{%cli%}}catalyst deploy{{%/cli%}} Now, to acquire the application URL: 1. Navigate to the {{%link href="/en/serverless/help/appsail/introduction/" %}}AppSail{{%/link%}} component present under the *COMPUTE* section of the **Catalyst Serverless** section of the console. <br /> You will be able to view that your application has been deployed as an AppSail service. 2. Now click your AppSail service, and you will be able to view the application URL. <br /> {{%info%}}{{%bold%}}Info:{{%/bold%}} We will discuss more about the {{%badge%}}catalyst deploy{{%/badge%}} CLI command and the AppSail service, after we re-deploy the application, towards the end of the tutorial.{{%/info%}} ### Create Additional Folders & Files You need to create two folders in the root directory to store your client code: * {{%badge%}}**static**{{%/badge%}}: Will contain the JS and CSS scripts required to complete the application * {{%badge%}}**templates**{{%/badge%}}: Will contain the HTML code of the app You also need to execute the following command to create the "**main.py**" code file. {{%cli%}}touch main.py{{%/cli%}} This file will be used to store your backend code. This is the current structure of the LeadManager project’s directory: <br /> -------------------------------------------------------------------------------- title: "Register the Client" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.694Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/register-client/" service: "All Services" related: - Catalyst Authentication (/en/cloud-scale/help/authentication/introduction/) - Social Logins (/en/cloud-scale/help/authentication/social-logins/introduction/) -------------------------------------------------------------------------------- # Register the Client We must now register the client application in the {{%link href="https://api-console.zoho.com/" %}}Zoho API console{{%/link%}} to generate the following credentials: - {{%badge%}}**Client ID**{{%/badge%}}: The unique key generated for a registered client - {{%badge%}}**Client Secret**{{%/badge%}}: The secret value generated for a registered client’s {{%badge%}}Client ID{{%/badge%}} The {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} are added to the backend and frontend code in several places. These values are necessary to generate the {{%badge%}}{{%bold%}}Access Token{{%/bold%}}{{%/badge%}} and {{%badge%}}{{%bold%}}Refresh Token{{%/bold%}}{{%/badge%}} initially, and later to refresh the {{%badge%}}{{%bold%}}Access Token{{%/bold%}}{{%/badge%}} using the {{%badge%}}{{%bold%}}Refresh Token{{%/bold%}}{{%/badge%}}. To register the client application in the Zoho API console: 1. Visit the {{%link href="https://api-console.zoho.com/" %}}Zoho API Console{{%/link%}} and click **Get Started**. <br /> 2. Select **Server-based Applications** as the client type. <br /> 3. Enter "{{%badge%}}LeadManagerApp"{{%/badge%}} as the **Client Name**. <br /> 4. Provide the other details in the following format: - Homepage URL: **AppSail application URL** - Authorized Redirect URIs: **AppSail applicationURL/generateToken** <br /> Replace {**AppSail applicationURL**} with the application URL you acquired when you deployed your project earlier in this {{%link href="/en/tutorials/leadmanager-appsail/flask/init-project/#deploy-the-application" %}}step{{%/link%}}. 5. You will need to add another **Authorized Redirect URI** for the client. We will serve the app through a **localhost** to test it after configuring the code. Because this will be redirected to a local domain, we must add that as another authorized redirect URI. <br /> {{%info%}}{{%bold%}}Info:{{%/bold%}} When you serve an application locally from the CLI, it is hosted from {{%badge%}}port 3000{{%/badge%}} by default, unless the port is otherwise occupied. So ensure you are adding the domain accordingly.{{%/info%}} 6. Click **Create**. <br /> The API console will generate and display the {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values for the registered client. You will need to copy these values and paste them into the frontend and backend code of your application. We will discuss this in the following sections. -------------------------------------------------------------------------------- title: "Install the Dependencies" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.694Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/init-dependencies/" service: "All Services" related: - Python SDK (/en/sdk/python/v1/overview/) -------------------------------------------------------------------------------- # Install Flask and the Required Dependencies in a Virtual Environment To employ this Python Flask app, we will need to create a virtual environment in your system. You can create a virtual environment by executing the following commands in your terminal. {{%tabs%}} {{%tab "For Linux/Mac Users" %}} {{%cli%}}python3.9 -m venv myenv{{%/cli%}}<br /> {{%cli%}}source myenv/bin/activate{{%/cli%}} {{%/tab%}} {{%tab "For Windows Users" %}} {{%cli%}}python3.9 -m venv myenv{{%/cli%}}<br /> {{%cli%}}myenv\Scripts\activate{{%/cli%}} {{%/tab%}} {{%/tabs%}} <br /> Now in the virtual environment you have just created, execute the following CLI command to install **Flask** and the required {{%link href="/en/sdk/python/v1/overview/" %}}Catalyst SDK{{%/link%}}. {{%cli%}}python3 -m pip install zcatalyst-sdk{{%/cli%}} <br /> {{%note%}}{{%bold%}}Note:{{%/bold%}} You can find out more about Catalyst SDK for AppSail from this {{%link href="/en/serverless/help/appsail/key-concepts/catalyst-configurations/#implementing-catalyst-sdk-in-appsail" %}}help documentation{{%/link%}}.{{%/note%}} After you install the packages, your project directory will appear like this: <br /> All the required packages for your Python Flask application have been installed. -------------------------------------------------------------------------------- title: "Code Your Application" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.694Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/code-app/" service: "All Services" related: - Web SDK for Authentication (/en/sdk/web/v4/cloud-scale/authentication/get-auth-instance/) -------------------------------------------------------------------------------- # Code Your Application Let’s begin coding the application. The backend logic of your application will be coded in the {{%badge%}}**main.py**{{%/badge%}} file present in the {{%badge%}}LeadManager/{{%/badge%}} directory. The front end of your code will be stored in the following manner: * In the {{%badge%}}LeadManager/templates/{{%/badge%}} directory, create the following files: - {{%badge%}}**index.html**{{%/badge%}}: Contains the HTML code for the front-end of the application. - {{%badge%}}**login.html**{{%/badge%}}: Contains the HTML code to enable {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication{{%/link%}} for the application. * In the {{%badge%}}LeadManager/static/{{%/badge%}} directory, create the following files: - {{%badge%}}**main.css**{{%/badge%}}: Contains the styling elements required for the app - {{%badge%}}**main.js**{{%/badge%}}: Contains the JavaScript code that connects the front-end and backend. This is the final folder structure of the LeadManager project: <br /> You will be coding the {{%badge%}}main.py{{%/badge%}}, {{%badge%}}index.html{{%/badge%}}, {{%badge%}}login.html{{%/badge%}}, {{%badge%}}main.css{{%/badge%}}, and {{%badge%}}main.js{{%/badge%}} files. You will also be updating the {{%badge%}}app-config.json{{%/badge%}} file. {{%note%}}{{%bold%}}Note:{{%/bold%}} Please go through the code in this section to make sure you fully understand it.{{%/note%}} Copy the code below and paste it into the respective files of your project using an IDE and save the files. {{%panel_with_adjustment class="language-python line-numbers" header="main.py" footer="button" scroll="set-scroll" %}}import sys sys.path.insert(0, './myenv/lib/python3.9/site-packages') from flask import Flask, request, jsonify,make_response,redirect import os import json import requests from flask.templating import render_template import zcatalyst_sdk import logging import os app = Flask(__name__, static_url_path='/', static_folder='static', template_folder='templates') apiUrl = "https://www.zohoapis.com/crm/v2/Leads" url = "https://accounts.zoho.com/oauth/v2/token" GET = "GET" POST = "POST" PUT = "PUT" DELETE = "DELETE" CLIENT_ID = '1000.CWDUB3ILOINSFI6J05T66FT39D4W8P' #Add your client ID CLIENT_SECRET = '13ed6e3f5cddbf10201f5bacb8a4bc5536af4bf4ae' #Add your Client Secret logger = logging.getLogger() @app.route('/') def index(): return render_template('index.html') @app.route('/index.html') def indexhtml(): return render_template('index.html') @app.route('/login.html') def login(): return render_template('login.html') @app.route('/generateToken',methods=['GET']) def generateToken(): try: app = zcatalyst_sdk.initialize(req=request) user_management_service = app.authentication() Datastore = app.datastore() code = request.args.get('code') userDetails = user_management_service.get_current_user() user_id = userDetails["user_id"] is_local = os.getenv('X_ZOHO_CATALYST_IS_LOCAL') == 'true' protocol = 'http' if is_local else 'https' host = request.headers['host'] if is_local else request.headers['host'].split(':')[0] domain = f"{protocol}://{host}" logger.info(f'domain:{domain}') tab = Datastore.table('12096000001648196') #replace with your Table ID refresh_token = getRefreshToken(code,domain) logger.info(f'refresh_token',refresh_token) row = {"refresh_token":refresh_token,"userId":user_id} tab.insert_row(row) redirect_uri = f"{domain}/index.html" return redirect(redirect_uri) except Exception as err: logger.error(f'Error on generateToken:{err}') response = make_response(({ "message": "Internal Server Error. Please try again after sometime.", "error": err, }), 500) return response @app.route('/getUserDetails',methods=['GET']) def UserDetails(): try: app = zcatalyst_sdk.initialize(req=request) userDetails = getUserId(app) if len(userDetails) != 0: response = make_response({ "userId":userDetails[0]["Token"]["userId"] },200) else: response = make_response({ "userId":None },200) return response except Exception as err: response = make_response({ "message":"Internal Server Error in Getting User Details. Please try again after sometime.", "error":err },500) return response @app.route('/crmData',methods=['GET']) def crmData(): try: app = zcatalyst_sdk.initialize(req=request) userDetails = getUserId(app) accesstoken = getAccessToken(userDetails,app) getAccess_Token = json.loads(accesstoken) access_token = getAccess_Token['access_token'] headers = { 'Authorization':f'Zoho-oauthtoken {accesstoken}', "Content-Type": "application/json" } response1 = requests.get(apiUrl,headers=headers) response = make_response(jsonify(response1.json()),200) return response except Exception as err: logger.error(err) response = make_response({ "message":"Internal Server Error.Please try again after sometime" },500) return response @app.route('/crmData',methods=['POST']) def postcrmData(): try: app = zcatalyst_sdk.initialize(req=request) data = {"data": [json.loads(request.data)]} userDetails = getUserId(app) accesstoken = getAccessToken(userDetails,app) getAccess_Token = json.loads(accesstoken) access_token = getAccess_Token['access_token'] headers = { 'Authorization':f'Zoho-oauthtoken {accesstoken}', "Content-Type": "application/json" } response1 = requests.post(apiUrl,headers=headers,json=data) if response1.status_code == 200 or response1.status_code == 201: response = make_response((response1.json()),200) return response else: logger.error(response1.json()) response = make_response((response1.json()),500) return response except Exception as err: logger.error(err) response = make_response({ "message":"Internal Server Error.Please try again after sometime" },500) return response @app.route('/crmData/&lt;id&gt;',methods=['GET']) def getCRMData(id): try: app = zcatalyst_sdk.initialize(req=request) userDetails = getUserId(app) accesstoken = getAccessToken(userDetails,app) getAccess_Token = json.loads(accesstoken) access_token = getAccess_Token['access_token'] headers = { 'Authorization':f'Zoho-oauthtoken {accesstoken}', "Content-Type": "application/json" } path = f"/{id}" response1 = requests.get(apiUrl+path,headers=headers) response = make_response((response1.json()),200) return response except Exception as err: logger.error(err) response = make_response({ "message":"Internal Server Errro.Please try again after sometime" },500) return response @app.route('/crmData/&lt;id&gt;',methods=['PUT']) def putcrmData(id): try: app = zcatalyst_sdk.initialize(req=request) reqData = request.get_json() data = { "data":[reqData] } if reqData is None: response = make_response({ "message":"Update Data not found" },400) userDetails = getUserId(app) accesstoken = getAccessToken(userDetails,app) getAccess_Token = json.loads(accesstoken) access_token = getAccess_Token['access_token'] headers = { 'Authorization':f'Zoho-oauthtoken {accesstoken}', "Content-Type": "application/json" } path = f"/{id}" response1 = requests.put(apiUrl+path,headers=headers,json=data) response = make_response((response1.json()),200) return response except Exception as err: logger.error(err) response = make_response({ "message":"Internal Server Error.Please try again after sometime" },500) return response @app.route('/crmData/&lt;id&gt;',methods=['DELETE']) def deletelead(id): try: app = zcatalyst_sdk.initialize(req=request) userDetails = getUserId(app) accesstoken = getAccessToken(userDetails,app) getAccess_Token = json.loads(accesstoken) access_token = getAccess_Token['access_token'] headers = { 'Authorization':f'Zoho-oauthtoken {accesstoken}', "Content-Type": "application/json" } path = f"/{id}" response1 = requests.delete(apiUrl+path,headers=headers) response = make_response((response1.json()),200) return response except Exception as err: logger.error(err) response = make_response({ "message":"Internal Server Errro.Please try again after sometime" },500) return response def getRefreshToken(code,domain): params = { 'code':code, 'client_id':CLIENT_ID, 'client_secret':CLIENT_SECRET, 'grant_type':'authorization_code', 'redirect_uri':f"{domain}/generateToken" } response = requests.post(url,params = params) data = response.json() logger.info(f'response:{data}') return data['refresh_token'] def getAccessToken(userdetails,app): app=zcatalyst_sdk.initialize(req=request) userId = userdetails[0]['Token']['userId'] Zcql = app.zcql() query = f"Select refresh_token FROM Token where userId={userId}" response = Zcql.execute_query(query) refresh_token = response[0]['Token']['refresh_token'] args = {} args["client_id"] = CLIENT_ID args["client_secret"] = CLIENT_SECRET args["auth_url"] = url args["refresh_url"] = url args["refresh_token"] = refresh_token connector_service = app.connection({userId:args}) access_token = connector_service.get_connector(userId).get_access_token() return access_token def getUserId(app): try: app=zcatalyst_sdk.initialize(req=request) user = app.authentication().get_current_user() user_id = user["user_id"] response = app.zcql().execute_query(f"Select * from Token where userId = {user_id}") return response except Exception as err: response = make_response({ "message":"Internal Server error", "error":err },500) return response if __name__ == '__main__': port = int(os.environ.get('X_ZOHO_CATALYST_LISTEN_PORT', 9000)) app.run(host='0.0.0.0', port=port) {{%/panel_with_adjustment%}} {{%note%}}{{%bold%}}Note:{{%/bold%}}<br /> * Ensure you add the {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values obtained after you registered the client in the Zoho API console to the lines {{%bold%}}20{{%/bold%}} and {{%bold%}}21{{%/bold%}} respectively, in the above code file. * Add the {{%badge%}}Table ID{{%/badge%}} of the table you created in the {{%italics%}}Data Store{{%/italics%}} in line {{%bold%}}50{{%/bold%}}.{{%/note%}} {{%panel_with_adjustment class="language-xml line-numbers" header="index.html" footer="button" scroll="set-scroll" %}}&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="utf-8" /&gt; &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt; &lt;title&gt;CRM Lead Manager&lt;/title&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt; &lt;link rel="stylesheet" type="text/css" media="screen" href="main.css" /&gt; &lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"&gt; &lt;link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"&gt; &lt;link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/css/mdb.min.css" rel="stylesheet"&gt; &lt;script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="main.js"&gt; &lt;/script&gt; &lt;script src="https://static.zohocdn.com/catalyst/sdk/js/4.4.0/catalystWebSDK.js"&gt; &lt;/script&gt; &lt;script src="/__catalyst/sdk/init.js"&gt; &lt;/script&gt; &lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"&gt; &lt;style&gt; #connect { height: 260px; width: 500px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } &lt;/style&gt; &lt;/head&gt; &lt;body onload="getUserDetails()"&gt; &lt;br&gt; &lt;center&gt; &lt;h1&gt;CRM Lead Manager&lt;/h1&gt; &lt;br&gt; &lt;/center&gt; &lt;div id="connect"&gt; &lt;center&gt; &lt;p&gt;Click here to connect to Zoho CRM&lt;/p&gt; &lt;button onclick='navigate()'&gt; &lt;img src="https://www.zohowebstatic.com/sites/default/files/styles/product-home-page/public/icon-crm_blue.png" style="width: 180px;height: 130px;"&gt; &lt;/button&gt; &lt;/center&gt; &lt;/div&gt; &lt;div style="width: 200px;float: right; margin-right: 30px;"&gt; &lt;label for="logoutbtn" class="btn btn-success btn-block btn-outlined"&gt;Logout&lt;/label&gt; &lt;button id="logoutbtn" onclick="logout()" style="display: none;"&gt; &lt;/button&gt; &lt;/div&gt; &lt;div id="main"&gt; &lt;div class="container"&gt; &lt;ul class="nav nav-tabs nav-justified mb-3" id="myTab" role="tablist"&gt; &lt;li class="nav-item"&gt; &lt;a class="nav-link active" id="check-tab" data-toggle="tab" href="#check" role="tab" aria-controls="check" aria-selected="true"&gt;Add a Lead&lt;/a&gt; &lt;/li&gt; &lt;li class="nav-item"&gt; &lt;a class="nav-link" id="report-tab" data-toggle="tab" href="#report" onclick="getLeads()" role="tab" aria-controls="report" aria-selected="false"&gt;Manage Leads&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;br&gt; &lt;div class="tab-content" id="myTabContent"&gt; &lt;div class="tab-pane fade show active" id="check" role="tabpanel" aria-labelledby="check-tab"&gt; &lt;div class="tab-pane fade show active" id="ex3-tabs-1" role="tabpanel" aria-labelledby="ex3-tab-1"&gt; &lt;div style="margin-left: 100px; margin-right:100px;"&gt; &lt;form id="leads"&gt; &lt;!-- 2 column grid layout with text inputs for the first and last names --&gt; &lt;div class="row mb-4"&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example1"&gt;First name&lt;/label&gt; &lt;input type="text" id="firstName" class="form-control" /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example2"&gt;Last name&lt;/label&gt; &lt;input type="text" id="lastName" class="form-control" required /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example3"&gt;Company name&lt;/label&gt; &lt;input type="text" id="companyName" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Email input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example5"&gt;Email&lt;/label&gt; &lt;input type="email" id="email" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example4"&gt;State&lt;/label&gt; &lt;input type="text" id="state" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Number input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example6"&gt;Phone&lt;/label&gt; &lt;input type="number" id="phone" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Number input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example6"&gt;Lead Source&lt;/label&gt; &lt;input type="text" id="leadSource" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Submit button --&gt; &lt;center&gt; &lt;button type="submit" onclick="createLead();return false;" class="btn btn-primary btn-block mb-4" style="width: 100px;"&gt;Add Lead&lt;/button&gt; &lt;div id="loader" style="display: none;"&gt; &lt;div class="spinner-border" role="status"&gt; &lt;span class="sr-only"&gt;Loading...&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/center&gt; &lt;/form&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="tab-pane fade" id="report" role="tabpanel" aria-labelledby="report-tab"&gt; &lt;center&gt; &lt;div id="loaders" style="display: none; padding-top: 200px;"&gt; &lt;div class="spinner-border" role="status"&gt; &lt;span class="sr-only"&gt;Loading...&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/center&gt; &lt;p id="showData"&gt; &lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- Modal --&gt; &lt;div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt; &lt;div class="vertical-alignment-helper"&gt; &lt;div class="modal-dialog vertical-align-center"&gt; &lt;div class="modal-content"&gt; &lt;center&gt; &lt;h4 class="modal-title" id="myModalLabel"&gt; &lt;/h4&gt; &lt;div class="modal-body" id="message"&gt; &lt;/div&gt; &lt;div class="modal-footer"&gt; &lt;button type="button" style="background-color: #007bff;color: white;" class="btn btn-default" data-dismiss="modal"&gt;Close&lt;/button&gt; &lt;/div&gt; &lt;/center&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="modal fade" id="editForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt; &lt;div class="vertical-alignment-helper"&gt; &lt;div class="modal-dialog vertical-align-center"&gt; &lt;div class="modal-content"&gt; &lt;div style="margin-left: 80px; margin-right:80px;"&gt; &lt;br&gt; &lt;center&gt; &lt;h2&gt;Edit Lead&lt;/h2&gt; &lt;/center&gt; &lt;br&gt; &lt;form id="editLeads"&gt; &lt;!-- 2 column grid layout with text inputs for the first and last names --&gt; &lt;div class="row mb-4"&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example1"&gt;First name&lt;/label&gt; &lt;input type="text" id="editfirstName" class="form-control" /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example2"&gt;Last name&lt;/label&gt; &lt;input type="text" id="editlastName" class="form-control" required /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example3"&gt;Company name&lt;/label&gt; &lt;input type="text" id="editcompanyName" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Email input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example5"&gt;Email&lt;/label&gt; &lt;input type="email" id="editemail" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example4"&gt;State&lt;/label&gt; &lt;input type="text" id="editstate" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Number input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example6"&gt;Phone&lt;/label&gt; &lt;input type="number" id="editphone" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Submit button --&gt; &lt;center&gt; &lt;button type="submit" id="editBtn" onclick="editLead();return false;" class="btn btn-primary btn-block mb-4" style="width: 100px;"&gt;Edit&lt;/button&gt; &lt;div id="loader" style="display: none;"&gt; &lt;div class="spinner-border" role="status"&gt; &lt;span class="sr-only"&gt;Loading...&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/center&gt; &lt;/form&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="modal fade right" id="ModalDanger" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt; &lt;div class="modal-dialog modal-notify modal-danger modal-side modal-top-right" role="document"&gt; &lt;!--Content--&gt; &lt;div class="modal-content"&gt; &lt;!--Header--&gt; &lt;div class="modal-header"&gt; &lt;p class="heading"&gt;Lead Deletion&lt;/p&gt; &lt;button type="button" class="close" data-dismiss="modal" aria-label="Close"&gt; &lt;span aria-hidden="true" class="white-text"&gt;×&lt;/span&gt; &lt;/button&gt; &lt;/div&gt; &lt;!--Body--&gt; &lt;div class="modal-body"&gt; &lt;div class="row"&gt; &lt;div class="col-9"&gt; &lt;p&gt;Are you sure you want to delete the Lead?&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!--Footer--&gt; &lt;div class="modal-footer justify-content-center"&gt; &lt;a type="button" class="btn btn-danger" id="delete-btn" onclick="deleteLead()"&gt;Delete&lt;/a&gt; &lt;a type="button" class="btn btn-outline-danger waves-effect" data-dismiss="modal"&gt;Cancel&lt;/a&gt; &lt;/div&gt; &lt;/div&gt; &lt;!--/.Content--&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/body&gt; &lt;script&gt; //Add Your Client ID function navigate() { window.location.href = "https://accounts.zoho.com/oauth/v2/auth?scope=ZohoCRM.modules.ALL&client_id={{client_id}}&response_type=code&access_type=offline&redirect_uri=" + location.protocol + '//' + location.host + "/generateToken"; } &lt;/script&gt; &lt;/html&gt; {{%/panel_with_adjustment%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure you enter the {{%badge%}}Client ID{{%/badge%}} in line {{%bold%}}252{{%/bold%}}{{%/note%}} {{%panel_with_adjustment class="language-xml line-numbers" header="login.html" footer="button" scroll="set-scroll" %}}&lt;html&gt; &lt;/html&gt; &lt;meta charset="utf-8" /&gt; &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt; &lt;title&gt;CRM Lead Manager&lt;/title&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt; &lt;link rel="stylesheet" type="text/css" media="screen" href="main.css" /&gt; &lt;script src="main.js"&gt; &lt;/script&gt; &lt;link rel="stylesheet" type="text/css" media="screen" href="main.css" /&gt; &lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"&gt; &lt;script src="https://js.zohostatic.com/catalystclient/1.0.0/catalystWebSDK.js"&gt; &lt;/script&gt; &lt;script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://static.zohocdn.com/catalyst/sdk/js/4.4.0/catalystWebSDK.js"&gt; &lt;/script&gt; &lt;script src="/__catalyst/sdk/init.js"&gt; &lt;/script&gt; &lt;script&gt; catalyst.auth.signIn("login"); &lt;/script&gt; &lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"&gt; &lt;style&gt; #login { height: 100%; width: 100%; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } &lt;/style&gt; &lt;body&gt; &lt;br&gt; &lt;center&gt; &lt;h1&gt;CRM Lead Manager&lt;/h1&gt; &lt;/center&gt; &lt;div id="login"&gt; &lt;/div&gt; &lt;/body&gt; &lt;/html&gt; {{%/panel_with_adjustment%}} {{%panel_with_adjustment class="language-css line-numbers" header="main.css" footer="button" scroll="set-scroll" %}}#dataTable { font-family: Arial, Helvetica, sans-serif; border-collapse: collapse; width: 100%; } #dataTable td, #dataTable th { border: 1px solid #ddd; padding: 8px; } #dataTable tr:nth-child(even){background-color: #f2f2f2;} #dataTable tr:hover {background-color: #ddd;} #dataTable th { padding-top: 12px; padding-bottom: 12px; text-align: left; background-color: #007bff; color: white; } .vertical-alignment-helper { display: table; height: 100%; width: 100%; pointer-events: none; } .vertical-align-center { display: table-cell; vertical-align: middle; pointer-events: none; } .modal-content { width: inherit; max-width: inherit; height: inherit; margin: 0 auto; pointer-events: all; } {{%/panel_with_adjustment%}} {{%panel_with_adjustment class="language-javascript line-numbers" header="main.js" footer="button" scroll="set-scroll" %}}function createLead() { debugger; $("#loader").show(); var firstName = $("#firstName").val(); var lastName = $("#lastName").val(); if (lastName == "") { alert("Kindly Enter the Last Name"); $("#loader").hide(); return; } var companyName = $("#companyName").val(); var email = $("#email").val(); var state = $("#state").val(); var phone = $("#phone").val(); var leadSource = $("#leadSource").val(); $.ajax({ url: "/crmData", type: "post", contentType: "application/json", data: JSON.stringify({ "First_Name": firstName, "Last_Name": lastName, "Company": companyName, "Email": email, "State": state, "Phone": phone, "Lead_Source": leadSource, }), success: function (data) { debugger; $('#leads').trigger("reset"); $("#myModalLabel").html("Success"); $("#message").html("Lead Created Successfully"); $("#loader").hide(); $('#myModal').modal('show'); }, error: function (error) { $('#leads').trigger("reset"); $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function logout() { var redirectURL = "/login.html"; //Add your app domain var auth = catalyst.auth; auth.signOut(redirectURL); } function getUserDetails() { $("#main").hide(); $("#connect").hide(); catalyst.auth.isUserAuthenticated().then(result =&gt; { console.log(result) $("#loader").show(); $.ajax({ url: "/getUserDetails", type: "get", success: function (data) { $("#loader").hide(); if (data.userId) { $("#main").show(); $("#connect").hide(); } else { $("#connect").show(); $("#main").hide(); } }, error: function (error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); }).catch(err =&gt; { document.body.innerHTML = 'You are not logged in. Please log in to continue. Redirecting you to the login page..'; setTimeout(function () { window.location.href = "login.html"; }, 3000); }); } function getLeads() { debugger; var tableContainer = document.getElementById("showData"); tableContainer.innerHTML = ""; $("#loaders").show(); $.ajax({ url: "/crmData", type: "get", success: function (data) { debugger; var reqData = getRequiredData(data.data); $("#loaders").hide(); renderTable(reqData); }, error: function (error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function showDeletePopup(leadID) { $('#ModalDanger').modal('show'); var deleteBtn = document.getElementById("delete-btn"); deleteBtn.value = leadID; } function deleteLead() { var leadID = document.getElementById('delete-btn').value; $.ajax({ url: "/crmData/" + leadID, type: "delete", success: function (data) { debugger; $('#ModalDanger').modal('toggle'); $("#myModalLabel").html("Success"); $("#message").html("Lead Deleted Successfully"); $('#myModal').modal('show'); setTimeout(function () { location.reload(); }, 3000); }, error: function (error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function showEditPopup(leadID) { $.ajax({ url: "/crmData/" + leadID, type: "get", success: function (data) { debugger; var respData = data.data; $('#editfirstName').val(respData[0].First_Name); $('#editlastName').val(respData[0].Last_Name); $('#editcompanyName').val(respData[0].Company); $('#editemail').val(respData[0].Email); $('#editstate').val(respData[0].State); $('#editphone').val(respData[0].Phone); $('#editleadSource').val(respData[0].Lead_Source); $('#editBtn').val(respData[0].id); $('#editfirstName').html(respData[0].First_Name); $('#editlastName').html(respData[0].Last_Name); $('#editcompanyName').html(respData[0].Company); $('#editemail').html(respData[0].Email); $('#editstate').html(respData[0].State); $('#editphone').html(respData[0].Phone); $('#editleadSource').html(respData[0].Lead_Source); $('#editForm').modal('show'); }, error: function (error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function editLead() { var firstName = $("#editfirstName").val(); var lastName = $("#editlastName").val(); if (lastName == "") { alert("Kindly Enter the Last Name"); return; } var companyName = $("#editcompanyName").val(); var email = $("#editemail").val(); var state = $("#editstate").val(); var phone = $("#editphone").val(); var leadSource = $("#editleadSource").val(); var leadID = $("#editBtn").val(); $.ajax({ url: "/crmData/" + leadID, type: "put", contentType: "application/json", data: JSON.stringify({ "First_Name": firstName, "Last_Name": lastName, "Company": companyName, "Email": email, "State": state, "Phone": phone, "Lead_Source": leadSource }), success: function (data) { debugger; $('#editForm').modal('toggle'); $("#myModalLabel").html("Success"); $("#message").html("Lead Edited Successfully"); $('#myModal').modal('show'); setTimeout(function () { location.reload(); }, 3000); }, error: function (error) { $('#leads').trigger("reset"); $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function getRequiredData(data) { var i; var resp = []; for (i = 0; i &lt; data.length; i++) { var gulp = { "First Name": data[i].First_Name, "Last Name": data[i].Last_Name, "Phone": data[i].Phone, "Email": data[i].Email, "Company": data[i].Company, "Edit": '&lt;center&gt;&lt;a href=&quot;javascript:showEditPopup(\'' + data[i].id + '\')&quot;&gt;&#9998;︎&lt;/a&gt;&lt;/center&gt;', "Delete": '&lt;center&gt;&lt;a href=&quot;javascript:showDeletePopup(\'' + data[i].id + '\')&quot;&gt;&#128465;︎&lt;/a&gt;&lt;/center&gt;' } resp.push(gulp); } console.log(resp); return resp; } function renderTable(respData) { var col = []; for (var i = 0; i &lt; respData.length; i++) { for (var key in respData[i]) { if (col.indexOf(key) === -1) { col.push(key); } } } var table = document.createElement("table"); table.id = "dataTable"; var tr = table.insertRow(-1); for (var i = 0; i &lt; col.length; i++) { var th = document.createElement("th"); th.innerHTML = col[i]; tr.appendChild(th); } for (var i = 0; i &lt; respData.length; i++) { tr = table.insertRow(-1); for (var j = 0; j &lt; col.length; j++) { var tabCell = tr.insertCell(-1); tabCell.innerHTML = respData[i][col[j]]; } } var divContainer = document.getElementById("showData"); divContainer.innerHTML = ""; divContainer.appendChild(table); } {{%/panel_with_adjustment%}} {{%panel_with_adjustment class="language-json line-numbers" header="app-config.json" footer="button" scroll="set-scroll" %}}{ "command": "python3 -u main.py", "build_path": "/", "stack": "python_3_9", "env_variables": {}, "memory": 256, "scripts": {}, "raw": {}, "catalyst_auth": true, "login_redirect": "/index.html" } {{%/panel_with_adjustment%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure you provide the right value for the {{%badge%}}{{%bold%}}buildpath{{%/bold%}}{{%/badge%}} key.{{%/note%}} Now let's go over the logic and functionality of the application code. * The {{%badge%}}login.html{{%/badge%}} file in the client component enables Catalyst Embedded Authentication login, allowing you to log in using the Zoho social login. * The {{%badge%}}index.html{{%/badge%}} file contains the code for the front-end of the client. It defines a function {{%badge%}}navigate(){{%/badge%}} that enables the connection to the CRM account by passing the required authorization information such as the {{%badge%}}Client ID{{%/badge%}} and the scope. * The backend logic of the application defines the following APIs that perform various actions: - {{%badge%}}**/generateToken**{{%/badge%}}: Obtains the *Refresh Token* by calling the {{%badge%}}getRefreshToken(){{%/badge%}} function, and inserts it along with the {{%badge%}}userID{{%/badge%}} of the current user in the {{%badge%}}Token{{%/badge%}} table in the *Data Store*. It then redirects to the index page of the client. - {{%badge%}}**/getUserDetails**{{%/badge%}}: Fetches the user details by calling the {{%badge%}}getUserDetails(){{%/badge%}} function. If there is no record in the table, a JSON response with the {{%badge%}}userID{{%/badge%}} alone is sent. If the record exists in the table, it is sent along with the {{%badge%}}userID{{%/badge%}}. - {{%badge%}}**/crmData**{{%/badge%}}: This route defines the path of all leads in the Leads module. The Node function executes the HTTP {{%badge%}}GET{{%/badge%}} and {{%badge%}}POST{{%/badge%}} operations to fetch all leads or create a new lead using this route, respectively. - {{%badge%}}**/crmData/:id**{{%/badge%}}: This route defines the path of a particular lead in the Leads module. The {{%badge%}}id{{%/badge%}} represents the unique ID of the lead in CRM. The function executes the HTTP {{%badge%}}PUT{{%/badge%}} and {{%badge%}}DELETE{{%/badge%}} operations to edit or delete a lead, respectively, using this route. * The backend logic is implemented using the following functions that are called by the APIs: - {{%badge%}}**getRefreshToken()**{{%/badge%}}: Fetches the *Refresh Token* by passing the {{%badge%}}Client ID{{%/badge%}}, {{%badge%}}Client Secret{{%/badge%}}, *Redirect URI* and other required values as query string parameters. - {{%badge%}}**getAccessToken()**{{%/badge%}}: Fetches the *Access Token* by passing the *Refresh Token* queried from the Token table using {{%link href="/en/cloud-scale/help/zcql/introduction/" %}}ZCQL{{%/link%}}, and other required parameters. The Access Token is fetched each time an operation needs to be performed on the CRM module, such as adding a lead or editing a lead. - {{%badge%}}**getResponse()**{{%/badge%}}: Passes the *Access Token* fetched to obtain the authorization needed to perform each action on the CRM module. This function is called with each {{%badge%}}/crmData{{%/badge%}} and {{%badge%}}/crmData/:id{{%/badge%}} API to authorize the request. - {{%badge%}}**getUserDetails()**{{%/badge%}}: Fetches the record from the *Token* table that contains the *Refresh Token*, by passing the {{%badge%}}userID{{%/badge%}}. * {{%badge%}}**main.js**{{%/badge%}}: It is the JavaScript function in the client component that parses the JSON responses obtained from the function and renders them in the {{%badge%}}index.html{{%/badge%}} page. This function defines the actions for all the UI elements in the client application. For example, {{%badge%}}getLeads(){{%/badge%}} obtains all leads from the function response and renders them in the client, and {{%badge%}}showEditPopup(){{%/badge%}} defines the actions for editing a lead. -------------------------------------------------------------------------------- title: "Test the Application" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.699Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/test-app/" service: "All Services" related: - CLI Help Documentation (/en/cli/v1/cli-command-reference/) - Serve Resources (/en/cli/v1/serve-resources/introduction/) -------------------------------------------------------------------------------- # Test the Application Before you deploy the application to the remote console, you can {{%link href="/en/cli/v1/serve-resources/introduction" %}}test the application on a local server{{%/link%}} and check if everything works fine using the Catalyst CLI. To serve the Catalyst project locally, execute the following command from your project directory: {{%cli%}}catalyst serve{{%/cli%}} The Lead Manager application will now be served at default {{%badge%}}port 3000{{%/badge%}}. The local endpoint URLs of the components are displayed. {{%info%}}{{%bold%}}Info:{{%/bold%}} Every time you access the home page or any of the sub-pages of your client or the function, the CLI will display a live log of the URL accessed, along with the HTTP request method.{{%/info%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure you have provided the required {{%bold%}}Authorized Redirect URIs{{%/bold%}} when you {{%link href="/en/tutorials/leadmanager-appsail/express/register-client/" %}}registered the client in Step {{%bold%}}4{{%/bold%}}{{%/link%}}.{{%/note%}} <br /> You can now open the application in a browser using the local URL of the client displayed in the CLI. You will initially be redirected to the login page. If you configure a sign-up action on your own, you can sign up first, then log in to the application. Alternatively, you can also log in using the *Zoho Social Login*. <br /> You will be redirected to the permissions page. Accept the permissions requested by the app to access your Zoho account details. You will then be redirected back to the application. Click the **Zoho CRM** icon in this page to connect to Zoho CRM. <br /> You must now **choose the CRM account** that you wish to connect with the Lead Manager app, then click **Submit**. <!-- <br /> --> All your existing developer, sandbox, and production accounts will be listed. Click **Accept** to allow the *Lead Manager* app to access your Zoho CRM modules. <br /> You will be redirected back to the application. You can now create and manage leads in your configured Zoho CRM account directly from this application. To add a lead, enter the details of the lead in the *Add a Lead* section and click **Add Lead**. <br /> A confirmation pop-up will display the status every time you add, edit, or delete a lead. <br /> You can click the **Manage Leads** tab to view all your leads from the *Leads* module. You can **edit** or **delete** any of them by clicking their respective icons in the table. <br /> You can update a lead’s information, then click **Edit**. <br /> If you click the **delete** icon, you must confirm the action in the confirmation pop-up. <br /> You can also check the *Refresh Token* and {{%badge%}}userID{{%/badge%}} values populated in the **Data Store** from your Catalyst console. Navigate to the **Data View** section of the *Token* table to view the record that was added. <br /> If you delete this entry, you will have to authenticate your credentials in the client application and establish a connection to your CRM account again. You can log out of the application by clicking **Logout**. You can quit the {{%badge%}}serve{{%/badge%}} session in your terminal by executing the command to kill a running process, based on your OS. If this setup is working correctly, we can deploy the application to production. -------------------------------------------------------------------------------- title: "Deploy the Application" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.700Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/flask/deploy-app/" service: "All Services" related: - CLI Help Documentation (/en/cli/v1/cli-command-reference/) - Deploy Resources (/en/cli/v1/deploy-resources/introduction/) - AppSail Help Documentation (/en/serverless/help/appsail/introduction/) -------------------------------------------------------------------------------- # Deploy the Application You can now deploy the application to the remote console. {{%note%}}{{%bold%}}Note:{{%/bold%}} Since you had already logged into the {{%bold%}}Lead Manager{{%/bold%}} application from the local server, a {{%italics%}}Refresh Token{{%/italics%}} would have already been generated. This token will continue to authenticate your access.{{%/note%}} To {{%link href="/en/cli/v1/deploy-resources/introduction" %}}deploy your Catalyst project from the CLI{{%/link%}}, run the following command in your terminal from your project directory: {{%cli%}}catalyst deploy{{%/cli%}} The function is deployed first, followed by the client component. The app URLs of the components will be displayed. <br /> The application is now deployed to the Catalyst console. Now, if you once again navigate to the AppSail component located under the *Serverless* section, you will be able to acquire the application's invocation URL. <br /> In this section you will also have access to a live dashboard denoting the number of instances the Lead Manager app service has spawned at any given moment. Using this section you will also be able configure and manage the AppSail service. You can find out more about this {{%link href="/en/serverless/help/appsail/console/introduction/" %}}here{{%/link%}}. You can use the invocation URL in a browser to access the deployed application. Lead Manager application can now be accessed from its {{%link href="/en/cloud-scale/help/web-client-hosting/introduction" %}}web app URL{{%/link%}}. <br />