From your website to your inbox.
Keep your frontend and your design. Add a little Contact and start collecting submissions in a few minutes.
1. Create a workspace and a form
Create a workspace, then choose New form in your dashboard. Give the form a name and enter the exact origins allowed to submit it, such as https://example.com or http://localhost:3000. An origin is the scheme and host, plus the port when it is not the default, and it never includes a path.
The starter schema accepts a name, email, and message. You can customize the field schema when you create or edit the form. See Field types and schema for the full reference.
2. Copy your endpoint and public key
After saving, your form shows a public key and a submission endpoint. The public key is designed to live in browser code — it identifies the form, not a user. Never place an administrator key or integration secret in frontend code.
| Value | Example |
|---|---|
| Submission endpoint | https://contact.kirandhakal.me/v1/forms/YOUR_PUBLIC_KEY/submissions |
| Method | POST with a JSON body |
| Required header | Idempotency-Key (one per submission) |
3. Send a submission
Send JSON from an allowed website origin. A native HTML form POST is not supported, so submit with JavaScript or from your own server. Pick the tab that matches your stack.
<form id="contact">
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required></textarea>
<input type="text" name="_website" tabindex="-1" autocomplete="off" hidden aria-hidden="true" />
<button type="submit">Send</button>
</form>
<p id="status" role="status"></p>
<script>
const form = document.getElementById("contact");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const status = document.getElementById("status");
status.textContent = "Sending…";
const response = await fetch("https://contact.kirandhakal.me/v1/forms/YOUR_PUBLIC_KEY/submissions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify(Object.fromEntries(new FormData(form)))
});
const result = await response.json();
status.textContent = response.ok ? result.message : (result.detail || "Something went wrong.");
if (response.ok) form.reset();
});
</script>Create one Idempotency-Key per submission and reuse the same value if you retry that exact submission. Keys prevent duplicate messages when a network hiccup makes you send twice.
4. Confirm it works
- Open your form’s inbox in the dashboard. The new submission should appear immediately.
- Check the delivery status of any automatic rules on the submission.
- Test from your production origin to confirm the allowlist is correct.
Where to go next
- Embedding — full examples for HTML, React, and Next.js.
- Field types and schema — validate and shape your data.
- File uploads — accept attachments safely.
- Spam protection and limits — honeypot, origins, and rate limits.