A real form engine, not a survey tool.
19 typed question primitives, composable sections, two display modes. Designed for forms that have to do something — not just collect rows.
For ops teams who outgrew their patched-together intake stack
Real conditional logic, AI-assisted building, and a production-grade backend — distributed wherever your users are via public link, iframe, script tag, or web component.
You can't bypass the rule from the client. The server runs the same JsonLogic on submit. Hidden questions are never validated as required; visible ones always are.
Buyers care about the wedge — not the 60-row feature matrix. Every section below serves one of these. Receipts, not adjectives.
19 typed question primitives, composable sections, two display modes. Designed for forms that have to do something — not just collect rows.
JsonLogic on the server and the renderer. Required-ness, visibility, skip-to are part of the model.
A grounded form-building agent (Anthropic or Gemini) emits a typed FormExport. Schema-validated before it lands.
Public link, iframe, script tag, or web component. Branded theming, draft-saving, URL prefill, graceful pause states.
FastAPI + Postgres + RS256 JWT with JWKS rotation. Multi-tenant, per-tenant quotas, HMAC-signed webhooks, self-hostable.
Rules are stored as JsonLogic expressions on the question record. The same expression evaluates on both surfaces — no drift. The submission endpoint runs the rules itself to decide which questions are required.
Numeric IDs become portable refs at export. Move a form between workspaces without rewriting any expression.
Every type is a typed primitive with its own renderer component, validator, and admin config UI. Answers are stored as JSONB so a new type can land without a schema migration.
single-line text · validated
multi-line textarea
RFC-validated email input
locale-rendered currency code
native or polyfilled date picker
radio · single value
star scale, configurable max
direct to object storage
Trigger question controls the count; the engine produces N copies with their own validation and storage. One-at-a-time mode turns each item into a named step.
"Hi {name}, when did you start at {company}?" — rendered live as the respondent moves through. Works in labels and descriptions.
A read-only question type derived from other fields via a friendly template syntax: {price} * {quantity}. Hidden-mode allowed; usable as a downstream value.
No free-text JSON dumps. The agent calls a typed generate_form tool whose payload is validated against the FormExport schema — and imported through the same path as a JSON upload.
Public URL, iframe, or web component — all three drive the same Vite + React renderer. Theming, draft-saving, and prefill behave identically. Pause a workspace and every surface returns a graceful 409 form_unavailable — never a blank screen.
Per-form slug, branded on a subdomain you control. URL query-params seed the form: ?email=…&plan=pro.
A dedicated /embed/:slug route sized for an iframe. No outer chrome, themed at fill-time, draft-saving still works.
Renders inside a Shadow DOM so host CSS never bleeds in. Same renderer, same draft-saving, same prefill — one custom tag.
Primary, background, font, logo, custom CSS — scoped to the form root.
Respondents get an X-Session-ID cookie; in-progress answers + step position persist. Restore toast on return.
Form-level or workspace-level pause returns 409 form_unavailable — your host page shows a real message, not a 404.
The narrative above explains the wedge. This is the rest of the surface — analytics, identity, governance, dispatch. Available in the workspace on day one.
Total / today / week, response trend, per-question breakdowns. Histograms for categorical, distributions for numeric.
Per-response PDF with every answer rendered. jspdf-autotable in the admin.
Workspaces with owner + member roles. Tenant-active state cached 30s on every backend instance.
Email-based, signed token, preview-before-accept. Resend / revoke / accept flows. Last owner can't be demoted.
Google OAuth, magic link with 6-digit fallback, and SSO / passkeys via your existing IdP.
Long-lived X-API-Key, hashed at rest, labeled and individually revocable. Default token minted on workspace create.
max_forms and max_responses per workspace as opaque policy. -1 = unlimited. Counter updates transactional with the insert.
Anonymous draft-saving by session cookie; auto-restore toast on return. Required validation respects conditional logic.
form.submitted today, extensible. SHA-256 signature on every payload. Async via background tasks.
Access tokens 15-min TTL, refresh 30-day with family-tracked rotation and reuse detection. JWKS endpoint for verifiers.
Forms round-trip as portable refs (q_0_3, s_2). The agent imports through the same path you upload to.
file_upload posts directly to object storage. Answer record holds the reference, not the bytes.
A 30-minute walkthrough on your most-painful intake flow — what the rules would look like, where the embed would go, what comes out the webhook end.