Clients log in, submit tickets, pick a priority. You query everything via API. That is the whole thing.
Updated March 2026
You need a place for clients to send you requests. Something with a login, a form, and a way for you to see what came in. Clerk handles auth. Cloudflare Pages hosts the portal. Sutrena stores the tickets and lets you query them by priority, status, and date via API. Brand it with your own domain and Clerk's branding settings. $29/month on Pro. `sutrena_launch` deploys portal pages, `sutrena_collect` handles intake forms, each scoped to a folder.
Architecture
| Tool | Role | Cost |
|---|---|---|
| Clerk | Client authentication | Free (50K MAU) |
| Cloudflare Pages | Portal hosting | Free |
| Sutrena | Ticket form, submission storage, webhooks | $29/mo (Pro) |
Total cost: $29/mo
Pro is $29/month for 100 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.
Clerk gives each client a user_id. The portal is a React app on Cloudflare Pages with a ticket form. When a client submits, the frontend injects their Clerk user_id as a hidden client_id field. Sutrena stores the ticket.
Query tickets via the submissions API — filter by priority, client_id, or date. Webhooks push new tickets to Slack or your internal tools in real time. For white-labeling, use your own domain on Cloudflare Pages and customize Clerk's branding.
Form Definition
Hidden client_id from Clerk, a subject line, a message, and a priority level. The client_id links each ticket to a specific client for filtering.
{
"name": "Client Support Tickets",
"fields": [
{
"name": "client_id",
"type": "hidden"
},
{
"name": "subject",
"label": "Subject",
"type": "text",
"required": true
},
{
"name": "message",
"label": "Message",
"type": "textarea",
"required": true
},
{
"name": "priority",
"label": "Priority",
"type": "select",
"options": [
"Low",
"Normal",
"Urgent"
],
"required": true
}
]
}Frontend Integration
A ticket form that gets the client_id from Clerk automatically. After submission, shows a confirmation with an option to submit another. Replace frm_YOUR_FORM_ID with yours.
"use client";
import { useUser } from "@clerk/nextjs";
import { useState } from "react";
const FORM_ID = "frm_YOUR_FORM_ID";
export function TicketForm() {
const { user } = useUser();
const [status, setStatus] = useState<"idle" | "sending" | "sent">("idle");
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
if (!user) return;
setStatus("sending");
const fd = new FormData(e.currentTarget);
const res = await fetch(
`https://sutrena.com/api/forms/${FORM_ID}/submit`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client_id: user.id,
subject: fd.get("subject"),
message: fd.get("message"),
priority: fd.get("priority"),
}),
}
);
setStatus(res.ok ? "sent" : "idle");
}
if (status === "sent") {
return (
<div>
<p>Ticket submitted. We will respond within 24 hours.</p>
<button onClick={() => setStatus("idle")}>Submit another</button>
</div>
);
}
return (
<form onSubmit={handleSubmit}>
<input name="subject" placeholder="Subject" required />
<textarea
name="message"
placeholder="Describe your issue or request..."
rows={5}
required
/>
<select name="priority" required>
<option value="">Select priority</option>
<option value="Low">Low</option>
<option value="Normal">Normal</option>
<option value="Urgent">Urgent</option>
</select>
<button type="submit" disabled={status === "sending" || !user}>
{status === "sending" ? "Submitting..." : "Submit Ticket"}
</button>
</form>
);
}Yes. sutrena_collect creates the form and webhooks in one call. sutrena_launch deploys pages with analytics. The code examples below show primitive APIs for full control, but compound tools handle most setups faster.
Not directly through Sutrena. You would need to fetch all submissions via the API and filter by client_id in a Cloudflare Worker or server component. Sutrena stores the data, but it does not have per-user views built in.
Customize Clerk's sign-in page with your logo and colors. Host on a custom domain via Cloudflare Pages. Clients never see Sutrena -- you use the fetch API, not the embed.
Yes. Add a file field to the form. The frontend needs the presigned upload flow from the file upload guide. A bit more wiring, but it works.
Set up a webhook on the form that sends to Slack. All tickets trigger it. If you want only urgent ones, use Zapier or a Cloudflare Worker to filter by priority before forwarding.
Sutrena is the web runtime for AI agents. Forms, Pages, Analytics, Webhooks, Automations — all through 67 MCP tools and one REST API. Your agent creates web artifacts, humans interact with them, and your agent gets the data back. Use any one feature or all of them together.
Pages
Deploy HTML instantly
Forms
Collect structured data
Automations
DSL-based pipelines with 14 step types
Analytics
Privacy-first, no cookies
Webhooks
Slack, Discord, Telegram
1. Get a trial key (no auth, no signup)
curl -X POST https://sutrena.com/api/trial2. Create anything — a page, form, automation, or analytics site
# Create a form
curl -X POST https://sutrena.com/api/forms \
-H "Authorization: Bearer st_trial_xxx" \
-H "Content-Type: application/json" \
-d '{"name": "waitlist", "fields": [{"name": "email", "label": "Email", "type": "email", "required": true}]}'
# Or deploy a page
curl -X POST https://sutrena.com/api/pages \
-H "Authorization: Bearer st_trial_xxx" \
-H "Content-Type: application/json" \
-d '{"slug": "index", "title": "My Site", "html": "<h1>Live</h1>"}'Get a trial API key instantly with no signup, or create an account for the full experience.