Sending Leads In
Push leads into ABC Sales AI from your own systems (forms, CRMs, landing pages) with the lead intake endpoint:
POST /v1/webhooks/leads
This is the inbound path: you send leads to ABC Sales AI. It is different from Webhooks, which is the outbound path where ABC Sales AI notifies your system about events.
custom_fields, automations, and tags all reference things configured on your company account. Use the Discovery endpoints to list valid custom-field keys, automation slugs, and existing tags before you build your payload.
Request
curl -X POST "https://api.abcsalesbot.com/v1/webhooks/leads" \
-H "Authorization: Bearer $ABC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+60123456789",
"id": "your-external-id-123",
"source": "landing-page",
"tags": ["pricing-page"],
"timezone": "Asia/Kuala_Lumpur",
"locale": "en",
"currency": "MYR",
"custom_fields": { "plan_interest": "scale" }
}'
Fields
| Field | Required | Notes |
|---|---|---|
name | Yes | 2 to 100 characters. |
email | No | |
phone | No | Up to 50 characters. Unparseable numbers are kept raw and tagged for review rather than rejected. |
id | No | Your external lead ID (up to 50 chars). Used as the upsert key, so resending the same id updates the existing lead instead of creating a duplicate. |
naver_line_id | No | LINE user ID, used as a lookup/upsert identifier for LINE-channel leads. Takes precedence over phone when both are supplied. |
source | No | Free-text source label. |
tags | No | Array of strings. Free-text: an unknown tag is created on the fly. List existing ones with Discovery. |
timezone, locale, currency | No | |
custom_fields | No | Object keyed by the json_key of a custom field configured on your account. See below. |
automations | No | subscribe / unsubscribe / replace, each an array of automation slug_ids. replace cannot be combined with the other two. |
user_assignments | No | assign / unassign / replace. replace cannot be combined with the other two. See the API Reference. |
Custom fields
Every key must match a json_key from GET /v1/custom-fields, and its value must match that field's declared type. An unknown key, or a value of the wrong type, returns 400 and rejects the whole lead, so nothing is partially saved. A key with a null value is skipped rather than rejected.
For a custom field of type file, the value is the s3_path of a file you uploaded first. See Attachments.
Automations
Automation slug_ids that don't exist are silently ignored: the request still returns 202 and the lead is still created, just without the subscription. Nothing surfaces the mismatch, so verify slugs against GET /v1/automations rather than relying on the response.
The same applies to user_assignments: user IDs that don't resolve to a user in your company are dropped rather than failing the request, so one bad ID can't lose an otherwise valid lead.
Response
The endpoint processes leads asynchronously and returns 202 Accepted once the payload is queued (it may return 200/201 when processed synchronously). The lead is created or updated out of band.
Because id is an upsert key, sending the same external id again is safe and idempotent.
Rate limit
This endpoint is rate limited to 300 requests per minute per company. On exceed it returns 429 with a Retry-After header. See Rate Limits.