How it works
Traditional contact forms require a backend Node.js server, AWS Lambda function, or PHP script just to forward inquiries to your email.
With SadaSend Contact Forms, you submit directly to our API endpoint. Submissions are screened through our invisible honeypot shield and disposable domain blocker, forwarded to your inbox, and logged in your dashboard inbox with instant CSV export.
- Zero backend code required — works with plain HTML <form>, modern JS frameworks, or no-code site builders.
- Public Access Key (sada_form_...) safe to include in client-side code.
- Automatic Reply-To header set to visitor email for 1-click direct email replies.
- Invisible honeypot bot shield (botcheck) stops spam without frustrating visual CAPTCHAs.
- Automated customer confirmation auto-responder delivers instant branded receipts.
Standard endpoint & parameter reference
Endpoint URL: POST https://api.sadasend.com/forms/submit
Accepts standard application/x-www-form-urlencoded, multipart/form-data, or application/json.
| Parameter | Type | Required | Description |
|---|---|---|---|
| access_key | string | Yes | Your unique public form endpoint key from /app/forms. |
| name | string | Recommended | Visitor name. Used in notifications and {{name}} template variables. |
| string | Recommended | Visitor email. Automatically set as the Reply-To address. | |
| subject | string | Optional | Custom email subject line for the incoming lead notification. |
| redirect | string | Optional | Redirect URL after submission (for static HTML forms). |
| botcheck | string | Optional | Invisible honeypot field. Keep hidden and empty; if filled, bot is trapped. |
| [custom] | string | Optional | Any custom fields (e.g. phone, company, message) are captured automatically. |
Plain HTML embed snippet
Paste this snippet into any static website or landing page template:
<form action="https://api.sadasend.com/forms/submit" method="POST">
<!-- Required SadaSend Access Key -->
<input type="hidden" name="access_key" value="sada_form_your_key_here" />
<input type="hidden" name="redirect" value="https://yoursite.com/thank-you" />
<!-- Invisible Honeypot Spam Shield (Keep Hidden) -->
<input type="checkbox" name="botcheck" class="hidden" style="display: none;" />
<!-- Visitor Inputs -->
<input type="text" name="name" required placeholder="Your Name" />
<input type="email" name="email" required placeholder="you@company.com" />
<textarea name="message" required placeholder="How can we help?"></textarea>
<button type="submit">Send Message</button>
</form>Vanilla JavaScript (Fetch API with FormData)
For single-page applications or static templates requiring inline success feedback without page redirects:
const form = document.getElementById('contact-form');
const submitBtn = document.getElementById('submit-btn');
const result = document.getElementById('result');
form.addEventListener('submit', async (e) => {
e.preventDefault();
submitBtn.disabled = true;
submitBtn.textContent = 'Sending...';
result.textContent = '';
const formData = new FormData(form);
formData.append('access_key', 'sada_form_your_key_here');
try {
const response = await fetch('https://api.sadasend.com/forms/submit', {
method: 'POST',
headers: { Accept: 'application/json' },
body: formData,
});
const data = await response.json();
if (response.ok && data.success) {
result.textContent = 'Thank you! Your message has been sent.';
form.reset();
} else {
result.textContent = 'Error: ' + (data.message || 'Submission failed');
}
} catch (error) {
result.textContent = 'Network error. Please try again.';
} finally {
submitBtn.disabled = false;
submitBtn.textContent = 'Send Message';
}
});React & Next.js integration
Integrates cleanly with React 18/19 and Next.js (App Router or Pages Router). Works as a Client Component ("use client") with no backend API route required:
'use client';
import React, { useState } from 'react';
export function ContactForm() {
const [status, setStatus] = useState<'idle' | 'sending' | 'success' | 'error'>('idle');
const [errorMessage, setErrorMessage] = useState('');
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setStatus('sending');
const form = e.currentTarget;
const formData = new FormData(form);
try {
const res = await fetch('https://api.sadasend.com/forms/submit', {
method: 'POST',
headers: { Accept: 'application/json' },
body: formData,
});
const data = await res.json();
if (res.ok && data.success) {
setStatus('success');
form.reset();
} else {
setStatus('error');
setErrorMessage(data.message || 'Submission failed');
}
} catch (err) {
setStatus('error');
setErrorMessage('Network error submitting form');
}
}
if (status === 'success') {
return <div className="text-emerald-700 font-medium">Thank you! Your message has been sent.</div>;
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<input type="hidden" name="access_key" value="sada_form_your_key_here" />
<input type="checkbox" name="botcheck" className="hidden" style={{ display: 'none' }} />
<div>
<label className="block text-sm font-medium">Name</label>
<input name="name" type="text" required className="w-full border rounded px-3 py-2" />
</div>
<div>
<label className="block text-sm font-medium">Email</label>
<input name="email" type="email" required className="w-full border rounded px-3 py-2" />
</div>
<div>
<label className="block text-sm font-medium">Message</label>
<textarea name="message" required rows={4} className="w-full border rounded px-3 py-2" />
</div>
{status === 'error' && <p className="text-red-600 text-sm">{errorMessage}</p>}
<button
type="submit"
disabled={status === 'sending'}
className="px-4 py-2 bg-emerald-800 text-white rounded font-medium text-sm disabled:opacity-50"
>
{status === 'sending' ? 'Sending...' : 'Send Message'}
</button>
</form>
);
}Astro static site integration
Astro enables fast static sites. You can embed SadaSend directly in an .astro component with zero client runtime dependencies, or with a client script for smooth AJAX feedback:
---
// src/components/ContactForm.astro
const ACCESS_KEY = "sada_form_your_key_here";
---
<form id="contact-form" class="space-y-4">
<input type="hidden" name="access_key" value={ACCESS_KEY} />
<input type="checkbox" name="botcheck" class="hidden" style="display: none;" />
<div>
<label for="name" class="block text-sm font-medium">Name</label>
<input type="text" id="name" name="name" required class="w-full border px-3 py-2 rounded" />
</div>
<div>
<label for="email" class="block text-sm font-medium">Email</label>
<input type="email" id="email" name="email" required class="w-full border px-3 py-2 rounded" />
</div>
<div>
<label for="message" class="block text-sm font-medium">Message</label>
<textarea id="message" name="message" required rows="4" class="w-full border px-3 py-2 rounded"></textarea>
</div>
<button type="submit" id="submit-btn" class="px-4 py-2 bg-emerald-800 text-white rounded">
Send Message
</button>
<div id="form-result" class="text-sm font-medium mt-2"></div>
</form>
<script>
const form = document.getElementById("contact-form") as HTMLFormElement;
const result = document.getElementById("form-result") as HTMLElement;
const btn = document.getElementById("submit-btn") as HTMLButtonElement;
form?.addEventListener("submit", async (e) => {
e.preventDefault();
btn.disabled = true;
btn.textContent = "Sending...";
result.textContent = "";
try {
const response = await fetch("https://api.sadasend.com/forms/submit", {
method: "POST",
body: new FormData(form),
headers: { Accept: "application/json" },
});
const data = await response.json();
if (response.ok && data.success) {
result.textContent = "Thank you! Your message has been sent.";
form.reset();
} else {
result.textContent = data.message || "Something went wrong.";
}
} catch (err) {
result.textContent = "Network error. Please try again.";
} finally {
btn.disabled = false;
btn.textContent = "Send Message";
}
});
</script>Vue 3 & Nuxt 3 component
For Vue 3 and Nuxt 3 applications, use the Composition API with <script setup> and reactive submission status:
<script setup lang="ts">
import { ref } from 'vue';
const status = ref<'idle' | 'sending' | 'success' | 'error'>('idle');
const message = ref('');
async function handleSubmit(event: Event) {
status.value = 'sending';
const form = event.target as HTMLFormElement;
const formData = new FormData(form);
try {
const res = await fetch('https://api.sadasend.com/forms/submit', {
method: 'POST',
headers: { Accept: 'application/json' },
body: formData,
});
const data = await res.json();
if (res.ok && data.success) {
status.value = 'success';
message.value = 'Thank you! Your message has been sent.';
form.reset();
} else {
status.value = 'error';
message.value = data.message || 'Submission failed.';
}
} catch (e) {
status.value = 'error';
message.value = 'Network error. Please try again.';
}
}
</script>
<template>
<form @submit.prevent="handleSubmit" class="space-y-4">
<input type="hidden" name="access_key" value="sada_form_your_key_here" />
<input type="checkbox" name="botcheck" class="hidden" style="display: none;" />
<div>
<label class="block text-sm font-medium">Name</label>
<input type="text" name="name" required class="w-full border px-3 py-2 rounded" />
</div>
<div>
<label class="block text-sm font-medium">Email</label>
<input type="email" name="email" required class="w-full border px-3 py-2 rounded" />
</div>
<div>
<label class="block text-sm font-medium">Message</label>
<textarea name="message" required rows="4" class="w-full border px-3 py-2 rounded"></textarea>
</div>
<p v-if="status === 'success'" class="text-sm text-emerald-600 font-medium">{{ message }}</p>
<p v-if="status === 'error'" class="text-sm text-red-600 font-medium">{{ message }}</p>
<button type="submit" :disabled="status === 'sending'" class="px-4 py-2 bg-emerald-800 text-white rounded">
{{ status === 'sending' ? 'Sending...' : 'Send Message' }}
</button>
</form>
</template>Webflow form settings guide
Connect any native Webflow form without Zapier or third-party paid automations:
- 1. In the Webflow Designer, select your Form block and open Form Settings (gear icon in right sidebar).
- 2. Set Action to:
https://api.sadasend.com/forms/submit - 3. Set Method to:
POST - 4. Add an Embed element or hidden input inside the form with
name="access_key"and your form key as the value. - 5. Add a hidden input
name="botcheck"(with styledisplay: none;) to trap bots. - 6. Set your custom Thank-You page redirect URL via an input named
redirectif desired. - 7. Publish your Webflow site — submissions will flow directly into your inbox and SadaSend dashboard.
Framer embed & code component
Framer sites can receive inquiries using either the Embed component or a custom Code Component:
- • Method A (Framer Embed): Drag an Embed element onto your Framer canvas, set the type to HTML, and paste the standard HTML embed snippet.
- • Method B (Code Component): Create a new Code Component in Framer and paste our React component snippet above.
- • Submissions are processed without external redirects or CORS blocking.
WordPress & Elementor HTML embed
Replace heavy, vulnerable form plugins (like Contact Form 7 or WPForms) that bloat page load speeds:
- • Gutenberg Editor: Add a Custom HTML block to any page or post and paste the Plain HTML snippet.
- • Elementor: Drag an HTML Widget into your section and paste the snippet.
- • No WordPress plugins, PHP mail server configuration, or SMTP credentials needed.
cURL & terminal testing
Test form endpoints directly from your command line or integrate with backend shell scripts:
curl -X POST https://api.sadasend.com/forms/submit \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"access_key": "sada_form_your_key_here",
"name": "Jane Doe",
"email": "jane@company.com",
"subject": "Inquiry regarding Enterprise Services",
"message": "Hello, we would like to schedule a product walkthrough."
}'Spam defense & bot trapping
SadaSend shields your inbox against automated form abuse through a multi-tier defense:
• Invisible Honeypot Shield: The hidden botcheck field catches automated scripts. When filled, SadaSend returns HTTP 200 { success: true } so the bot believes it succeeded, while silently blocking email notifications.
• Disposable Domain Blocker: Rejects temporary 10-minute email domains (e.g. Mailinator, TempMail).
• CORS Origin Lock: Restrict submissions exclusively to your verified website domains.
Free plan quota & Starter upgrades
• Free Plan: Includes 2 active form endpoints, 250 submissions/month, basic honeypot shielding, and CSV export.
• Starter Plan ($12/mo): Unlocks up to 10 form endpoints, automated customer confirmation emails (auto-responders), CC & BCC notifications, custom branded email templates, and real-time webhook forwarding to Telegram and Zapier/Make.