Lead capture from your own website

Put a form on the website you already have, and have it post straight into your CRESUPER instance. There is nothing to install and no code of ours running on your site - your form talks to your instance's public lead API, and the lead lands in your pipeline.

1. The three endpoints

Replace <your-slug> with your instance's slug.

POST https://<your-slug>.cresuper88.com/api/public/leads/buy
POST https://<your-slug>.cresuper88.com/api/public/leads/sell
POST https://<your-slug>.cresuper88.com/api/public/contact

Use /api/public/leads/buy for buyer and tenant inquiries, /api/public/leads/sell for owners who want to sell or lease out a property, and /api/public/contact for a general "get in touch" form.

2. The fields

All three

FieldRule
contact_nameRequired, non-empty, 200 characters or fewer.
company_websiteThe honeypot. See section 4 - leave it in.

/api/public/leads/buy

FieldRule
contact_phoneRequired. Normalized to exactly 10 US digits: punctuation is stripped and a leading country-code 1 is dropped, so (505) 555-0134 and +1 505 555 0134 are both fine. Anything that does not reduce to 10 digits is rejected.
contact_emailOptional, but shape-checked when present.
notesOptional, 5000 characters or fewer.
budgetOptional, 50 characters or fewer.
timelineOptional, 100 characters or fewer.
property_types[], areas[]Optional arrays, at most 20 elements each, each element 80 characters or fewer.

/api/public/leads/sell

FieldRule
contact_phoneRequired, same 10 US digits rule as buy.
addressRequired - the property being sold or leased out. 300 characters or fewer.
contact_emailOptional, shape-checked when present.
notesOptional, 5000 characters or fewer.
sizeOptional, 50 characters or fewer.
timelineOptional, 100 characters or fewer.
reasonOptional, 500 characters or fewer.

/api/public/contact

FieldRule
contact_emailRequired here, and it must be a valid address. This is the one endpoint where the email is required and the phone is not.
messageOptional, 5000 characters or fewer.

3. What comes back

CaseStatusBody
Success200{"ok":true} - buy additionally returns a chat_url you may show the visitor.
Validation failure400{"error":"Please check the form and try again."}
Contact, bad or missing email400{"error":"Please enter a valid email."}

Branch on the status code, and show the error string as-is: it is written for the visitor, not for you.

4. The honeypot, and why you must not remove it

Include a hidden input named company_website in your form, positioned off-screen or with display: none, with tabindex="-1" and autocomplete="off" so a real visitor can never focus it.

If that field arrives with any value, the request is accepted and silently dropped: you get 200 with {"ok":true} and no lead is written. That is deliberate - telling a bot it failed teaches it to try again. Two consequences for your developer: do not "fix" the field away because it looks pointless, and do not treat a 200 as a delivery receipt. If you need certainty that a lead landed, look in the CRM.

5. Snippet A - server-side relay (recommended)

Your own backend receives the form the ordinary way and posts JSON onward. No CORS is involved, because the request comes from your server rather than from a browser. This is the only shape that works from a marketing site on a different hostname.

// your site's own handler, any framework
const r = await fetch('https://<your-slug>.cresuper88.com/api/public/leads/buy', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    contact_name: form.name,
    contact_phone: form.phone,
    contact_email: form.email,
    notes: form.message,
    company_website: form.company_website,   // pass the honeypot through untouched
  }),
});
const out = await r.json();
// r.ok -> out.ok === true ; otherwise show out.error to the visitor

6. Snippet B - browser fetch, same origin only

If the page is served from the instance's own origin (https://<your-slug>.cresuper88.com), the browser can post directly:

const res = await fetch('/api/public/leads/sell', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    contact_name: name.value,
    contact_phone: phone.value,
    address: address.value,
    company_website: hp.value,
  }),
});
const out = await res.json();

CORS: in production your instance allows exactly one browser origin - its own public URL. A fetch() from any other origin, including your marketing site, is refused at the preflight and never reaches the API. That is why snippet A exists.

7. The constraint that catches everyone

The API parses JSON only. Your instance mounts a JSON body parser and no urlencoded parser at all, so a plain <form method="post"> - which sends application/x-www-form-urlencoded - arrives with an unparsed body and fails validation on fields you did send. Always send a JSON body with Content-Type: application/json, from your server (snippet A) or from a same-origin page (snippet B).

Your instance is the authority on all of the above. If a limit here and your instance disagree, your instance is right - tell us and we will fix this page.