A static site can't receive a form submission on its own; it needs somewhere to send it. With Birta, you describe the form to your agent, the fields you want, and it declares the form and writes the markup. From then on, every submission lands in your project's panel, and a summary email follows within 15 minutes.
This walks through the real contract behind that: what your agent actually writes, where a submission goes, and what Birta doesn't do (Telegram, webhooks, a CAPTCHA), so you're not left guessing.
Why a static site can't just "have" a form
A plain HTML form is front-end markup, and nothing more. When someone clicks submit, the browser sends that data somewhere, and a static site has no back end sitting behind it to catch it. A static host only serves files. It doesn't process anything.
This is the wall almost everyone hits first. You build a landing page with an
AI tool, it looks finished, and then a <form> tag sits there expecting the
submit button to just work. It doesn't, because nothing is listening on the
other end.
That's not a bug in your markup. It's the nature of static hosting: fast, cheap, and hard to break into precisely because no server-side code is running that could fail or be attacked. The tradeoff is that a form needs one more piece: somewhere that actually accepts the request and does something with it.
What "add a form" actually means here
On Birta, that piece is built in, but not as a drop-in widget. Say what you want to collect to the agent that's already building your site: a name, an email, a message, a checkbox for consent. The agent declares the form on your project, a set of fields, each with a type and whether it's required.
Then the agent writes the form's actual markup itself, styled to match your site. Birta gives no ready-made form block and doesn't dictate how the form looks.
That's a deliberate difference from widget-based tools such as Formbricks, which embeds its own form inside an iframe on your page. The box works, but it looks like the tool, not your site. Here the HTML is yours, and so is the "thanks for reaching out" line the visitor reads. The full contract lives in the lead-forms guide if you want the operational reference alongside this.
Where a submission actually goes
This is the part most guides skip, and it decides whether the form works at
all. A submission posts to POST /_forms/<key> on the site's own host,
whatever address it's live at, standard or a connected domain. The body is
JSON, and the endpoint is public: no API key, no project id, no secret token
belongs anywhere in the markup, because a visitor's own browser is the one
sending it.
A successful submission gets 201 {"status": "accepted"}. A rejected one
comes back with a specific code: 400 when a field doesn't match the
declared form, 403 if you're testing on a draft (a version preview never
accepts a submission, on purpose), 404 if the form key doesn't exist, 413
if the payload is too large, 429 past a rate limit. Your agent reads that
code and turns it into whatever the visitor should see next. Birta doesn't
write that message for you.
The body only carries the keys you declared, nothing else. An absent field,
null, an empty string, and an empty list all count the same way: not
filled in. A required field left that way is refused. An optional one is
simply left out of the lead, no error, no empty row in your panel.
One field is stricter than it looks: consent. Most contact forms have a
checkbox for permission to reply, and a consent field here takes a JSON
boolean, where only true counts as given. Anything else, including a
missing value or the string "true" instead of the boolean, is refused as
consent_not_given. A vague checkbox that any truthy-looking value could
satisfy isn't really consent. Requiring an actual boolean is what keeps it
meaning what it says.
What you can actually collect
A form can hold up to 20 fields, and a project can declare up to 5 forms, splitting an order form from a callback request, say. Each field is one of a handful of types: short text, long text, email, a single choice from a list, a checkbox for consent. Short text tops out at 500 characters, long text at 5,000, email addresses at 254, and a whole submission at 65,536 bytes.
Those are this deployment's configured limits as of publishing, not a number carved into the product forever. What matters is the shape: room for a real inquiry, not enough for someone to paste in a novel.
Reading what comes in
Every accepted submission shows up in your project's panel, marked "new," with the date, the form it came from, and every field the visitor filled in. A site that collects more than one kind of request, an order form and a callback form, say, splits them out so you're not scanning one long list for the ones that matter.
You don't have to sit there refreshing it. The notification is an email, not a live push: a submission opens a 15-minute window, and when it closes, one message goes to everyone with access to the project. It names the project and lists every submission that landed in the window, each with its form, its time, and its fields. A single late submission still gets its own email, 15 minutes after it arrives.
When the form sits on a page built to collect inquiries, how many of those leads your plan lets you open starts to matter as much as the form itself. When there is nothing to reply to yet, because the thing you are building is not out, the form shrinks to one field and the job becomes collecting a waitlist. And on a site of several pages, the link that sends people to the form usually belongs in the footer, because that is the one block a visitor can reach from wherever they gave up.
And this is where it stops
Three things this isn't. No Telegram delivery, no webhook, and no choice of where a submission goes: it lands in the panel, and a digest follows by email, and that's the whole delivery story. There's also no accept-payment step built into the form.
If your project needs any of that today, it needs a different layer than this brick gives you.
Keeping spam out without a CAPTCHA
Birta doesn't put a CAPTCHA in front of your form. A plain rate limit does
the work instead. A visitor can send up to 5 submissions in a 10-minute
window, and a project accepts up to 200 submissions an hour in total. Past
either limit, a submission comes back as 429 too_many_submissions, and your
agent can turn that into a line on the page.
That's not smart spam filtering. It won't recognize a script pacing itself under the limit, and it won't score a message for spammy content. What it actually stops is the ordinary case: a double-submitted form, a broken retry loop, someone hammering refresh. For most contact forms, that covers most of what goes wrong.
Describe the form. Your agent builds it.
Tell your agent what fields you need, and it writes the form. Submissions land in your panel within minutes.
