To integrate Freshsales with Lovable, generate an API key from your Freshsales profile settings, store it with your subdomain in Cloud → Secrets, then build Edge Functions that proxy calls to the Freshsales API for contacts, deals, accounts, and activities. Freshsales adds Freddy AI lead scoring on top of its pipeline management, making it ideal for founders who want AI-powered sales prioritization built into their Lovable app dashboards.
Build AI-powered sales dashboards in Lovable with Freshsales and Freddy AI scoring
Freshsales is the sales CRM product from Freshworks, designed for teams that also use Freshdesk (support), Freshservice (IT), or other Freshworks products. Its defining feature is Freddy AI — an AI engine that scores leads and deals based on historical win/loss patterns, engagement data, and demographic signals. For founders building custom sales tools on top of their CRM, surfacing Freddy AI scores in a Lovable dashboard gives sales teams a prioritized view of their pipeline without requiring each rep to log into Freshsales manually.
Freshsales API authentication is simple: each user has a personal API key (similar to Pipedrive's approach), plus your account's subdomain serves as the API base URL. There is no OAuth2 required — the API key is included in an Authorization header as a token, making integration straightforward.
The Freshsales API covers the full CRM data model: contacts (individual people), accounts (companies), deals (opportunities), activities (calls, meetings, tasks), appointments, and notes. The API also exposes Freddy AI data: lead scores, deal health indicators, and propensity-to-buy ratings are available as fields on contact and deal objects.
For teams using the Freshworks suite, Freshsales integrates natively with Freshdesk (support tickets appear in the CRM contact timeline), Freshmarketer (email campaign engagement syncs to contact records), and Freshservice (IT tickets associated with accounts). Building your Lovable app as the unified interface for this data creates significant operational efficiency for Freshworks-heavy organizations.
Integration method
Freshsales has no native Lovable connector. All CRM operations are proxied through Lovable Edge Functions that call the Freshsales API using API key authentication. The API key and Freshsales subdomain are stored in Cloud → Secrets and accessed via Deno.env.get(), keeping credentials server-side and preventing CORS errors from direct browser calls to the Freshsales API.
Prerequisites
- A Lovable project with Lovable Cloud enabled (Edge Functions require a deployed app)
- A Freshsales account (free plan available for up to 3 users at freshworks.com/crm/sales/)
- Your Freshsales account subdomain (the 'yourcompany' in yourcompany.freshsales.io)
- Basic familiarity with Freshsales data model: contacts, accounts, deals, and activities
Step-by-step guide
Generate a Freshsales API key and find your account subdomain
Generate a Freshsales API key and find your account subdomain
Freshsales uses API key authentication, similar to Pipedrive. Each user has a personal API key that provides access to the API with that user's permissions. To get your API key: log in to Freshsales and click your profile avatar in the top-right corner. Select 'Profile Settings' from the dropdown. In the Profile Settings page, scroll to the 'API Settings' section. Your API key is displayed — click the eye icon to show it and copy it. Your Freshsales subdomain is the company name part of your Freshsales URL. When you log in, the URL looks like yourcompany.freshsales.io. The subdomain is 'yourcompany' (without .freshsales.io). This forms the base URL for all API calls: https://yourcompany.freshsales.io/api/. Freshsales API base URL format: https://{subdomain}.freshsales.io/api/ Example endpoint: https://yourcompany.freshsales.io/api/contacts Authentication header: Token token={YOUR_API_KEY} Note the 'Token token=' prefix — this is Freshsales-specific and different from 'Bearer' or 'Basic' auth formats. Forgetting the 'Token token=' prefix causes 401 errors even with a valid API key. For production integrations, consider using the API key of a dedicated admin user rather than your personal account, so the integration is not disrupted if your account permissions change.
Pro tip: The Freshsales API key is personal to your account. If you are building a multi-user integration or your team wants the integration to show activity attributed to a specific team member, use that team member's API key rather than an admin's key.
Expected result: A Freshsales API key is copied from Profile Settings. Your Freshsales subdomain is noted (the company name part of your Freshsales URL without the .freshsales.io suffix).
Store credentials in Cloud Secrets
Store credentials in Cloud Secrets
Add Freshsales credentials to Lovable's Cloud Secrets panel. In Lovable, click '+' → Cloud panel → Secrets tab. Add two secrets: - FRESHSALES_API_KEY — your personal API key from Freshsales Profile Settings - FRESHSALES_SUBDOMAIN — your Freshsales subdomain (just 'yourcompany', not the full URL) The Edge Function constructs the full API base URL as: https://${FRESHSALES_SUBDOMAIN}.freshsales.io/api/ Store the subdomain without protocol or domain suffix. Including 'https://' or '.freshsales.io' creates malformed URLs. Freshsales API authentication header format is: Token token=YOUR_API_KEY — note the capital T in 'Token' and the lowercase 'token=' prefix before the key value. This double-token format is specific to Freshsales and does not follow the standard Bearer token convention. The Freshsales API supports JSON responses for all endpoints. All list endpoints return data in a named array matching the resource type: contacts returns { contacts: [...] }, deals returns { deals: [...] }. Single resource endpoints return the object directly: { contact: {...} }. Pagination uses page and per_page query parameters with a default of 25 items per page.
Pro tip: Freshsales subdomain is case-sensitive in API calls. If your Freshsales URL is MyCompany.freshsales.io (with capital M), the subdomain in the API URL must also be 'MyCompany'. In practice, most Freshsales subdomains are all lowercase.
Expected result: FRESHSALES_API_KEY and FRESHSALES_SUBDOMAIN appear in Cloud → Secrets with masked values.
Create the Freshsales API proxy Edge Function
Create the Freshsales API proxy Edge Function
Build the Edge Function that handles common Freshsales operations. The Freshsales API uses standard REST conventions with JSON request/response bodies and query parameters for filtering and pagination. Key Freshsales API endpoints: - Contacts: GET /api/contacts (list), GET /api/contacts/{id} (get), POST /api/contacts (create), PUT /api/contacts/{id} (update) - Deals: GET /api/deals (list), POST /api/deals (create), PUT /api/deals/{id} (update) - Accounts: GET /api/accounts (list/search), POST /api/accounts (create) - Activities: GET /api/activities (list), POST /api/activities (create) Freshsales supports field filtering with the 'include' parameter to reduce response payload size: GET /api/contacts?include=freddy_score,last_activity_date returns only those fields plus the default ID and name fields. For searching contacts by email (the most common lookup): GET /api/contacts/filter uses POST with a filter body: { filter_rule: [{ attribute: 'email', operator: 'is_in', value: 'user@example.com' }] }. This endpoint requires a POST with the filter body even though it is a search/read operation. Freddy AI scores for contacts are available as the 'freddy_score' field (0-100). Deal health scores are 'freddy_forecast_score'. These fields are not returned by default — include them explicitly in the 'include' parameter.
Create an Edge Function called freshsales-crm at supabase/functions/freshsales-crm/index.ts. Accept POST with { action, params }. Support actions: create_contact, list_contacts, search_contact_by_email, create_deal, list_deals, log_activity. Use FRESHSALES_API_KEY and FRESHSALES_SUBDOMAIN from secrets. Use 'Token token={key}' for Authorization. Return the Freshsales API response. Include CORS headers.
Paste this in Lovable chat
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'23const corsHeaders = {4 'Access-Control-Allow-Origin': '*',5 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',6}78function fsHeaders() {9 const key = Deno.env.get('FRESHSALES_API_KEY')10 if (!key) throw new Error('FRESHSALES_API_KEY not configured')11 return {12 Authorization: `Token token=${key}`,13 'Content-Type': 'application/json',14 }15}1617function fsUrl(path: string) {18 const sub = Deno.env.get('FRESHSALES_SUBDOMAIN')!19 return `https://${sub}.freshsales.io/api${path}`20}2122serve(async (req) => {23 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders })2425 try {26 const { action, params = {} } = await req.json()27 const headers = fsHeaders()28 let resp: Response2930 switch (action) {31 case 'create_contact':32 resp = await fetch(fsUrl('/contacts'), {33 method: 'POST',34 headers,35 body: JSON.stringify({36 contact: {37 first_name: params.firstName,38 last_name: params.lastName,39 email: params.email,40 mobile_number: params.phone || '',41 company: { name: params.company || '' },42 lead_source_id: params.leadSourceId,43 tags: params.tags || [],44 },45 }),46 })47 break4849 case 'list_contacts':50 resp = await fetch(fsUrl(`/contacts?page=${params.page || 1}&per_page=${params.perPage || 25}&include=freddy_score,last_activity_date,deal_stage`), { headers })51 break5253 case 'search_contact_by_email':54 resp = await fetch(fsUrl('/filtered_search/contact'), {55 method: 'POST',56 headers,57 body: JSON.stringify({58 filter_rule: [{ attribute: 'email', operator: 'is_in', value: params.email }],59 }),60 })61 break6263 case 'create_deal':64 resp = await fetch(fsUrl('/deals'), {65 method: 'POST',66 headers,67 body: JSON.stringify({68 deal: {69 name: params.name,70 amount: params.amount,71 contacts_added_list: params.contactId ? [params.contactId] : [],72 deal_stage_id: params.dealStageId,73 expected_close: params.expectedClose,74 },75 }),76 })77 break7879 case 'list_deals':80 resp = await fetch(fsUrl(`/deals?page=${params.page || 1}&per_page=${params.perPage || 25}&include=freddy_forecast_score,contacts,deal_stage`), { headers })81 break8283 case 'log_activity':84 resp = await fetch(fsUrl('/activities'), {85 method: 'POST',86 headers,87 body: JSON.stringify({88 activity: {89 title: params.title,90 type: { name: params.type || 'Task' },91 notes: params.notes || '',92 targetable_type: 'Contact',93 targetable_id: params.contactId,94 due_date: params.dueDate || new Date().toISOString().split('T')[0],95 },96 }),97 })98 break99100 default:101 return new Response(JSON.stringify({ error: 'Unknown action' }), {102 status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },103 })104 }105106 const data = await resp.json()107 return new Response(JSON.stringify(data), {108 status: resp.ok ? 200 : resp.status,109 headers: { ...corsHeaders, 'Content-Type': 'application/json' },110 })111 } catch (error) {112 return new Response(JSON.stringify({ error: error.message }), {113 status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },114 })115 }116})Pro tip: Freshsales contact creation requires the company name as a nested object: { company: { name: 'Acme Corp' } }, not a flat string field. Passing company as a string at the top level will either fail or create an unnamed company record.
Expected result: The freshsales-crm Edge Function deploys in Cloud → Edge Functions. Test with action 'list_contacts' — Freshsales contact records with Freddy AI scores should appear in the response.
Build the Freshsales dashboard with Freddy AI scoring in Lovable
Build the Freshsales dashboard with Freddy AI scoring in Lovable
With the Edge Function deployed, use Lovable's chat to build the sales dashboard that highlights Freddy AI lead scoring. The key differentiator from standard CRM dashboards is the visual prioritization driven by Freddy scores. For the lead prioritization view, invoke list_contacts with the include parameters for freddy_score and last_activity_date. Sort by freddy_score descending so the highest-scoring leads appear at the top. Apply color coding: scores 75-100 (green/hot), 50-74 (yellow/warm), 25-49 (orange/cool), 0-24 (gray/cold). Include the days since last activity to help reps identify engaged leads with recent interaction. For deal pipeline health, invoke list_deals with the freddy_forecast_score included. Deals with low forecast scores despite being in late pipeline stages indicate high churn risk — surface these as an 'At Risk' section in your dashboard. For the contact creation flow (adding leads from your app), call create_contact from form submit handlers. Map your app's plan tiers to Freshsales tags ('free', 'trial', 'pro') for segment-based sales outreach. Use the fire-and-forget pattern (no await) so contact creation latency does not affect the user's registration experience. For connecting Freshsales with your existing Freshdesk support integration to show support ticket history alongside CRM data in a unified customer 360 view, RapidDev's team can help design the cross-Freshworks API architecture.
Build a sales dashboard page using the freshsales-crm Edge Function. Fetch contacts with Freddy scores (action: list_contacts). Display as a ranked list sorted by freddy_score with score badges: green circle for 75+, yellow for 40-74, red for below 40. Show contact name, company, email, score, and days since last activity. Add a button to log an activity for any contact. Include a deals summary section showing total pipeline value and deal count.
Paste this in Lovable chat
Pro tip: Freddy AI scores require data to generate — new contacts in an empty Freshsales account will all show scores of 0. The scores become meaningful after Freddy has analyzed several weeks of historical deal win/loss data in your account. In the meantime, sort by last_activity_date as a fallback prioritization signal.
Expected result: The sales dashboard displays Freshsales contacts sorted by Freddy AI score with color-coded badges. Deal count and total pipeline value show in the summary section. Activity logging creates tasks in Freshsales visible in the contact's timeline.
Common use cases
Sales prioritization dashboard using Freddy AI lead scores
Build a dashboard that fetches contacts and deals from Freshsales with their Freddy AI scores and displays a prioritized list sorted by lead score. Sales reps see which contacts are most likely to convert at the top, with score badges and engagement signals. Clicking a contact shows their activity history and Freddy AI score breakdown. This replaces manual pipeline review with data-driven prioritization.
Create an Edge Function called freshsales-leads that fetches contacts from Freshsales with their freddy_score field using FRESHSALES_API_KEY and FRESHSALES_SUBDOMAIN from secrets. Sort by freddy_score descending. Return name, email, company, freddy_score, last_activity_date, and deal_stage. Build a Lovable dashboard showing a ranked lead list with color-coded score badges (green >75, yellow 40-75, red <40).
Copy this prompt to try it in Lovable
Auto-create Freshsales contacts from app registrations
When a new user registers for your Lovable app, automatically create a Freshsales contact with their information, set a lead source tag, and assign to the appropriate sales rep based on territory or plan tier. The contact appears immediately in the Freshsales pipeline for follow-up, with Freddy AI starting to build a score based on engagement data from the CRM.
Create an Edge Function called freshsales-create-contact that accepts { firstName, lastName, email, company, phone, plan, source } and creates a Freshsales contact using FRESHSALES_API_KEY and FRESHSALES_SUBDOMAIN from secrets. Set the lead source to source, add a tag based on plan tier (free/trial/paid), and return the contact ID. Call this from my registration success handler alongside Supabase Auth user creation.
Copy this prompt to try it in Lovable
Deal pipeline view with stage-by-stage conversion analytics
Fetch all active deals from Freshsales and display them in a pipeline view grouped by deal stage. For each stage, show total deal value and count. Include a conversion funnel showing the percentage of deals moving between stages. Sales managers use this to identify pipeline bottlenecks without needing to navigate Freshsales reports.
Create an Edge Function called freshsales-pipeline that fetches all open deals from Freshsales grouped by deal_stage using FRESHSALES_API_KEY and FRESHSALES_SUBDOMAIN from secrets. Return deal count, total value, and deal list per stage. Build a pipeline view in Lovable with stage columns showing deal cards (name, amount, contact name, expected close date) and a summary header per stage showing count and total value.
Copy this prompt to try it in Lovable
Troubleshooting
Freshsales API returns 401 Unauthorized on every request
Cause: The Authorization header format is incorrect. Freshsales uses 'Token token=KEY' format, not 'Bearer KEY' or 'Basic' encoding.
Solution: Verify the Authorization header in your Edge Function is exactly: 'Token token=YOUR_API_KEY' — capital T in Token, then a space, then lowercase 'token=' immediately followed by the key with no space. This non-standard format is specific to Freshsales (and other Freshworks APIs).
1// Correct Freshsales auth header format:2Authorization: `Token token=${apiKey}` // NOT 'Bearer' or 'Basic'Contact creation fails with 'Name is not valid' or missing field errors
Cause: Freshsales requires first_name and last_name as separate fields, not a combined 'name' field. Company must be passed as a nested object.
Solution: Split the user's full name into first_name and last_name before sending to the API. If you only have a full name, split on the first space: const [firstName, ...lastParts] = fullName.split(' '). Pass company as: { company: { name: companyName } }. The API returns a 422 with detailed field error messages — check the response body for which specific field is failing.
The freddy_score field returns null or zero for all contacts
Cause: Freddy AI requires historical deal data to generate scores. New Freshsales accounts or accounts with very few closed deals will have null or zero scores for all contacts.
Solution: This is expected behavior for new accounts. Freddy AI builds its scoring model from historical win/loss patterns over time. As more deals are closed or lost in Freshsales, scores become meaningful. For demonstration purposes, you can display 'Score Pending' for null scores rather than showing zero.
API returns 404 for all endpoints with 'Account not found' error
Cause: The FRESHSALES_SUBDOMAIN is incorrect or includes the full domain instead of just the subdomain.
Solution: Verify the subdomain value is only the company name portion of your Freshsales URL. For yourcompany.freshsales.io, the secret value should be 'yourcompany' with no protocol, no dots, and no '.freshsales.io' suffix. The Edge Function constructs the full URL from this subdomain.
Best practices
- Use the 'include' parameter in Freshsales API list calls to request only the fields you need — large contact lists with all fields included can be slow and expensive.
- Always split full names into first_name and last_name before creating Freshsales contacts — the API does not accept a combined name field.
- Surface Freddy AI scores visually with clear color-coded indicators — the scoring system is only valuable if it drives behavioral changes in how reps prioritize outreach.
- Implement fire-and-forget (no await) for Freshsales contact creation in user-facing registration flows — CRM sync should never delay the primary user experience.
- Store deal stage IDs as secrets (FRESHSALES_STAGE_QUALIFICATION_ID) rather than hardcoding — Freshsales stage IDs are account-specific and change if you restructure your pipeline.
- Combine Freddy score with days-since-last-activity for a more nuanced prioritization signal — a high-scoring lead that has been inactive for 30 days needs different outreach than one active yesterday.
- Create activities immediately after contact creation to give Freddy AI initial signals about engagement — even a 'New signup activity' helps the AI model start building a score.
Alternatives
Choose Pipedrive if you want a pure visual pipeline CRM without AI scoring and prefer simpler API key authentication with a larger third-party integration ecosystem.
Choose HubSpot if you need a free CRM tier with unlimited users alongside marketing automation — HubSpot's free plan is significantly more generous than Freshsales.
Choose Zoho CRM if you are already using other Zoho products — the deep ecosystem integration between Zoho CRM, Zoho Books, and Zoho Desk provides cross-product context that Freshsales only matches within the Freshworks suite.
Frequently asked questions
Does Freshsales have a free plan that supports API access?
Yes — Freshsales has a free plan supporting up to 3 users with basic CRM features and full API access. The free plan includes contacts, accounts, deals, and activities but does not include Freddy AI lead scoring (Growth plan at $29/user/month required) or advanced automation (Pro plan at $69/user/month). For building and testing a Lovable integration, the free plan is sufficient. Freddy AI scoring requires a paid plan to generate non-zero scores.
What is Freddy AI and how accurate are its lead scores?
Freddy AI is Freshworks' machine learning engine that analyzes your historical CRM data to predict lead and deal quality. Lead scores (0-100) are generated based on historical win/loss patterns, deal velocity, contact engagement, demographic signals, and behavioral data. Scores become more accurate over time as Freddy processes more historical data — expect meaningful scores after approximately 3-6 months of deal history. Freddy is included in the Growth plan and above.
Can I use the Freshsales API for both Freshsales Classic and Freshsales?
Freshworks has two CRM products: Freshsales (the current product, sometimes called Freshsales Suite) and Freshsales Classic (the legacy product). The API endpoints and authentication methods differ between them. This guide covers the current Freshsales API. If your account is on Freshsales Classic (older accounts with a different UI), check the Freshsales Classic API documentation for endpoint differences.
How do I use Freshsales alongside Freshdesk in the same Lovable app?
Both Freshdesk and Freshsales APIs use the same API key and subdomain-based authentication pattern. You can create Edge Functions for each product separately, using FRESHSALES_API_KEY and FRESHDESK_API_KEY as separate secrets. Both APIs follow the same 'Token token=KEY' authorization format. To build a customer 360 view, call both APIs for a given email address and merge the CRM contact data with the support ticket history in your Lovable UI.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation