Create a form endpoint, post your own website form to it with a few lines of script, map the fields to contact fields and go live — with allowed origins, rate limits and reCAPTCHA covered.
A form endpoint turns a form you already have on your website into a lead source. You create the endpoint, add a short script to your page that posts the form's fields to it, send one test, map the fields, and submissions start creating and updating contacts.
crm:forms:manage in Karmaflow.ai — tenant administrators have it; it puts Create Form Endpoint on the Forms page.<script> to the page that holds your form (or to your site builder's custom-code slot).https://www.example.com), comma-separated. Leave * while you test; narrow it before you go live.On the edit page, the Integration Guide card has three tabs — JavaScript, HTML Form and cURL — with your endpoint URL already filled in. The HTML Form tab is the usual starting point:
<form id="contactForm">
<input type="email" name="email" required>
<input type="text" name="name">
<textarea name="message"></textarea>
<button type="submit">Submit</button>
</form>
<script>
document.getElementById('contactForm')
.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
const response = await fetch('https://omni.karmaflow.ai/api/forms/<your-workspace>/<form>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'YOUR_API_KEY'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) alert('Submitted!');
});
</script>
Keep your own fields and styling; what matters is that the page sends the fields as JSON (or URL-encoded) to the endpoint URL with the X-API-Key header. Field names are yours to choose — you map them in the next step.
Three things to know before you paste:
<form action="…"> will not work. The API key travels in a request header, which a browser's native form post cannot send, so the endpoint answers 401. The script is required.Submit your form once from the page (or run the cURL tab's command). Until fields are mapped the endpoint treats every submission as a test: it records the field names and values and creates no contact. The response says so:
{ "success": true, "isTest": true,
"message": "Test submission received. Please configure field mappings in the admin panel." }
Back on the edit page, Detected Fields switches from Awaiting First Submission to N fields detected and lists each field with the value you sent. Wrong field set? Clear & Re-detect and submit again. On the Forms list the endpoint's status moves from Awaiting Test to Needs Mapping.
In Field Mapping, choose a destination for each detected field:
| Choose | To |
|---|---|
| -- Skip this field -- | Keep the value in the submission record but write it nowhere on the contact |
| Full Name → First Name + Last Name | Split one name field into the two contact fields |
| A standard field — First Name, Last Name, Email, Phone, Company, LinkedIn ID, Years Experience | Write it to that contact field (phone numbers are normalised with your workspace's default country) |
| Notes (adds as a note) | Add the value as a note on the contact, prefixed with the form's name |
| A custom field | Write it to one of your contact custom fields |
| + Create New Custom Field | Make a new custom field for it, right here |
One field must map to Email — Save Field Mappings refuses otherwise, because email is how a submission finds its contact.
Click Save Field Mappings. The endpoint is now Active, and the next submission is live. Remap clears the map if you need to start over.
Back in Form Details on the edit page:
* in Allowed Origins (CORS) with your site's origin(s). A post from any other origin is refused with 403 Origin not allowed.429 with a Retry-After header.For bot protection, open the reCAPTCHA v3 card, tick Enable reCAPTCHA v3, paste your reCAPTCHA secret key, set the Score Threshold (Google suggests 0.5; higher is stricter) and Save reCAPTCHA Settings. Your page must then include the token Google issues as a captchaToken field (and the action name as captchaAction); a missing token is refused with 400, a failing score with 403.
AI spam scoring is on for every endpoint by default: each live submission is scored against the last ten, and anything over the threshold is stored as Spam and creates no contact — while the response still reads as a success, so a bot cannot tell.
data-kf-attribution), the visitor's click id, campaign tags and GA4 session are lifted off the submission onto the contact, and a generate_lead event is sent when the GA4 integration is on.CRM → Setup → Forms → the eye icon (or View Submissions) opens Form Submissions for the endpoint. Filter by status — All · Test · Received · Processed · Failed · Spam — and click View on a row for Submission Details: when it arrived, its status and CRM Outcome (created contact, updated contact, skipped — internal domain), the IP, user agent and referring page, the spam score, the Submitted Data as sent, the Mapped Contact Data as written, and an Open link to the contact.
The same submission is reachable from the contact's timeline row.
Open the Email Intake card and click Enable Email Intake. The endpoint gets its own address, form-<name>.<id>@sys.karmaflow.ai. Mail sent or forwarded there is read by AI, the fields are extracted according to your field map and the result is processed as a normal submission. AI Processing Instructions lets you give hints ("the subject line holds the person's name"). Use it when a partner or an older system emails you leads instead of posting them.
401 API key required or Invalid API key. The header is missing or the key is wrong. Check the header is literally X-API-Key, and that the key is the one shown at creation (or after the last Regenerate API Key). A native form post without script always lands here.
403 Origin not allowed. The page's origin is not in Allowed Origins (CORS). Add the exact origin including scheme and any www..
429 Rate limit exceeded. More than Rate Limit (per minute) submissions in a minute. Raise it on the edit page, or wait for Retry-After.
The status stays "Awaiting Test". No submission has reached the endpoint yet. Run the cURL tab's command to prove the endpoint works, then look at your page's network tab.
Submissions arrive but no contact is created. Open the submission: a Test status means the fields are not mapped yet (Step 4); Spam means the AI score crossed the threshold; skipped — internal domain means the submitter's domain is one of yours.
My workflow runs for other forms. Open the orchestration and check the trigger's Form Endpoint select names this form. A trigger with no form selected runs for every endpoint.