When you build your own website frontend, you don't need to integrate a third-party form service just to create a "Contact Us" or "Consultation Request" form. You can create forms directly in the dashboard under "Marketing › Online Forms" and then fetch fields and submit responses from your custom frontend via the Content Delivery API.
Once a form is submitted, Kanorio automatically handles bot protection, spam filtering, creating or merging contacts, sending confirmation emails to submitters, and notifying your team, while triggering the customers.form.submitted webhook.
Full Endpoint and Error Code Specifications (SSOT): For parameter details, field structures, and error codes for the three form endpoints, please refer to the Content Delivery API Reference (Forms Group).
formId in the URL or under "Data & Records › Data Tables".https://www.example.com) to "Allowed Origins" (localhost is allowed by default for local development, no setup required).GET /api/v1/forms/{id})Fetch the form title, fields, privacy and marketing consent settings, and current availability status when the page loads or builds:
availability.accepting is false (e.g., the form is archived or past its deadline), your frontend can display a closed message instead of rendering input fields.field.id matches the configuration in the dashboard.GET /api/v1/forms/{id}/challenge)To block automated spam bots without requiring visitors to solve tedious CAPTCHAs, Kanorio uses a lightweight Proof-of-Work challenge:
GET /api/v1/forms/{id}/challenge from the browser (this endpoint is no-store and returns a fresh challenge every time).solution string (or use the helper function included in @kanorio/sdk) and include it with your submission.POST /api/v1/forms/{id}/submit)POST the visitor's answers (an object keyed by field id), the anti-spam solution, and the marketing consent status to /api/v1/forms/{id}/submit:
async function submitContactForm(siteUrl: string, formId: string, answers: Record<string, unknown>) { // 1. Get anti-spam challenge and compute solution const challengeRes = await fetch(`${siteUrl}/api/v1/forms/${formId}/challenge`, { cache: "no-store", }); const challenge = await challengeRes.json(); const token = await solveFormChallenge(challenge); // 2. Submit form answers const res = await fetch(`${siteUrl}/api/v1/forms/${formId}/submit`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ answers, challengeToken: token, marketingConsent: true, pagePath: window.location.pathname, }), }); if (!res.ok) { const { error } = await res.json(); throw new Error(error?.message ?? "Submission failed"); } return res.json(); }
Once /submit returns 200 OK, Kanorio automatically executes the following in the background:
customers.form.submitted event, the system will immediately push the answers to your external system or automation workflow.Yes. If you proxy via your server, please preserve the visitor's original source information or complete the challenge and submission directly in the browser to ensure that per-site/per-IP rate limiting accurately protects your form quotas.