RSVP form with a 200-seat cap, email dedup, and a live counter. Fills up, form closes. That is it.
Updated March 2026
An event page needs to do three things: show the details, collect RSVPs, and let people see how many spots are left. This gives you all three. Name, email, ticket type. 200-person cap with email dedup. A public dashboard shows the count. When it fills up, the form closes automatically. $9/month for Sutrena Builder, free hosting on Cloudflare Pages. An agent can set this up end-to-end: deploy the event landing page, create the RSVP form with maxSubmissions cap, build the live counter dashboard.
Architecture
| Tool | Role | Cost |
|---|---|---|
| Cloudflare Pages | Static site hosting | Free |
| Sutrena | RSVP form, dedup, cap, dashboard | $9/mo (Builder) |
Total cost: $9/mo
Builder starts at $9/month for 50 projects. Pro at $29/month covers 200 projects and all your other work too. Build five blueprints on Pro and it is still $29/month. That is where the value is — at scale.
A static landing page with event details, an RSVP form, and a live counter. Sutrena enforces email uniqueness and a 200-submission cap. Hit 200 and the form returns 410 Gone -- your frontend shows "Sold Out."
The dashboard shows total RSVPs, ticket type distribution (pie chart), and a daily signup timeline. You can also fetch the count via the API and display it directly on the page.
Form Definition
Name, email, ticket type. uniqueBy prevents duplicate RSVPs from the same email. maxSubmissions caps at 200. publicResults lets the counter work without auth.
{
"name": "Event RSVP",
"fields": [
{
"name": "name",
"label": "Full Name",
"type": "text",
"required": true
},
{
"name": "email",
"label": "Email",
"type": "email",
"required": true
},
{
"name": "ticket_type",
"label": "Ticket Type",
"type": "select",
"options": [
"General",
"VIP",
"Student"
],
"required": true
}
],
"uniqueBy": [
"email"
],
"publicResults": true,
"maxSubmissions": 200
}Dashboard Definition
Total RSVPs, a pie chart of General vs VIP vs Student, and a daily signup timeline. Share the URL so attendees can see the momentum building.
{
"version": 1,
"widgets": [
{
"type": "metric_card",
"title": "Total RSVPs",
"value": "count(*)"
},
{
"type": "pie_chart",
"title": "Ticket Types",
"groupBy": "ticket_type"
},
{
"type": "line_chart",
"title": "RSVPs Per Day",
"groupBy": "$submitted_at:day"
}
]
}Frontend Integration
A landing page with a live counter that polls every 30 seconds, an RSVP form with ticket types, and automatic sold-out handling. The counter fetches the total from the public API. Replace frm_YOUR_FORM_ID with yours.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tech Meetup 2026 - RSVP</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 600px; margin: 0 auto; padding: 2rem 1rem; }
.counter { font-size: 2rem; font-weight: bold; text-align: center; margin: 2rem 0; }
.counter span { color: #2563eb; }
form { display: grid; gap: 1rem; }
input, select { padding: 0.75rem; font-size: 1rem; }
button { padding: 0.75rem; font-size: 1rem; cursor: pointer; background: #111; color: #fff; border: none; }
.sold-out { text-align: center; padding: 2rem; background: #fee; border-radius: 8px; }
</style>
</head>
<body>
<h1>Tech Meetup 2026</h1>
<p>March 15, 2026 · Downtown Conference Center</p>
<div class="counter">
<span id="count">...</span> / 200 spots claimed
</div>
<div id="form-container">
<form id="rsvp-form">
<input name="name" placeholder="Full Name" required />
<input name="email" type="email" placeholder="Email" required />
<select name="ticket_type" required>
<option value="">Select ticket type</option>
<option value="General">General</option>
<option value="VIP">VIP</option>
<option value="Student">Student</option>
</select>
<button type="submit">RSVP Now</button>
</form>
</div>
<p id="status"></p>
<script>
const FORM_ID = "frm_YOUR_FORM_ID";
// Fetch live count
async function updateCount() {
try {
const res = await fetch(
`https://sutrena.com/api/forms/${FORM_ID}/submissions?limit=1`
);
const data = await res.json();
document.getElementById("count").textContent = data.total || 0;
if (data.total >= 200) {
document.getElementById("form-container").innerHTML =
'<div class="sold-out"><strong>Sold Out!</strong><p>All 200 spots have been claimed.</p></div>';
}
} catch (e) {
document.getElementById("count").textContent = "...";
}
}
updateCount();
setInterval(updateCount, 30000);
// Handle RSVP
document.getElementById("rsvp-form")?.addEventListener("submit", async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
const body = Object.fromEntries(fd);
const res = await fetch(
`https://sutrena.com/api/forms/${FORM_ID}/submit`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
}
);
const status = document.getElementById("status");
if (res.ok) {
status.textContent = "You're in! See you there.";
updateCount();
} else if (res.status === 409) {
status.textContent = "You've already RSVP'd with this email.";
} else if (res.status === 410) {
status.textContent = "Sorry, all spots are taken!";
}
});
</script>
</body>
</html>Sutrena returns 410 Gone. The frontend shows "Sold Out." You can increase maxSubmissions via PATCH if you want to open more spots later.
You can delete a submission by email via the API. There is no self-service cancellation built in. You could build one with a Cloudflare Worker if you need it, but for most events manual cancellation is fine.
Create a second form with no cap. When the main form returns 410, redirect users to the waitlist form. Two forms, same account.
It updates every 30 seconds. Close enough for most events. If you need true real-time, you would need a webhook pushing to a WebSocket server. Probably overkill for an RSVP counter.
Sutrena is the web runtime for AI agents. Three primitives — pages, forms, and dashboards — accessible through one API. Your agent creates web artifacts, humans interact with them, and your agent gets the data back. Framework-agnostic. Works from any MCP client or HTTP client.
1. Get a trial key (no auth, no signup)
curl -X POST https://sutrena.com/api/trial2. Create a form + dashboard from a template
curl -X POST https://sutrena.com/api/forms \
-H "Authorization: Bearer st_trial_xxx" \
-H "Content-Type: application/json" \
-d '{"templateId": "waitlist", "createDashboard": true}'Get a trial API key instantly with no signup, or create an account for the full experience.