Overview
If a prospective renter fills out a form on a building's website, you POST the form data to this endpoint. SeeClickRent will:
- Create or look up the customer record (by email, then phone).
- Create a new lead and attach it to the right building (using the
tokenyou send). - Notify the assigned leasing agent by email.
The response gives you back the new lead ID. There are no read endpoints — this API is write-only.
Authentication
There is no API key or bearer token. Each building has its own opaque token string, and you include it in the request body to associate the lead with that building.
- A SeeClickRent admin issues the token to you when your integration is set up.
- Treat the token like a shared secret — anyone with the token can post leads for that building.
- One token = one building. If you integrate multiple buildings, you'll receive one token per building.
If you're integrating a SeeClickRent-managed building website, the token is typically already embedded in the page by the time the form posts.
CORS
The endpoint accepts cross-origin browser requests from:
- The SeeClickRent domain itself.
- Any building's registered
websiteURL (configured in SeeClickRent).
If you call the endpoint directly from a browser on a domain that hasn't been registered for any building, the request will be blocked by CORS. The allowlist is cached for up to 5 minutes after a building's website is added or changed.
If you call from a server (cURL, Python, Node backend, etc.), CORS does not apply.
Rate limits
- 300 requests per 5 minutes per source IP across the entire
/api/*namespace. - Excess requests get an HTTP
429 Too Many Requestswith aRetry-Afterheader (in seconds) and this body:
{
"error": {
"message": "throttled",
"human_message": "Too many requests. Please try again later."
}
}
If you anticipate higher volume from a single IP, contact SeeClickRent before going live.
Request
Headers
Content-Type: application/json
Accept: application/json
Body
All lead fields go inside a tour_request object. The building token (and a couple of optional building-lookup alternatives) live at the top level alongside it.
{
"token": "abc123def456",
"tour_request": {
"requestor_name": "Jane Smith",
"requestor_email": "jane@example.com",
"requestor_phone": "+15551234567",
"message": "Interested in 2-bedroom units, ideally for May 1st move-in.",
"slot": "2026-05-15T14:00:00Z",
"unit_preference": "2A",
"utm_data": "utm_source=google&utm_medium=cpc&utm_campaign=spring2026",
"listing_source": "nooklyn",
"listing_source_original_id": "12345",
"request_host": "https://example-building.com",
"sms_consent": "true"
}
}
Field reference
Top-level fields (used to identify the building)
| Field | Type | Required | Description |
|---|---|---|---|
token |
string | Recommended | Building token issued by SeeClickRent. The preferred way to attach the lead to a building. |
unified_address_id |
string | Optional | Fallback building lookup by SeeClickRent's unified address ID. Only used if token is absent. |
address_line_one |
string | Optional | Fallback building lookup by exact street address (e.g. "619 Throop Ave"). Only used if both token and unified_address_id are absent. |
The endpoint tries them in order: token → unified_address_id → address_line_one. If none match a known building, the lead is still created but will be unassigned (no agent will be notified). Always send token if you have it.
tour_request fields
| Field | Type | Required | Description |
|---|---|---|---|
requestor_email |
string | Required | Renter's email. Used to find or create the customer record. |
requestor_name |
string | Optional | Full name. Stored on the customer if it's a new contact. |
requestor_phone |
string | Optional | Phone number in any reasonable format. Used as a fallback to match an existing customer if email isn't recognized. |
message |
string (text) | Optional | Free-form message from the renter. |
slot |
string (ISO 8601 datetime) | Optional | Preferred tour time, e.g. "2026-05-15T14:00:00Z". |
unit_preference |
string | Optional | Specific unit the renter is interested in, e.g. "2A". If present, the lead is treated as a listing-level lead; otherwise as a building-level lead. |
utm_data |
string | Optional | UTM tracking parameters as a query-string fragment. See UTM tracking. |
listing_source |
string | Optional | Where the listing originated. Allowed values: june_homes, streeteasy, nooklyn, zillow. |
listing_source_original_id |
string | Optional | The listing's ID on the source platform (e.g. the StreetEasy listing ID). |
request_host |
string | Optional | Origin URL of the page that submitted the form. If you don't send it, the server uses the HTTP Host header. |
sms_consent |
string | Optional | Send "true" (the literal string) to record explicit SMS consent. See SMS consent. |
Server-managed fields (do not send)
These are set automatically and cannot be overridden:
lead_sourceis always set towebsitefor this endpoint.property_typeis set tolistingifunit_preferenceis provided, otherwisebuilding.
UTM tracking
Pass utm_data as a single URL-query-style string. The server splits and stores it as a JSON object on the lead.
Input
"utm_data": "utm_source=google&utm_medium=cpc&utm_campaign=spring2026"
Stored as
{
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "spring2026"
}
A leading ? is tolerated and stripped. Send null or omit the field if you have no UTM data.
SMS consent
If a renter explicitly opts in to SMS communication on your form, set:
"tour_request": {
"requestor_phone": "+15551234567",
"sms_consent": "true"
}
sms_consentmust be the exact string"true". Booleans,1, etc. are ignored.- Consent is only recorded if
requestor_phoneis also present. - The consent source is logged as the
Hostheader of the request, so it's visible to compliance reviewers later. - Without
sms_consent, the customer is treated as not having opted in to SMS.
Responses
201 Created — success
{
"id": 12345
}
id is the SeeClickRent lead ID. Persist it if you want to correlate later support requests, but you cannot read the lead back through this API.
400 Bad Request — validation or unexpected error
{
"error": "Unable to create tour request"
}
Or, if a server-side exception was raised (bad payload shape, unparseable datetime, etc.), the exception message is returned:
{
"error": "param is missing or the value is empty: tour_request"
}
Common causes:
- Missing
tour_requestwrapper object. - Missing
tour_request.requestor_email. - Malformed JSON.
429 Too Many Requests — throttled
See Rate limits.
Other status codes
Anything in the 5xx range indicates a SeeClickRent-side problem. Retry with exponential backoff. The endpoint is not idempotent (see below), so guard against double-creating leads when retrying.
What happens after a successful call
You don't need to do anything else, but for context:
- The customer record is created or matched (by email first, then phone).
- A new lead is created and linked to the building identified by
token. - A deal is created from the lead and moved to its initial pipeline stage.
-
The assigned leasing agent receives a notification email. Notification is silently skipped if:
- the customer has been flagged as spam, or
- the building has no agent email configured.
- If
listing_sourceisjune_homes, the lead is also synced back to June Homes via a background job.
Idempotency
This endpoint is not idempotent — every call creates a new lead, even if you send the exact same payload twice. If your form can be submitted multiple times by the same renter (double-clicks, form retries, etc.), de-duplicate on your side before posting.
Code samples
curl -X POST https://seeclickrent.com/api/v1/website_leads \
-H "Content-Type: application/json" \
-d '{
"token": "abc123def456",
"tour_request": {
"requestor_name": "Jane Smith",
"requestor_email": "jane@example.com",
"requestor_phone": "+15551234567",
"message": "Interested in 2-bedroom units",
"slot": "2026-05-15T14:00:00Z",
"unit_preference": "2A",
"utm_data": "utm_source=google&utm_campaign=spring2026",
"sms_consent": "true"
}
}'
const response = await fetch("https://seeclickrent.com/api/v1/website_leads", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: "abc123def456",
tour_request: {
requestor_name: "Jane Smith",
requestor_email: "jane@example.com",
requestor_phone: "+15551234567",
message: "Interested in 2-bedroom units",
slot: "2026-05-15T14:00:00Z",
unit_preference: "2A",
utm_data: window.location.search.replace(/^\?/, ""),
sms_consent: "true",
},
}),
});
if (response.status === 201) {
const { id } = await response.json();
console.log("Created lead", id);
} else {
const { error } = await response.json();
console.error("Lead creation failed:", error);
}
import requests
resp = requests.post(
"https://seeclickrent.com/api/v1/website_leads",
json={
"token": "abc123def456",
"tour_request": {
"requestor_name": "Jane Smith",
"requestor_email": "jane@example.com",
"requestor_phone": "+15551234567",
"message": "Interested in 2-bedroom units",
"slot": "2026-05-15T14:00:00Z",
"unit_preference": "2A",
"utm_data": "utm_source=google&utm_campaign=spring2026",
"sms_consent": "true",
},
},
timeout=10,
)
if resp.status_code == 201:
lead_id = resp.json()["id"]
print(f"Created lead {lead_id}")
elif resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", "60"))
print(f"Throttled, retry in {retry_after}s")
else:
print(f"Failed: {resp.status_code} {resp.text}")
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
400 with "param is missing or the value is empty: tour_request" |
You posted lead fields at the top level instead of nested under tour_request. |
Wrap all lead fields inside a tour_request object. |
400 with "Unable to create tour request" |
Validation failure (typically missing email). | Ensure tour_request.requestor_email is present and well-formed. |
201 returned but no agent email arrives |
The building has no agent configured, or the customer is flagged as spam. | Verify the building's agent email with SeeClickRent. Spam flags are intentionally silent. |
| Lead created but not linked to the right building | The token was missing, mistyped, or one of the address fallbacks matched the wrong building. |
Always send the token for the specific building. |
| Browser request blocked by CORS | The page's origin isn't on the SeeClickRent allowlist. | Register the building's website URL in SeeClickRent, or call the endpoint server-side instead. |
429 Too Many Requests |
Hit the 300-per-5-minute IP throttle. | Honor the Retry-After header. Spread bursts over time, or contact SeeClickRent for a higher limit. |
5xx errors |
Transient server-side issue. | Retry with exponential backoff. Remember the endpoint isn't idempotent — de-duplicate before retrying. |
Support
For tokens, building setup, or rate-limit increases, reach out to your SeeClickRent point of contact or contact us.