Ingesting Leads
POST /v1/leads:ingest is the one call for pushing people in from anywhere: your landing pages, form tools, ad platforms, Zapier, a WhatsApp bot. It runs the same path as an inquiry on your letsrealty website — deduplication, the Inquiry, the Lead Owner, the team notification and AI scoring — and adds your attribution.
It needs leads:ingest (or leads:write) and has its own rate budget of 60 per minute.
The request
{
"source": "Facebook Lead Ads",
"campaign": "Escazú launch",
"type": "inquiry",
"person": {
"name": "Ana Rojas",
"email": "ana@example.com",
"phone": "8888 1234"
},
"property_ref": "CASA-ESC-12",
"agent_email": "maria@agency.example",
"message": "Is it still available?",
"occurred_at": "2026-09-30T14:05:00Z"
}
source(required) andcampaign— free text that says where the Lead came from. The first ones are kept on the Lead assource_detailandcampaign; each Inquiry keeps its own.type(required) —inquiry(a question, the usual case),registration(signed up without a question) ornote(a message to log on the Lead;messageis required and it is recorded as a note Activity).person.name(required) and at least one ofperson.email/person.phone. Phones are read with your agency's default country, so local numbers work.- The Property —
property_id, orproperty_ref: your listing's slug or your own internal reference. Give one or neither. - The Agent —
agent_id, oragent_email. Give one or neither. occurred_at— when it really happened; defaults to now. See backfills below.
Send an Idempotency-Key header so a retry after a timeout never records the Inquiry twice — see Rate limits & idempotency.
The answer
201 when a new Lead was created, 200 when the person matched an existing Lead:
{
"lead": { "id": "6f1c…", "name": "Ana Rojas", "source": "api", "…": "…" },
"inquiry_id": "0b9e…",
"activity_id": null,
"warnings": [
{ "code": "property_ref_unmatched", "detail": "property_ref names no Property" }
]
}
A Lead created by ingestion has source api (or import for a backfill). inquiry_id is set for an inquiry or registration, activity_id for a note.
Matching people
letsrealty matches on email first, then phone. When the email matches one Lead and the phone another, the email wins and the two are flagged as possible duplicates for your team; nothing is ever merged automatically. A phone match can fill in a missing email, but never overwrites one.
Warnings, not errors
A reference that can't be resolved never loses the Lead. The Inquiry is recorded without it and the answer lists a warning:
property_ref_unmatched— no listing has that slug or reference.property_ref_ambiguous— more than one does; none is linked.property_not_found— no listing has thatproperty_id.agent_unmatched— no active Agent has that email; the usual owner rules apply.
Check warnings[] in your logs and fix your mapping; the call itself succeeded.
Backfills with occurred_at
To bring in history from another system, send each record with its original occurred_at. Anything more than 24 hours old is recorded at that time quietly: no notification, no AI scoring and no change of Lead Owner. Fresh records (within 24 hours) behave like a live inquiry. A Lead first created by a backfill has source import.
There is no batch call. At 60 per minute, 5,000 records take under 90 minutes; pace your loop on the RateLimit header and retry 429s after Retry-After. Use the record's id in your old system as the Idempotency-Key, so a restarted import never duplicates.