Integrate LeadSquared with Bolt.new using their REST API with access key and secret key authentication in custom request headers. Capture leads from Bolt forms via API route, fetch lead details and activity history, and build a lead management dashboard. LeadSquared uses a unique x-LSQ-AccessKey and x-LSQ-SecretKey header authentication pattern — store both keys server-side. Webhook-based automation triggers require a deployed Netlify URL.
Connect Bolt.new Forms and Dashboards to LeadSquared CRM
LeadSquared is one of the leading CRM platforms in India and Southeast Asia, with particularly strong adoption in education, healthcare, financial services, and field sales industries. Unlike Salesforce or HubSpot (which require significant configuration for high-volume lead operations), LeadSquared is purpose-designed for the specific workflows of sales teams handling thousands of leads per day — structured calling queues, automated lead distribution, field sales apps with offline capability, and role-based access control for large sales hierarchies.
For Bolt.new developers working with clients or companies in these markets, integrating lead capture and management features with LeadSquared is a natural requirement. The API supports all the operations you would need: creating leads (called 'Prospects' in some LeadSquared versions), logging sales activities against contacts, updating lead quality scores, retrieving lead details, and querying leads by various criteria.
LeadSquared's authentication model uses custom HTTP headers — x-LSQ-AccessKey and x-LSQ-SecretKey — rather than OAuth or Bearer tokens. Both keys appear in every API request header. Since these headers are included in every call to `api.leadsquared.com`, they must stay server-side in your Next.js API routes. A client-side fetch to LeadSquared would expose both keys in browser developer tools.
Integration method
LeadSquared's REST API uses a custom header authentication scheme with x-LSQ-AccessKey and x-LSQ-SecretKey values that must be included in every request. All API calls from Bolt must go through a Next.js API route with these keys stored in server-side environment variables — never in client code. The API supports lead creation, activity logging, custom field management, and lead scoring. Webhook notifications for automation events require a deployed Netlify URL.
Prerequisites
- A LeadSquared account at leadsquared.com — API access requires a paid LeadSquared subscription
- LeadSquared API credentials: go to My Profile → API Settings to find your Access Key and Secret Key
- The LeadSquared API host URL for your account region (e.g., api.leadsquared.com for India, api-us.leadsquared.com for US)
- A Bolt.new account with a new Next.js project open
- A Netlify account for deployment if you plan to use LeadSquared webhook notifications
Step-by-step guide
Get LeadSquared API credentials and understand the authentication pattern
Get LeadSquared API credentials and understand the authentication pattern
LeadSquared uses a custom header-based authentication scheme that is different from most modern APIs. Rather than OAuth tokens or Bearer authentication, every API request must include two custom headers: `x-LSQ-AccessKey` containing your Access Key, and `x-LSQ-SecretKey` containing your Secret Key. Both are required for every request — missing either one results in a 401 error. To find your credentials: in LeadSquared, click your account name or profile icon in the top-right corner → My Profile → API Settings (also sometimes found under Settings → CRM Settings → API Settings depending on your LeadSquared version). You will see your Access Key and Secret Key displayed. Copy both — they are long alphanumeric strings. LeadSquared has multiple regional API endpoints. The standard India endpoint is `api.leadsquared.com`. For US-hosted accounts, the endpoint is `api-us.leadsquared.com`. Check your account settings or LeadSquared documentation to confirm the correct endpoint for your account region. Using the wrong regional endpoint results in authentication failures even with correct credentials. Store both keys in your .env.local as LEADSQUARED_ACCESS_KEY and LEADSQUARED_SECRET_KEY. Also add LEADSQUARED_API_HOST (e.g., `api.leadsquared.com`) to make the regional endpoint configurable without changing code. These are server-side credentials — never add NEXT_PUBLIC_ prefix. Anyone with both keys can make full API calls to your LeadSquared account.
Set up LeadSquared API integration. Create .env.local with LEADSQUARED_ACCESS_KEY=your-access-key, LEADSQUARED_SECRET_KEY=your-secret-key, LEADSQUARED_API_HOST=api.leadsquared.com. Create lib/leadsquared.ts with a base apiRequest function that accepts path (string), method ('GET'|'POST'), and body (optional object). The function builds the URL as https://{LEADSQUARED_API_HOST}/{path}, adds Content-Type and x-LSQ-AccessKey and x-LSQ-SecretKey headers. Add TypeScript interfaces for LeadSquaredLead (FirstName, LastName, EmailAddress, Phone, Source, ProspectStage, ProspectScore, mx_Custom_1 example custom field). Export createLead, getLeads, getLeadByEmail, and updateLead helper functions.
Paste this in Bolt.new chat
1// lib/leadsquared.ts2export interface LeadSquaredLead {3 ProspectID?: string;4 FirstName: string;5 LastName: string;6 EmailAddress: string;7 Phone?: string;8 Mobile?: string;9 Company?: string;10 Source?: string;11 Description?: string;12 ProspectStage?: string;13 ProspectScore?: number;14 OwnerIdEmail?: string;15 [key: string]: string | number | undefined;16}1718export interface LeadSquaredActivity {19 RelatedProspectId: string;20 ActivityEvent: number; // 200-999 range for custom events, standard = 1-19921 ActivityNote?: string;22 ActivityDateTime?: string;23}2425interface ApiOptions {26 method?: 'GET' | 'POST';27 body?: unknown;28 queryParams?: Record<string, string | number>;29}3031async function apiRequest<T>(path: string, options: ApiOptions = {}): Promise<T> {32 const accessKey = process.env.LEADSQUARED_ACCESS_KEY;33 const secretKey = process.env.LEADSQUARED_SECRET_KEY;34 const apiHost = process.env.LEADSQUARED_API_HOST || 'api.leadsquared.com';3536 if (!accessKey || !secretKey) {37 throw new Error('LeadSquared credentials not configured');38 }3940 const url = new URL(`https://${apiHost}/${path}`);41 if (options.queryParams) {42 for (const [key, value] of Object.entries(options.queryParams)) {43 url.searchParams.set(key, String(value));44 }45 }4647 const response = await fetch(url.toString(), {48 method: options.method || 'GET',49 headers: {50 'Content-Type': 'application/json',51 'x-LSQ-AccessKey': accessKey,52 'x-LSQ-SecretKey': secretKey,53 },54 ...(options.body ? { body: JSON.stringify(options.body) } : {}),55 });5657 const text = await response.text();58 if (!response.ok) {59 throw new Error(`LeadSquared API error ${response.status}: ${text}`);60 }6162 if (!text) return null as T;6364 try {65 return JSON.parse(text) as T;66 } catch {67 return text as unknown as T;68 }69}7071export async function createLead(leadData: Partial<LeadSquaredLead>): Promise<{ Message: string; ProspectID?: string }> {72 return apiRequest('v2/LeadManagement.svc/Lead.Create', {73 method: 'POST',74 body: leadData,75 });76}7778export async function getLeads(79 page = 1,80 size = 50,81 searchBy?: string82): Promise<LeadSquaredLead[]> {83 const params: Record<string, string | number> = { Page: page, Size: size };84 if (searchBy) params.SearchText = searchBy;8586 const result = await apiRequest<{ ProspectList: LeadSquaredLead[] }>(87 'v2/LeadManagement.svc/Leads.GetAll',88 { queryParams: params }89 );90 return result?.ProspectList || [];91}9293export async function getLeadByEmail(email: string): Promise<LeadSquaredLead | null> {94 const leads = await apiRequest<LeadSquaredLead[]>(95 'v2/LeadManagement.svc/Lead.GetByEmailAddress',96 { queryParams: { emailaddress: email } }97 );98 return Array.isArray(leads) ? leads[0] : null;99}100101export async function updateLead(102 prospectId: string,103 fields: Partial<LeadSquaredLead>104): Promise<void> {105 await apiRequest('v2/LeadManagement.svc/Lead.Update', {106 method: 'POST',107 body: { ProspectID: prospectId, ...fields },108 });109}Pro tip: LeadSquared API paths use a service-based naming convention: v2/LeadManagement.svc/Lead.Create, v2/LeadManagement.svc/Lead.GetByEmailAddress, etc. The service name (LeadManagement.svc) and method name (Lead.Create) are case-sensitive. Check LeadSquared's API documentation for your version to confirm exact endpoint paths.
Expected result: A lib/leadsquared.ts helper with typed functions for lead management and authentication headers configured, ready for use in API routes.
Build the lead capture API route with source tracking
Build the lead capture API route with source tracking
The lead capture API route creates a new lead in LeadSquared from a Bolt.new form submission. Source tracking is particularly important in LeadSquared integrations because the platform's lead scoring and distribution rules often depend on lead source — a lead from a pricing page might go to the enterprise sales team, while a lead from a help article goes to a success manager. LeadSquared's API for creating leads accepts a flat object with field names that must match LeadSquared's configured field names exactly. Standard fields use PascalCase: FirstName, LastName, EmailAddress, Phone, Mobile, Company, Source, Description. Custom fields added by your LeadSquared administrator have names starting with `mx_` followed by the custom field name (e.g., `mx_Course_Interested_In` for an education platform). The create-or-update pattern prevents duplicate lead records when the same email submits a form multiple times. Use `getLeadByEmail` to check for an existing record. If found, update the existing lead with any new information and log an activity. If not found, create a new lead. This is especially important in lead generation contexts where prospects submit multiple inquiry forms. For lead quality, consider adding a scoring hint at creation time. LeadSquared has automated scoring rules, but you can also pass initial quality signals: if the form asks for budget range or company size, these can be mapped to a custom field that feeds into LeadSquared's scoring formulas.
Create a lead capture API route at app/api/leadsquared/capture/route.ts using lib/leadsquared.ts. Accept POST with: firstName (required), lastName (required), email (required, validate format), phone (optional), company (optional), source (optional, defaults to 'Web Form'), message (optional), customFields (optional Record<string,string>). Check for existing lead by email. If exists, update with new data. If new, create with LeadSquared field names (FirstName, LastName, EmailAddress, Phone, Company, Source, Description). Map customFields to mx_ prefixed keys. Return 201 for new leads, 200 for updates. Create an InquiryForm React component with name, email, phone, company, and message fields, plus Zod validation and success/error states.
Paste this in Bolt.new chat
1// app/api/leadsquared/capture/route.ts2import { NextRequest, NextResponse } from 'next/server';3import { createLead, updateLead, getLeadByEmail } from '@/lib/leadsquared';45const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;67export async function POST(request: NextRequest) {8 const body = await request.json();9 const { firstName, lastName, email, phone, company, source, message, customFields } = body;1011 if (!firstName?.trim()) return NextResponse.json({ error: 'First name required' }, { status: 400 });12 if (!lastName?.trim()) return NextResponse.json({ error: 'Last name required' }, { status: 400 });13 if (!email || !emailRegex.test(email)) {14 return NextResponse.json({ error: 'Valid email required' }, { status: 400 });15 }1617 const leadData: Record<string, string> = {18 FirstName: firstName.trim(),19 LastName: lastName.trim(),20 EmailAddress: email.toLowerCase().trim(),21 Source: source || 'Web Form',22 };2324 if (phone) leadData.Phone = phone.trim();25 if (company) leadData.Company = company.trim();26 if (message) leadData.Description = message.trim();2728 // Map custom fields with mx_ prefix29 if (customFields && typeof customFields === 'object') {30 for (const [key, value] of Object.entries(customFields)) {31 if (typeof value === 'string') {32 leadData[`mx_${key}`] = value;33 }34 }35 }3637 try {38 const existing = await getLeadByEmail(email);3940 if (existing?.ProspectID) {41 await updateLead(existing.ProspectID, leadData);42 return NextResponse.json({ success: true, action: 'updated', prospectId: existing.ProspectID });43 } else {44 const result = await createLead(leadData);45 return NextResponse.json({ success: true, action: 'created', prospectId: result?.ProspectID }, { status: 201 });46 }47 } catch (error) {48 console.error('LeadSquared capture error:', error);49 return NextResponse.json({ error: 'Failed to save lead' }, { status: 500 });50 }51}Pro tip: Ask your LeadSquared administrator for the exact custom field names (mx_ prefixed) used in your account. Custom field names are set by the account administrator and vary across accounts — the custom field for 'Course of Interest' in one account might be mx_Course_Interest in another. You can also fetch all field definitions via LeadSquared's LeadManagement.svc/GetLeadFieldDefinitions endpoint.
Expected result: A lead capture API route that creates or updates LeadSquared leads from Bolt form submissions, with custom field support and source tracking.
Build a lead list and activity dashboard
Build a lead list and activity dashboard
A lead management dashboard lets sales teams view and act on their LeadSquared pipeline without leaving your Bolt.new app. This is valuable for teams that want a simplified view of their leads — filtered by their assignment, sorted by score, or focused on a specific lead stage — alongside other app data. LeadSquared's `Leads.GetAll` endpoint supports pagination via `Page` and `Size` parameters, and returns leads in descending order of creation date by default. For a dashboard, you typically want to display the most recent leads or highest-scoring leads first. The API also supports search via a `SearchText` parameter that searches across name, email, and phone. The activity log is one of LeadSquared's most distinctive features. Every interaction — call made, email sent, meeting held, form submitted — is recorded as an Activity linked to a lead's ProspectID. Fetching activity history with `ProspectActivity.GetByProspectId` gives you a timeline of every touchpoint for a specific lead. This is valuable for building a lead detail view that shows the complete engagement history. For the scoring visualization, LeadSquared stores a numeric `ProspectScore` on each lead that is updated by the platform's scoring engine as the lead takes actions and matches scoring criteria. Displaying this score alongside other lead data helps sales managers prioritize follow-up — a dashboard sorted by score with color-coded temperature indicators (hot/warm/cold) is one of the most frequently requested LeadSquared dashboard features.
Create a lead management dashboard. Build two API routes: GET /api/leadsquared/leads that accepts page and size query params and calls getLeads from lib/leadsquared.ts, returning the list with pagination info, and GET /api/leadsquared/leads/:id/activities that fetches activity history for a specific lead from ProspectActivity.GetByProspectId. Create a LeadDashboard React component with: a search input that filters leads by name/email, a leads table with columns for name, email, company, source, score (color-coded badge), stage, and last activity date, and a drawer/modal showing full lead details and activity timeline when a row is clicked.
Paste this in Bolt.new chat
1// app/api/leadsquared/leads/route.ts2import { NextRequest, NextResponse } from 'next/server';3import { getLeads } from '@/lib/leadsquared';45export async function GET(request: NextRequest) {6 const { searchParams } = new URL(request.url);7 const page = parseInt(searchParams.get('page') || '1', 10);8 const size = parseInt(searchParams.get('size') || '25', 10);9 const search = searchParams.get('q') || undefined;1011 try {12 const leads = await getLeads(page, Math.min(size, 100), search);13 return NextResponse.json({ leads, page, size });14 } catch (error) {15 return NextResponse.json(16 { error: (error as Error).message },17 { status: 500 }18 );19 }20}2122// app/api/leadsquared/leads/[id]/activities/route.ts23// (create as a separate file)24import { NextRequest, NextResponse } from 'next/server';2526async function getLeadActivities(prospectId: string) {27 const accessKey = process.env.LEADSQUARED_ACCESS_KEY!;28 const secretKey = process.env.LEADSQUARED_SECRET_KEY!;29 const apiHost = process.env.LEADSQUARED_API_HOST || 'api.leadsquared.com';3031 const url = `https://${apiHost}/v2/ProspectActivity.svc/ProspectActivity.GetByProspectId?prospectId=${prospectId}&pageIndex=1&pageSize=20`;3233 const response = await fetch(url, {34 headers: {35 'x-LSQ-AccessKey': accessKey,36 'x-LSQ-SecretKey': secretKey,37 },38 });3940 if (!response.ok) throw new Error(`LeadSquared API error: ${response.status}`);41 return response.json();42}4344export async function GET(45 request: NextRequest,46 { params }: { params: { id: string } }47) {48 try {49 const activities = await getLeadActivities(params.id);50 return NextResponse.json(activities);51 } catch (error) {52 return NextResponse.json(53 { error: (error as Error).message },54 { status: 500 }55 );56 }57}Pro tip: LeadSquared's ProspectScore ranges from 0-100. Define temperature thresholds appropriate for your account's scoring setup — the default hot/warm/cold split at 80/50/0 may not match how your LeadSquared scoring is configured. Check with your LeadSquared admin for the score thresholds that map to your sales team's terminology.
Expected result: A lead list API route with search and pagination, plus an activities API route, ready for a dashboard React component.
Deploy to Netlify and configure LeadSquared webhooks
Deploy to Netlify and configure LeadSquared webhooks
LeadSquared API calls work in Bolt.new's WebContainer during development — the outbound HTTP requests to `api.leadsquared.com` with custom headers are supported in the browser-based runtime. You can test lead creation, fetching, and activity logging in the Bolt preview before deploying. Deployment to Netlify is required for production use and for any LeadSquared webhook features. LeadSquared can send webhook notifications to your app when specific lead events occur — lead stage changes, activity additions, quality score updates — through their Workflow Builder or API Webhooks settings. To deploy: click Deploy in Bolt.new, connect Netlify via OAuth, and wait for the build. In the Netlify dashboard → Site Configuration → Environment Variables, add: LEADSQUARED_ACCESS_KEY, LEADSQUARED_SECRET_KEY, and LEADSQUARED_API_HOST. Trigger a redeploy. For LeadSquared webhooks: the configuration depends on your LeadSquared version. In some versions, go to Settings → CRM Settings → Webhooks. In others, webhooks are configured within the Automation Workflow builder as a 'Call Webhook' action. Enter your Netlify URL as the webhook endpoint. LeadSquared typically sends form-encoded or JSON POST requests with lead and activity data. This is a fundamental WebContainer constraint — Bolt.new runs in a browser tab and cannot receive incoming HTTP requests. LeadSquared webhooks need a publicly accessible server endpoint, which only exists after deploying to Netlify or Bolt Cloud.
Create a LeadSquared webhook handler at app/api/leadsquared/webhook/route.ts. Accept POST with application/json or application/x-www-form-urlencoded content type. Parse the payload to extract lead ProspectID, event type, and changed fields. Log the event. For stage change events, update a Supabase lead_sync table if it exists. Return 200 for all events. Add netlify.toml with Next.js build configuration and a comment that webhook delivery requires a deployed public URL.
Paste this in Bolt.new chat
1// app/api/leadsquared/webhook/route.ts2// NOTE: LeadSquared webhooks require a publicly accessible URL.3// Deploy to Netlify first, then configure in LeadSquared Settings → Webhooks.4import { NextRequest, NextResponse } from 'next/server';56export async function POST(request: NextRequest) {7 const contentType = request.headers.get('content-type') || '';89 let payload: Record<string, unknown>;1011 try {12 if (contentType.includes('application/x-www-form-urlencoded')) {13 const text = await request.text();14 const params = new URLSearchParams(text);15 payload = Object.fromEntries(params.entries());16 } else {17 payload = await request.json();18 }19 } catch {20 return NextResponse.json({ error: 'Invalid payload' }, { status: 400 });21 }2223 const eventType = payload.event_type as string || payload.EventType as string || 'unknown';24 const prospectId = payload.ProspectID as string || payload.prospect_id as string;25 const email = payload.EmailAddress as string || payload.email as string;2627 console.log(`LeadSquared webhook: ${eventType}`, { prospectId, email });2829 switch (eventType) {30 case 'LeadStageChanged':31 case 'lead.stage_changed':32 console.log(`Lead ${email} stage changed to: ${payload.ProspectStage || payload.new_stage}`);33 // TODO: Update lead stage in Supabase if syncing lead data34 break;3536 case 'ActivityAdded':37 case 'lead.activity_added':38 console.log(`Activity added for lead: ${email}`);39 break;4041 case 'LeadCreated':42 case 'lead.created':43 console.log(`New LeadSquared lead created: ${email}`);44 break;4546 default:47 console.log(`Unhandled LeadSquared webhook: ${eventType}`);48 }4950 return NextResponse.json({ received: true });51}Pro tip: LeadSquared's webhook payload format can vary between accounts and versions — some send JSON, some send form-encoded data. The webhook handler above handles both formats. If you are not sure which format your LeadSquared account uses, log the raw request body first and inspect the output after configuring the webhook.
Expected result: A deployed Netlify app with LeadSquared lead capture working in production and a webhook handler receiving lead event notifications.
Common use cases
Inquiry Form to LeadSquared CRM
Capture inquiries from a landing page form (education enrollment, financial product interest, service consultation request) and create a corresponding lead record in LeadSquared immediately. The lead enters the sales queue for the assigned team to follow up, with the source (which landing page) tracked in the lead record.
Create an inquiry capture form that sends leads to LeadSquared. Build an API route at app/api/leadsquared/leads/route.ts using LEADSQUARED_ACCESS_KEY and LEADSQUARED_SECRET_KEY env vars. Accept POST with firstName, lastName, email, phone, source, and message. Map these to LeadSquared field names (FirstName, LastName, EmailAddress, Phone, Source, Description). POST to https://api.leadsquared.com/v2/LeadManagement.svc/Lead.Create with x-LSQ-AccessKey and x-LSQ-SecretKey headers. Create an InquiryForm React component with these fields plus validation and success/error handling.
Copy this prompt to try it in Bolt.new
Lead Activity Logging Dashboard
Build an internal tool that fetches a sales rep's assigned leads and logs call activities (call made, email sent, meeting booked) back to LeadSquared. Useful for teams that want to log activities from a custom interface without navigating the full LeadSquared CRM UI.
Build a lead activity logger. Create API routes: GET /api/leadsquared/leads that fetches assigned leads using LeadSquared's Lead.GetAll API method with pagination, and POST /api/leadsquared/activity that accepts leadId, activityType ('Call' | 'Email' | 'Meeting'), and notes, then logs the activity using LeadSquared's ProspectActivity.Create endpoint. Create a LeadActivityDashboard React component with a searchable lead list on the left and an activity log form on the right, showing recent activities for the selected lead.
Copy this prompt to try it in Bolt.new
Lead Score Visualization
Display a visual lead scoring dashboard that shows leads sorted by their LeadSquared quality score, with color-coded indicators for score ranges. Helps sales managers quickly identify which leads are hottest and should be prioritized for follow-up.
Create a lead scoring dashboard. Fetch leads from LeadSquared using GET /api/leadsquared/leads and include the ProspectScore field. Group leads into buckets: Hot (score 80-100), Warm (score 50-79), Cold (score 0-49). Create a LeadScoreDashboard React component showing three columns, one per temperature bucket, with lead cards showing name, company, score, and last activity date. Add a donut chart using Recharts showing the distribution across buckets. Refresh data every 5 minutes automatically.
Copy this prompt to try it in Bolt.new
Troubleshooting
LeadSquared API returns 401 with 'Incorrect Keys' message
Cause: Either the x-LSQ-AccessKey or x-LSQ-SecretKey header is missing, contains the wrong value, or the API host URL is for the wrong region. LeadSquared accounts in different regions (India vs US) use different API host domains.
Solution: Verify both LEADSQUARED_ACCESS_KEY and LEADSQUARED_SECRET_KEY in your .env.local match exactly what is shown in LeadSquared under My Profile → API Settings. Check that LEADSQUARED_API_HOST is set to the correct regional endpoint — api.leadsquared.com for India, api-us.leadsquared.com for US accounts. Both headers must be present in every request.
1headers: {2 'Content-Type': 'application/json',3 'x-LSQ-AccessKey': process.env.LEADSQUARED_ACCESS_KEY!,4 'x-LSQ-SecretKey': process.env.LEADSQUARED_SECRET_KEY!,5}Lead creation returns success but lead does not appear in LeadSquared
Cause: LeadSquared has lead deduplication rules and stage filters. New leads may be automatically deduplicated (merged with an existing record with the same email) or placed in a stage that is not visible in your default pipeline view.
Solution: In LeadSquared, go to All Leads (not just the current pipeline view) and search by email address to find the created record. Check your LeadSquared deduplication settings under Settings → Duplicate Management. If the API returns a ProspectID in the response, use that ID to fetch the lead directly via Lead.GetById to confirm it exists.
Custom field values are not saving when creating leads
Cause: Custom field names must exactly match the LeadSquared field system names (starting with mx_), and the field must exist in your LeadSquared account configuration. Sending a field name that does not exist in LeadSquared is silently ignored.
Solution: Check your LeadSquared account's custom fields in Settings → Custom Fields (or Settings → Lead Fields depending on your version). The API field name is the 'Schema Name' shown in that settings page — it begins with mx_ followed by the field identifier. If the field does not appear in Settings, it needs to be created by your LeadSquared administrator before it can receive data via API.
LeadSquared webhooks are not firing during Bolt.new development
Cause: LeadSquared sends webhook POST requests to a publicly accessible URL. Bolt.new's WebContainer runs in a browser tab and cannot receive incoming HTTP connections. The preview URL is not a stable public endpoint.
Solution: Deploy your app to Netlify and configure the webhook in LeadSquared using your Netlify URL. This is a fundamental WebContainer limitation. Alternatively, for testing purposes, you can use a tool like ngrok to temporarily expose a local port — but the recommended approach is to deploy to Netlify early and test with the deployed URL.
Best practices
- Always send both x-LSQ-AccessKey and x-LSQ-SecretKey headers in every LeadSquared API request — either missing results in a 401 error regardless of the other credential being correct
- Store the API host as LEADSQUARED_API_HOST environment variable rather than hardcoding the URL — LeadSquared has regional endpoints and the correct host varies by account
- Verify custom field system names (mx_FieldName format) against your LeadSquared account settings before writing code — sending incorrect field names is silently ignored, not an error
- Implement the create-or-update pattern for lead capture to prevent duplicates — always check for an existing lead by email before creating a new one
- Log the raw API response during development to understand the exact response structure from your LeadSquared account version — field names and response formats can vary between LeadSquared versions
- Add source tracking to every lead capture call — LeadSquared's routing and scoring rules often depend on lead source, and this data is harder to reconstruct after the fact
- Test LeadSquared API calls in the Bolt.new WebContainer preview before deploying — outbound API calls with custom headers work in the preview
- Deploy to Netlify before configuring LeadSquared webhooks — webhooks require a publicly accessible URL that the WebContainer cannot provide
Alternatives
HubSpot has a better free tier, clearer REST API documentation, and a larger global developer community — easier to integrate from Bolt.new and better for teams outside the Indian/Southeast Asian market that LeadSquared primarily serves.
Zoho CRM is also popular in India and Southeast Asia with a well-documented REST API and a free tier — a direct competitor to LeadSquared with similar market positioning and easier API integration.
Freshsales by Freshworks is another strong option in the Indian market with a modern REST API, a free plan, and built-in phone and email tools — competing with LeadSquared on field sales automation features.
Pipedrive is a globally used sales CRM with an excellent REST API and better developer documentation than LeadSquared — preferable for teams building integrations for global sales teams not specifically focused on high-velocity lead operations.
Frequently asked questions
Can LeadSquared API calls work in Bolt.new's WebContainer during development?
Yes. LeadSquared API calls are standard outbound HTTP requests with custom headers — these work in Bolt's WebContainer preview. You can build and test lead creation, fetching, and activity logging in the Bolt preview. The only feature requiring deployment is LeadSquared webhook delivery, which needs a publicly accessible URL to send POST requests to your endpoint.
Why does LeadSquared use x-LSQ- headers instead of standard Bearer token authentication?
LeadSquared's API predates widespread adoption of OAuth and Bearer token authentication standards. Their custom header scheme (x-LSQ-AccessKey and x-LSQ-SecretKey) is functionally equivalent to API key authentication — it identifies your account and authenticates the request. Both headers must appear in every API call. The authentication is HTTP header-based, so it works the same way from any HTTP client.
What regions does LeadSquared's API support and how do I know which endpoint to use?
LeadSquared operates regional data centers with separate API endpoints. The India endpoint is api.leadsquared.com and the US endpoint is api-us.leadsquared.com. Your account region is determined during account setup. Check your LeadSquared dashboard URL — if it is app.leadsquared.com, use api.leadsquared.com. If the URL contains 'us', use the US endpoint. You can also check Settings → API Settings where the base API URL is sometimes displayed.
How do I find the correct field names for LeadSquared custom fields?
In LeadSquared, go to Settings → Custom Fields (or Settings → Lead Fields). Each field shows its 'Schema Name' or 'API Name', which is the field name to use in API calls — it starts with mx_ followed by the field identifier. Alternatively, fetch an existing lead record via the API and inspect the JSON response to see all field names with their current values for your account.
Is LeadSquared suitable for non-Indian or Southeast Asian markets?
Yes, though LeadSquared's design prioritizes high-velocity sales scenarios common in Indian and Southeast Asian markets (education admissions, financial services, healthcare). Global companies in industries with similar sales patterns — field sales teams, high lead volume, mobile-first sales reps — also use LeadSquared successfully. The platform is available in multiple languages and currencies for global deployments.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation