LeadSquared
The LeadSquared integration runs in two independent directions. Most accounts use both together, but each can be enabled on its own:
| Direction | What happens | Section |
|---|---|---|
| Inbound — LeadSquared → Sprio | A lead is created, or reassigned to a specific owner, and Sprio automatically places an outbound call | Auto-call trigger |
| Outbound — Sprio → LeadSquared | After a Sprio call ends, a lead record is created/updated in LeadSquared with the call outcome | Post-call lead push |
Both use the same LeadSquared API credential (an Access Key + Secret Key pair, generated from LeadSquared's own Settings → API page — this is not something Sprio issues).
Inbound: Auto-call trigger
How it works
- You connect LeadSquared from Integrations → LeadSquared and choose which assistant should place the calls.
- Sprio registers two webhooks on your LeadSquared account via their
native
Webhook.svc/CreateAPI — one for lead creation, one for owner reassignment (see why two below). This happens automatically; there's no manual webhook setup on your side. - When either event fires, LeadSquared POSTs the lead's data to Sprio. Sprio validates the request, queues the lead, and — once the checks below pass — places a call using the assigned assistant, with the lead's name and details available to the assistant during the conversation.
Why two webhooks
LeadSquared's Webhook.svc/Create ties one webhook to exactly one
WebhookEvent. In real usage, "a lead enters the account" almost always
means an existing lead being reassigned to a specific owner (e.g. your
sales team routes a lead to an "AI Calling" account when they want Sprio to
call it) — not a brand-new lead being created. Registering only the
creation event misses this entirely: a reassignment produces zero
webhook traffic unless the owner-change event is also registered.
| WebhookEvent | Meaning | Payload shape |
|---|---|---|
3 | Lead creation | Flat — fields posted directly on the request body |
4 | Lead owner change | Wrapped — {"Before": {...}, "After": {...}}; Sprio reads After |
Both webhooks point at the same URL and the same secret token; both feed the identical processing pipeline below.
Field detection
LeadSquared's field names are per-tenant configurable (different accounts name their phone/lead-id fields differently), so Sprio checks a list of common variants rather than requiring one fixed key:
| What Sprio needs | Fields checked (case-insensitive) |
|---|---|
| Phone number | Phone, Mobile, MobileNumber, Mobile_Number, PhoneNumber, Phone_Number, ContactNumber, Contact_Number, mx_Alternate_Number, mx_Phone, mx_Mobile |
| Lead identifier | ProspectID, ProspectId, prospectid, Id, LeadId, RelatedProspectId |
| Owner identifier | OwnerId, Owner |
| Context given to the assistant | FirstName, LastName, EmailAddress, Source, City, mx_City, mx_Project_Name, Notes, ProspectStage |
If the webhook payload is missing a phone number (or the owner ID, when an
owner restriction is configured — see below), Sprio makes a fallback call to
LeadSquared's LeadManagement.svc/Leads.GetById to fetch the full record.
Owner restriction (optional, recommended)
LeadSquared's webhook API has no server-side filtering — a registered webhook fires for every lead across the entire account, with no way to scope it to "only leads owned by user X" at registration time. Without an app-level filter, turning on auto-call would call every new/reassigned lead org-wide.
Sprio's trigger_owner_user_id setting closes this gap: configure it to a
specific LeadSquared user ID (e.g. a dedicated "AI Calling" account), and
Sprio only places a call when the lead's owner matches — every other real
lead is received, logged, and skipped (visible in your integration's
Activity tab as owner_mismatch).
If you want true server-side scoping instead of an app-level filter, that requires building a custom Automation Workflow inside LeadSquared itself — a separate, LeadSquared-side mechanism you'd maintain independently. Most accounts find the app-level filter sufficient.
Dedup guarantees
- Once per lead per day — the same lead ID won't trigger a second call the same day (IST). A lead re-entering tomorrow is treated as fresh.
- Cross-assistant phone dedup — if any assistant on this connection has already dialed a phone number, no other assistant on the same connection will dial it again, even if the number arrives under a different lead ID.
- Race-safe — both checks above are enforced by a database uniqueness constraint, not just a pre-check, so concurrent webhook deliveries (e.g. a bulk reassignment) can't double-dial.
- Loop guard — a lead carrying one of your own platform phone numbers is never auto-called.
Known LeadSquared platform behavior
- No signature scheme. Authenticity is the secret token header alone
(
X-Sprio-Webhook-Token, generated per connection). LeadSquared lets a webhook carry custom headers (CustomHeaders) — this is what carries the token. - Auto-disables after failures. LeadSquared disables a webhook after 10
consecutive delivery failures, so Sprio always acknowledges quickly
(
200 OK) before doing any real processing. - Validates the URL synchronously during registration. When a webhook is
created, LeadSquared immediately fires a
HEADrequest, then aPOSTcarrying the token, as part of validating the registration call itself — beforeCreateeven returns a response. Sprio's webhook route always answers these fast. - Delivery isn't instant. Expect roughly 5–10 minutes between a lead event happening in LeadSquared and the webhook actually arriving — this is LeadSquared's own dispatch latency, not something Sprio can speed up.
Outbound: Post-call lead push
After a call ends, Sprio can push the outcome back into LeadSquared as a
lead record using Lead.Capture.
Field mapping
Field mapping is configured per connection. A typical setup:
| LeadSquared field | Source |
|---|---|
FirstName | Extracted from the call (optional — sent blank if not captured, not skipped) |
Phone | The caller's number |
EmailAddress | A unique per-call placeholder (voice-lead-{call_id}@dummy.com) — avoids LeadSquared's email-based dedup colliding across different callers |
Source | Configurable literal, or conditional based on whether call details were captured |
mx_Project_Name, mx_City, etc. | Extracted from the call, if your extraction schema captures them |
Field availability depends on your LeadSquared tenant's schema — fields like
mx_Location that don't exist on your account will reject the whole push
with a MXUnknownAttributeException. Confirm your field set with your
LeadSquared admin before enabling a mapping.
Repeat callers and phone uniqueness
LeadSquared's own dedup behavior matters here:
Lead.CapturewithSearchBy: Phonemerges into the existing lead for a repeat caller rather than creating a new one — this is expected LeadSquared behavior (its response reportsIsCreated: false), not a Sprio bug.- If your LeadSquared tenant enforces a unique Phone constraint, using
Lead.Create(always creates) instead will fail for repeat callers withMXDuplicateEntryException. If you need every call to always create a brand-new lead record regardless of repeat callers, your LeadSquared admin needs to relax that constraint — there's no workaround on Sprio's side.
Templates and optional fields
Field values that use a {placeholder} template have no fallback — a
call missing any referenced value aborts that entire push. Reserve
templates for fields that are always populated (like the per-call email
placeholder above); use plain extracted-field mapping for anything
optional.
Setup checklist
- Get your Access Key and Secret Key from LeadSquared (Settings → API, on your LeadSquared account).
- In Sprio, go to Integrations → LeadSquared → Connect, and enter the credential.
- For inbound auto-calling: assign the assistant, set
trigger_owner_user_idif you want owner-scoped filtering, and enable auto-call new leads. - For outbound post-call push: configure field mapping and which call statuses should trigger a push.
- Send a test event from the connection page to confirm the whole pipeline before relying on real leads — see Testing.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Reassigning a lead's owner doesn't trigger a call | Confirm both webhooks are armed (Integrations → LeadSquared connection detail shows webhook status) — a connection created before this was fixed may only have the creation webhook |
A real lead is skipped with owner_mismatch in Activity | Expected if trigger_owner_user_id is set and the lead isn't owned by that user — this is the filter working as intended |
| No call after a lead event, no error either | LeadSquared's own dispatch delay (5–10 min) — wait before assuming failure; check the connection's Activity tab for received-but-unprocessed events |
Outbound push fails with MXUnknownAttributeException | A mapped field doesn't exist on your LeadSquared tenant's schema — remove or rename it in your field mapping |
Outbound push fails with MXDuplicateEntryException | Your tenant enforces unique Phone and you're using Lead.Create — switch to Lead.Capture + SearchBy:Phone, or ask LeadSquared support to relax the constraint |