Mark

Capture leads and subscribers

The request and response contract for POST /leads and POST /subscribe, the two endpoints a tenant's site form posts to.

Mark records a lead or a newsletter signup through two public endpoints: POST /leads and POST /subscribe. Your site keeps its own form, design, and copy — these endpoints are the contract your form's submit handler posts to.

Both endpoints live on the API host (for example https://api.mark.lifewithdata.org) and take a JSON body over HTTPS. Life With Data gives you the key value below; it identifies your workspace and is safe to include in client-side code.

Before you integrate

  • Your public form key. Every request body includes key, the value Life With Data gave you for your workspace.
  • Your site's domain on the allowlist. Requests from a browser must come from an origin Life With Data has added to your workspace. An origin that isn't allowed gets refused.
  • A consent checkbox. Both endpoints require an explicit consent acknowledgment before they record anything.

POST /leads

Call this when a visitor submits your lead form.

POST /leads
Content-Type: application/json
FieldTypeRequiredNotes
keystringYesYour public form key.
emailstringYesThe visitor's email.
consenttrueYesMust be exactly true.
consentVersionstringYesThe version of the consent text you showed.
pageUrlstringYesThe page the form was on, including any utm_* query parameters.
renderedAtnumberYesUnix time in milliseconds when the form first rendered. Used to reject a submit that happens too fast to be human.
namestringNo
phonestringNo
messagestringNoThe visitor's message.
personaIdstringNoAn id from your Mark workspace, if your form asks which persona the visitor matches.
answersobjectNoAny other named field on your form: a flat object of strings, numbers, or booleans, up to 40 keys.
referrerstringNodocument.referrer at submit time.
distinctIdstringNoYour analytics visitor id, if you have one.
fbclid, gclidstringNoAd click ids from the page URL.
honeypotstringNoLeave any hidden honeypot input empty; a filled value marks the submission as a bot.

A successful submission returns:

{ "leadId": "..." }

Show your own thank-you message — Mark doesn't redirect anywhere. If the same email submits again while their lead is still new, Mark attaches the new message to that same lead instead of creating a second one.

POST /subscribe

Call this for a newsletter or marketing-only signup, where you don't want a sales lead created. It takes the same fields as POST /leads except phone, message, personaId, and answers, and returns:

{ "contactId": "..." }

Responses

StatusMeaning
201Recorded. The body has leadId or contactId.
200 with an empty bodyThe submission looked automated (a filled honeypot or an impossibly fast submit) and nothing was recorded.
400The body is missing a required field, consent isn't true, or answers doesn't fit the shape above.
403The request's origin isn't on your workspace's allowlist.
404The key doesn't match a workspace.
429Too many requests from the same address; try again shortly.

Example

curl -X POST https://api.mark.lifewithdata.org/leads \
  -H "Content-Type: application/json" \
  -d '{
    "key": "your-public-form-key",
    "email": "visitor@example.com",
    "message": "Interested in a quote",
    "consent": true,
    "consentVersion": "1.0",
    "pageUrl": "https://your-site.com/contact?utm_source=instagram",
    "renderedAt": 1735000000000
  }'

On this page