For the complete documentation index, see llms.txt. This page is also available as Markdown.

Connect your own form

Auto-trigger a phone call when your existing lead form is submitted.

You already have a lead form. You do not have to replace it β€” have it trigger a phone call as well, so a submitted form rings your team within seconds instead of sitting in an inbox.

This is the highest-value integration the widget has. Speed of response is the single biggest driver of inbound lead conversion, and a form that rings you immediately beats one that emails you every time.

Two ways

Approach
Use when

Ask the widget

The widget is installed. Shortest path, and it handles validation for you.

Hand off to the widget

You want the widget's own confirmation screen and ringing state.

Post directly

You want your own interface end to end, or you are submitting from a server.

Ask the widget

If the widget is already on the page, requestCallback() does the whole thing and tells you what happened:

No key in your code, no endpoint to get right, and the phone number is validated before anything leaves the browser. It resolves { ok, id, message } and never rejects, so there is nothing to catch.

Hand off to the widget

To show the widget's own confirmation and ringing state instead of your own, pass the number to call() and let it take over:

call() returns a boolean that tells you nothing about the outcome β€” listen for callback:requested and callback:failed, or use requestCallback() above.

Pair either with hideLauncher() if you do not want the floating button on the page.

Post directly

To keep your own interface entirely, post to the widget's public endpoint. This uses your widget key β€” the publishable one from your snippet's data-key β€” not a secret API key.

Use the same host as your snippet's data-api value.

Fields

Field
Required
Notes

phone

yes

The number to call back, international format.

name

no

Shown to whoever takes the call.

email

no

Stored on the resulting lead.

department

no

Routes to a specific team.

captured

no

Extra fields you collected, carried onto the lead.

sessionId

no

Ties the request to a widget session for attribution. If the widget is on the page, get it from window.LimeCall.getVisitorId().

Success returns the callback's id. A failure returns a message worth showing the visitor β€” it is where "outside business hours" arrives.

Scheduling instead

Same shape plus a time, to a different path:

Worked example β€” an existing lead form

A complete drop-in: keep your form and its styling, add a call request, and fall back gracefully when nobody can be reached.

What that example gets right

Your backend still receives the lead. The call request is added alongside, not instead. If LimeCall is unreachable you have still captured the enquiry.

It tells the visitor a call is coming. Someone who does not expect a call does not answer an unknown number, and the whole point is lost. Say it before the phone rings.

It shows the API's own message on failure. "We're closed right now" is useful; "Something went wrong" is not.

It disables the button. A visitor who clicks twice otherwise gets rung twice.

captured carries the free-text field onto the lead, so whoever picks up can see what was asked before they speak.

Only promise a call someone can take

Ask before you offer. hasAvailableAgents() accounts for working hours, whether the people the widget routes to still resolve, and β€” on an AI-routed widget β€” whether you have minutes left:

Changing the label is better than hiding the option. The lead is still captured either way; the visitor just is not told to expect a ringing phone that never comes.

If you are posting directly rather than using the widget, the request still succeeds outside hours β€” the response message is where "we're closed right now" arrives, which is why the example above shows it to the visitor verbatim.

Which key is which

See API keys.

Doing it server-side instead

If your form already posts to your own backend, create the callback there. It is the right choice when you want to validate, deduplicate, enrich or rate-limit before spending a call β€” and the visitor's browser never has to be trusted.

It is the same endpoint, with a secret key instead of a widget key:

Browser
Your server

Header

X-Widget-Key: pk_live_…

Authorization: Bearer sk_live_…

Origin

Must be on your allowed list

Not checked

fromNumber

From your saved widget settings

Required in the body

Daily cap

Your widget's cap (default 50)

dailyCallbackCap, default 200

Node

PHP

What you can send

phone and fromNumber are required. name, email, department, captured and sessionId behave exactly as they do from the browser.

The server path also accepts routing overrides the browser cannot set, so one key can serve several brands or campaigns: dailyCallbackCap, bridgeProvider ("vapi" or "grok"), voiceAgentId, callableCountries, blockedCountries and blockVoip.

Errors worth handling

Status

error

Means

400

missing_from_number

fromNumber was not sent.

401

unauthorized

Key missing, malformed or revoked.

403

insufficient_scope

The key lacks calls:write.

403

from_not_owned

That caller ID is not a number on your account.

403

(destination)

The number is in a range we refuse to dial.

429

spend_cap

The daily cap is spent.

from_not_owned exists because fromNumber comes from your request body on this path. The check stops a leaked key being used to spoof someone else's caller ID.

See API keys for creating a key with the right scope.

Was this helpful?