Framework guides
Next.js
Server Actions, Route Handlers, and when to use each.
With a Server Action the key never reaches the browser and the form works without client JavaScript. It is the best default for a Next.js site.
app/contact/page.tsx
// Server Action — no client JavaScript required.
import { redirect } from "next/navigation";
export default function ContactPage() {
async function send(formData: FormData) {
"use server";
formData.append("access_key", process.env.CONTACT_ACCESS_KEY!);
const res = await fetch("https://api.formpost.ai/submit", {
method: "POST",
headers: { Accept: "application/json" },
body: formData,
});
// Without this the page just sits there on failure and the visitor
// assumes it sent. Point these at pages you actually have.
const { success } = await res.json();
redirect(success ? "/contact/thanks" : "/contact/error");
}
return (
<form action={send}>
<input name="name" required />
<input type="email" name="email" required />
<textarea name="message" required />
<button type="submit">Send</button>
</form>
);
}Client-side alternative
If you want inline validation or an optimistic UI, submit from a client component exactly as you would in plain React. Both approaches hit the same endpoint.
ContactForm.tsx
import { useState } from "react";
export function ContactForm() {
const [status, setStatus] = useState<"idle" | "sending" | "sent" | "error">("idle");
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus("sending");
const data = new FormData(event.currentTarget);
data.append("access_key", "YOUR_ACCESS_KEY_HERE");
const res = await fetch("https://api.formpost.ai/submit", {
method: "POST",
headers: { Accept: "application/json" },
body: data,
});
const json = await res.json();
setStatus(json.success ? "sent" : "error");
}
return (
<form onSubmit={onSubmit}>
<input name="name" required />
<input type="email" name="email" required />
<textarea name="message" required />
<button disabled={status === "sending"}>Send</button>
{status === "sent" && <p>Thanks — we will be in touch.</p>}
</form>
);
}