Trigger URL
Every agent has its own trigger URL. POST a lead to it from Zapier, Make, GoHighLevel, Typeform or Facebook Lead Ads, and the agent calls that lead. No API key and no code needed.
POST https://api.avoonta.com/v1/hooks/lead/hk_<64 hex characters>
Switch it on first
A new trigger URL is off and accepts nothing. A workspace owner or admin switches it on by ticking this statement for the agent:
I confirm every lead sent to this URL has agreed to be called and texted by {Company Name}, including by an AI assistant.
We save who ticked it, when, and the exact words. Unticking switches the URL off again. While it is off, or while the agent is switched off, the URL answers 404 not_found.
Only send leads who really agreed to be called by your business, including by an AI assistant. The attestation above is your statement that they did. See Compliance.
What to send
Send JSON (Content-Type: application/json) or form fields (application/x-www-form-urlencoded). At most 64 KB. Multipart form uploads are not supported.
You do not need exact field names. We look for each value by name, ignoring case, spaces and punctuation, at the top level first and then inside nested objects. Facebook's [{ "name": …, "values": [ … ] }] list shape works too.
| We fill | From any of these names |
|---|---|
| phone required | phone, phone_number, mobile, mobile_phone, mobile_number, cell, cell_phone, telephone, tel, contact_phone, lead_phone, phone1, primary_phone |
| first name | first_name, fname, given_name, first. If none, the first word of: full_name, name, contact_name, lead_name |
| last name | last_name, lname, surname, family_name |
| email, email_address, mail, contact_email | |
| company | company, company_name, business, business_name, organization, organisation |
| context for the agent | custom_context, notes, note, message, comments, comment, context, details |
| when the lead agreed | consented_at, consent_timestamp, opt_in_at, opt_in_timestamp, created_time, submitted_at, date_added, submission_time, timestamp, created_at |
The phone follows the same rules as lead.phone in Orders: US numbers only. The consent time can be ISO 8601 or a Unix time in seconds or milliseconds. If there is none, or it is in the future or unreadable, we use the time we received the lead.
Example
curl -X POST "https://api.avoonta.com/v1/hooks/lead/hk_…" \
-H "Content-Type: application/json" \
-d '{
"full_name": "Daniel Cohen",
"phone_number": "(415) 555-0199",
"email": "daniel@acme.example",
"message": "Wants a quote for a 10kW system",
"submitted_at": "2026-10-14T09:00:00Z"
}'
HTTP/1.1 202 Accepted
{
"success": true,
"order_id": "ord_9b1e0c4d2a7f4e8b9c3d5a6f7e8d9c0b",
"status": "QUEUED",
"test": false
}
What happens to the lead
- It becomes a normal order and goes through the same checks as
POST /v1/orders: published agent, US number, wallet, do-not-contact list, calling hours. - The cadence is the agent's follow-up plan, set in the app on the agent's Follow-up tab: 1 to 3 attempts, the wait between them, and the fallback text on or off. Until you change it, that is up to 3 attempts, 120 minutes apart, with the fallback text on. A test lead (
?test=1) is always one attempt with no text. - Its consent record is
{ "opt_in_confirmed": true, "consented_at": <the lead's time or receipt time>, "source": "inbound_hook:<token>", "attestation": { "user_id", "attested_at", "text" } }. - The result goes to your workspace's default webhook URL, if one is set. You cannot set a webhook URL or
external_reference_idper lead here; use the Orders API for that.
Duplicates and rate limit
- Zapier, Make and Facebook sometimes send the same lead twice. The same payload sent to the same URL within 24 hours returns the first order (with the header
Idempotent-Replayed: true) and does not call again. Key order in the JSON does not matter. - Each trigger URL accepts at most 60 leads per minute. Above that you get
429 rate_limitedwithRetry-After: 60.
Send a test lead
Add ?test=1 to the URL to send a test lead to your own phone:
POST https://api.avoonta.com/v1/hooks/lead/hk_…?test=1
- The phone must be a number your workspace confirmed with a one-time code in the last 90 days. Otherwise:
403 test_number_not_verified. - One attempt, no fallback text, never deduplicated (pressing twice rings twice).
- It is a real call and is charged like one.
- A test lead never sends a webhook to your default webhook URL, so it cannot pollute your CRM.
- The response has
"test": true.
Using it from your tools
Zapier
- Trigger: your lead source (Facebook Lead Ads, a form, a CRM).
- Action: Webhooks by Zapier → POST.
- URL: your trigger URL. Payload type:
json(orform). - Data: map at least
phone, and ideallyfirst_name,emailand the lead's submission time asconsented_at.
Make
- Add an HTTP → Make a request module after your trigger.
- Method
POST, URL: your trigger URL, body typeRaw, content typeJSON (application/json). - Body: a JSON object with
phone,first_name,consented_atand anything else useful.
GoHighLevel, Typeform and other tools
Use the tool's "webhook" or "custom webhook" action with method POST and your trigger URL. Most send JSON; the field names are matched as shown above.
Your own website form
Do not put the trigger URL in the HTML of a public page. Anyone who reads the page source could then send leads that we would call at your cost. Post the form to your own server, or to Zapier or Make, and forward it from there.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | Unknown URL, or the URL or its agent is switched off. |
| 405 | method_not_allowed | Use POST. |
| 400 | invalid_body | Not JSON or form fields, or bigger than 64 KB. |
| 400 | invalid_request | No phone number was found in the lead. |
| 403 | test_number_not_verified | ?test=1 to a number you have not confirmed. |
| 429 | rate_limited | More than 60 leads in a minute. Wait 60 seconds. |
| 503 | unavailable | A short problem on our side. Retry. |
The order checks can also return agent_not_published, invalid_phone, unsupported_destination, high_cost_destination, insufficient_balance, do_not_contact and the 503 codes. See Errors.