# How to Integrate Lovable with LeadSquared

- Tool: Lovable
- Difficulty: Intermediate
- Time required: 25 minutes
- Last updated: March 2026

## TL;DR

Integrating LeadSquared with Lovable uses Edge Functions to capture leads, sync activities, and retrieve opportunity data via the LeadSquared REST API. Store your Access Key and Secret Key in Cloud Secrets, create Edge Functions to push leads from your Lovable frontend and pull CRM data for dashboards. Setup takes 25 minutes.

## Why integrate LeadSquared with Lovable?

LeadSquared is the dominant CRM platform for growth-stage companies in India, Southeast Asia, and the Middle East, with particular strength in edtech, real estate, financial services, and healthcare sectors. If you're building a Lovable app for an organization that already uses LeadSquared as their CRM, connecting your app to LeadSquared lets you capture leads directly into the sales team's workflow without any manual data export/import. Lead assignments, activity tracking, and pipeline management all happen automatically in the tool the sales team already uses.

For Lovable developers, the most common integration scenarios are: a marketing landing page that captures leads into LeadSquared (replacing manual CSV imports), a field sales app that syncs call activities and site visits to the CRM, an admissions portal for edtech that creates student leads with custom fields for course interest and test scores, and a dashboard that pulls LeadSquared pipeline data to display in an internal analytics tool.

LeadSquared's API is straightforward: all endpoints use HTTPS GET or POST with your Access Key and Secret Key passed as query parameters. There's no OAuth flow or token exchange — the same credentials work for every call. Edge Functions keep these credentials server-side. The API is organized around four main resources: Leads (create, search, update), Lead Activities (log calls, emails, meetings), Opportunities (deals in the pipeline), and SmartViews (saved filters you can query).

## Before you start

- A Lovable project with Cloud enabled
- A LeadSquared account — sign up at leadsquared.com or request a trial
- Your LeadSquared Access Key and Secret Key from Settings → API & Webhooks → Credentials
- Your LeadSquared API host URL (varies by data center — e.g., api.leadsquared.com for US, in21.leadsquared.com for India)
- Knowledge of which LeadSquared custom fields (mx_ prefix) you want to map to your app's data

## Step-by-step guide

### 1. Find your LeadSquared API credentials and data center URL

Log into your LeadSquared account and navigate to Settings (gear icon, top right) → API & Webhooks → Access Key. You'll see your Access Key and Secret Key displayed here. Copy both — these are your permanent API credentials that authenticate every API call. Unlike OAuth tokens, these don't expire unless you regenerate them.

Critically, LeadSquared has multiple data centers and your API host URL depends on which region your account is on. US accounts use api.leadsquared.com. India accounts typically use in21.leadsquared.com or in22.leadsquared.com (your settings page shows the correct URL). Look at the 'API Host' field in the API & Webhooks settings to find your correct host — using the wrong host returns a 401 even with correct credentials.

In your Lovable project, open the Cloud tab ('+' button next to Preview) and click 'Secrets'. Add three secrets: LEADSQUARED_ACCESS_KEY with your Access Key, LEADSQUARED_SECRET_KEY with your Secret Key, and LEADSQUARED_HOST with your data center host (e.g., api.leadsquared.com — without trailing slash). These are automatically injected into your Edge Functions.

**Expected result:** LEADSQUARED_ACCESS_KEY, LEADSQUARED_SECRET_KEY, and LEADSQUARED_HOST stored in Cloud Secrets.

### 2. Create an Edge Function to capture leads in LeadSquared

In Lovable's Code panel, navigate to supabase/functions/ and create a new folder leadsquared-create-lead with an index.ts file. This function receives lead data from your frontend form and creates a lead in LeadSquared using the Create Lead API.

LeadSquared's API uses a different authentication pattern than most REST APIs: credentials are passed as query parameters (accessKey and secretKey) rather than headers. The Create Lead endpoint is POST https://{host}/v2/LeadManagement.svc/Lead.Create?accessKey={key}&secretKey={secret}. The request body is a JSON array of lead attribute objects, each with an Attribute and Value key. Required attributes include EmailAddress or Phone (at least one). Standard attributes include FirstName, LastName, Phone, EmailAddress, Source, LeadStatus. Custom attributes use the mx_ prefix (e.g., mx_Product_Interest).

The API returns a JSON response with a Status field ('Success' or 'Error') and a Message. On success, it returns the LeadId of the created lead. Your Edge Function should build the attributes array from the request body, call the API, and return the LeadId so your frontend can store it alongside the form submission in Supabase.

```
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

const ACCESS_KEY = Deno.env.get("LEADSQUARED_ACCESS_KEY") ?? "";
const SECRET_KEY = Deno.env.get("LEADSQUARED_SECRET_KEY") ?? "";
const HOST = Deno.env.get("LEADSQUARED_HOST") ?? "api.leadsquared.com";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};

serve(async (req) => {
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }

  try {
    const body = await req.json();
    const { firstName, lastName, email, phone, source = "Website", ...customFields } = body;

    const attributes: Array<{ Attribute: string; Value: string }> = [
      { Attribute: "FirstName", Value: firstName ?? "" },
      { Attribute: "LastName", Value: lastName ?? "" },
      { Attribute: "EmailAddress", Value: email ?? "" },
      { Attribute: "Phone", Value: phone ?? "" },
      { Attribute: "Source", Value: source },
      { Attribute: "LeadStatus", Value: "New" },
    ];

    // Add custom fields with mx_ prefix
    for (const [key, value] of Object.entries(customFields)) {
      if (value !== undefined && value !== null) {
        attributes.push({ Attribute: `mx_${key}`, Value: String(value) });
      }
    }

    const url = `https://${HOST}/v2/LeadManagement.svc/Lead.Create?accessKey=${ACCESS_KEY}&secretKey=${SECRET_KEY}`;
    const res = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(attributes),
    });

    const data = await res.json();

    if (data.Status === "Success" || data.LeadId) {
      return new Response(
        JSON.stringify({ success: true, leadId: data.Message?.Id ?? data.LeadId }),
        { headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    } else {
      return new Response(
        JSON.stringify({ success: false, error: data.ExceptionMessage ?? data.Message ?? "Unknown error" }),
        { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }
  } catch (e) {
    return new Response(
      JSON.stringify({ error: (e as Error).message }),
      { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  }
});
```

**Expected result:** Edge Function deployed. Test by calling it with curl or from the Lovable preview — a new lead should appear in your LeadSquared inbox within seconds.

### 3. Build the lead capture form in Lovable

Now create the frontend form component that collects lead data and calls your Edge Function. Open Lovable's chat and prompt it to build a lead capture form. The form should collect the relevant fields for your use case (at minimum, name, email, and phone), validate them client-side, and call the leadsquared-create-lead Edge Function on submission.

After a successful API call, store the returned LeadId in Supabase so you can link app interactions back to the CRM record. For example, if a user submits a demo request and gets LeadId '12345678', store that in your Supabase users or leads table. Future activity logs, page views, or follow-up form submissions can reference this LeadId when posting activities to LeadSquared.

For the form UI, use shadcn/ui form components with react-hook-form for validation. Show a loading state while the Edge Function runs and a success toast when the lead is created. If LeadSquared returns a duplicate lead error (the email already exists), handle it gracefully — you may want to update the existing lead rather than showing an error to the user. LeadSquared provides a separate Lead.CreateOrUpdate endpoint that handles duplicates automatically.

**Expected result:** Lead capture form visible in the Lovable preview. Submitting the form creates a new lead in LeadSquared and stores the leadId in Supabase.

### 4. Add activity logging for lead interactions

Beyond lead creation, LeadSquared tracks Activities — everything a lead does or a salesperson does with a lead. Activities include email opens, page visits, calls, meetings, and custom activities you define. Logging activities enriches the lead's timeline in LeadSquared and can trigger automation rules (e.g., 'If a lead views the pricing page 3 times, assign to senior sales rep').

Create a second Edge Function leadsquared-log-activity that calls the PostLeadActivity endpoint. This endpoint requires the lead's EmailAddress or ProspectId to identify the lead, the Activity type (you can use built-in types or create custom ones in LeadSquared settings), a Score for the activity (points used for lead scoring), and optional Note. The endpoint is POST https://{host}/v2/ProspectActivity.svc/Create.

For common activity types, LeadSquared uses numeric ActivityEvent IDs. Common ones are: 3 = Lead created, 4 = Email sent, 206 = Webinar attended, 212 = Form submitted. You can also create custom activities under Settings → Custom Activity Types which give you a custom ActivityEvent ID. Your Lovable app can log activities when a user visits a key page, downloads a resource, or completes an in-app action — giving the sales team rich context about what the prospect did.

```
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

const ACCESS_KEY = Deno.env.get("LEADSQUARED_ACCESS_KEY") ?? "";
const SECRET_KEY = Deno.env.get("LEADSQUARED_SECRET_KEY") ?? "";
const HOST = Deno.env.get("LEADSQUARED_HOST") ?? "api.leadsquared.com";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};

serve(async (req) => {
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }

  try {
    const { email, activityEvent, note = "", score = 5 } = await req.json();

    const activity = {
      EmailAddress: email,
      ActivityEvent: activityEvent,
      ActivityNote: note,
      Score: score,
      ActivityDate: new Date().toISOString(),
      MXFields: [],
    };

    const url = `https://${HOST}/v2/ProspectActivity.svc/Create?accessKey=${ACCESS_KEY}&secretKey=${SECRET_KEY}`;
    const res = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(activity),
    });

    const data = await res.json();

    if (res.ok && data.Status !== "Error") {
      return new Response(
        JSON.stringify({ success: true }),
        { headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    } else {
      return new Response(
        JSON.stringify({ success: false, error: data.ExceptionMessage ?? "Activity log failed" }),
        { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }
  } catch (e) {
    return new Response(
      JSON.stringify({ error: (e as Error).message }),
      { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  }
});
```

**Expected result:** Activity logging Edge Function deployed. Test by logging an activity for a known lead email and verifying it appears in that lead's activity timeline in LeadSquared.

## Best practices

- Store LEADSQUARED_ACCESS_KEY and LEADSQUARED_SECRET_KEY in Cloud Secrets — never include them as query parameters in frontend JavaScript where they'd be visible in browser network tabs
- Use Lead.CreateOrUpdate instead of Lead.Create for public forms to prevent duplicate lead records when the same prospect submits multiple times
- Always set the Source attribute when creating leads — this tells the sales team where the lead came from (e.g., 'Website', 'Webinar', 'Referral') and enables source attribution reporting in LeadSquared
- Cache LeadSquared search results in Supabase with a TTL of 5-15 minutes for dashboard queries — LeadSquared API has rate limits and frequent queries for the same data waste your quota
- Log meaningful activities when leads interact with your Lovable app — page views of key pages (pricing, case studies), demo requests, and feature usage give sales reps context before their first call
- Map your app's user IDs to LeadSquared ProspectIds in Supabase so you can look up lead records without relying on email address (which can change)
- For complex LeadSquared configurations with custom pipelines, automation rules, or multiple user roles, RapidDev's team can help map your sales process requirements to the LeadSquared API correctly

## Use cases

### Lead capture form that syncs to LeadSquared CRM

A marketing landing page built in Lovable captures prospect information and immediately creates a lead in LeadSquared, triggering the sales team's assigned automation rules and workflows. Custom fields capture source-specific data like the campaign name, product interest, and UTM parameters. The sales team sees new leads in real-time in their LeadSquared inbox without any manual data transfer.

Prompt example:

```
Create a lead capture form with fields for first name, last name, email, phone, and product interest (dropdown). When submitted, call an Edge Function that uses the LeadSquared API to create a lead with these fields plus source set to 'Website' and LeadStatus set to 'New'. Map product interest to a LeadSquared custom attribute called 'mx_Product_Interest'. On success, show a thank-you message and record the LeadSquared lead ID in the Supabase submissions table.
```

### Activity log from field sales mobile app

A field sales team uses a Lovable web app to log their daily activities — calls, meetings, and site visits. When a rep submits an activity, the Edge Function posts it to LeadSquared as a lead activity against the appropriate lead record. Sales managers can see the logged activities in LeadSquared's activity timeline and track field team performance through the CRM's built-in reports.

Prompt example:

```
Build a field activity logging screen for sales reps. Show a list of their assigned leads from LeadSquared (fetched via Edge Function from the GetLeads API). When a rep selects a lead and logs an activity (call, meeting, site visit) with notes and outcome, POST that activity to the LeadSquared PostLeadActivity API via an Edge Function. Include activity type, related lead ID, notes, and date. After successful save, sync the activity to the local Supabase activities table for offline access.
```

### Sales pipeline dashboard pulling LeadSquared data

An internal dashboard built in Lovable displays real-time pipeline metrics from LeadSquared — lead counts by stage, today's activities, and opportunity values. Edge Functions query the LeadSquared SearchLeads and Opportunities APIs to aggregate data, which is cached in Supabase to reduce API call frequency. Sales managers get a custom view of their pipeline without leaving the Lovable app.

Prompt example:

```
Create a sales dashboard that fetches pipeline data from LeadSquared. Build an Edge Function that calls the LeadSquared GetLeads API with status filter to count leads by stage (New, Contacted, Qualified, Proposal, Won, Lost). Also fetch today's activities using GetLeadActivities with date filter. Display the results as summary cards showing lead counts per stage and a list of today's pending follow-ups. Refresh data every 5 minutes. Cache results in a Supabase pipeline_cache table to avoid hitting LeadSquared API limits.
```

## Troubleshooting

### API returns 401 Unauthorized even with correct Access Key and Secret Key

Cause: The API host URL is wrong for your LeadSquared data center. LeadSquared has US (api.leadsquared.com) and multiple India data centers (in21.leadsquared.com, in22.leadsquared.com) — using the wrong host returns a 401 even with valid credentials.

Solution: Log into your LeadSquared account and go to Settings → API & Webhooks. Look at the API Host field — copy the exact URL shown there and update LEADSQUARED_HOST in Cloud → Secrets. The host does not include 'https://' — just the hostname like 'in21.leadsquared.com'.

### Lead is created successfully but custom mx_ fields are empty in LeadSquared

Cause: The custom attribute name in your API request doesn't match the exact field name created in LeadSquared settings. Field names are case-sensitive and must exactly match what's defined in Settings → Lead Custom Fields.

Solution: In LeadSquared, go to Settings → Lead Custom Fields and note the exact API name for each custom field — it appears as the field's attribute code. Use that exact name after the mx_ prefix. For example, if the field is named 'Product Interest', its attribute might be 'mx_Product_Interest' or 'mx_ProductInterest' depending on how it was created.

### Edge Function times out when calling LeadSquared with large attribute arrays

Cause: LeadSquared API requests with many custom attributes can be slow. Combined with Supabase Edge Function cold start time, this can exceed default timeouts.

Solution: Limit your attributes array to only the fields you actually need. Remove empty string values — sending blank attributes is unnecessary and adds payload size. For the initial capture, only send critical fields (name, email, phone, source). Additional attributes can be updated in a separate API call after the lead is created using the Lead.Update endpoint.

```
// Filter out empty values before sending:
const attributes = rawAttributes.filter(a => a.Value !== "" && a.Value !== null && a.Value !== undefined);
```

### Duplicate leads created when the same email submits the form twice

Cause: The Lead.Create endpoint always creates a new lead even if the email already exists. LeadSquared does not deduplicate by email by default on the basic create endpoint.

Solution: Use the Lead.CreateOrUpdate endpoint instead of Lead.Create. The URL is the same but use POST to /v2/LeadManagement.svc/Lead.CreateOrUpdate. This endpoint checks for existing leads by email and updates the existing record instead of creating a duplicate.

```
// Change endpoint from:
const url = `https://${HOST}/v2/LeadManagement.svc/Lead.Create?...`;
// To:
const url = `https://${HOST}/v2/LeadManagement.svc/Lead.CreateOrUpdate?...`;
```

## Frequently asked questions

### Does LeadSquared have a free tier for testing?

LeadSquared offers a free trial but not a permanent free tier. Contact LeadSquared sales for a trial account, or use their sandbox environment if your account includes it. Unlike Authorize.net or Stripe, LeadSquared doesn't have a widely accessible developer sandbox — most testing is done in a trial account with test data you clean up before going live.

### What are the LeadSquared API rate limits?

LeadSquared's API rate limits depend on your plan. Most plans allow hundreds of requests per minute, which is sufficient for form submissions and activity logging. High-volume use cases like bulk lead imports should use LeadSquared's bulk import API rather than individual Create calls. Check your account's API documentation or contact LeadSquared support for your plan's specific limits.

### Can I use webhooks from LeadSquared to push data to Lovable?

Yes — LeadSquared supports outbound webhooks that fire when leads are updated, stages change, or activities are logged. Configure them under Settings → API & Webhooks → Outbound Webhooks, pointing to a Supabase Edge Function URL. This lets you keep Supabase in sync with LeadSquared changes without polling. Your Edge Function receives the webhook payload and updates relevant Supabase records.

### How do I look up a lead's ProspectId from their email address?

Use the LeadSquared Search Leads API: GET https://{host}/v2/LeadManagement.svc/Leads.GetByEmailAddress?accessKey={key}&secretKey={secret}&emailAddress={email}. This returns the lead's ProspectId and all their attributes. Store the ProspectId in Supabase so future API calls can use it directly instead of searching by email each time.

---

Source: https://www.rapidevelopers.com/lovable-integration/leadsquared
© RapidDev — https://www.rapidevelopers.com/lovable-integration/leadsquared
