Forms
Define forms with field schemas, then collect submissions through a validated public endpoint. No controller code required.
Field definitions
The fields column stores a JSON array. Each definition supports:
| Property | Type | Description |
|---|---|---|
name | string | Required. Field name (key in submitted data) |
type | string | string (default), number, boolean, email, uuid |
required | boolean | Must be present |
min / max | number | Numeric bounds (number type) |
minLength / maxLength | number | String length bounds |
pattern | string | Regex the value must match (string/email) |
enum | array | Allowed values (all types) |
[
{ "name": "email", "type": "email", "required": true },
{ "name": "subject", "type": "string", "required": true, "minLength": 3 },
{ "name": "rating", "type": "number", "required": false, "min": 1, "max": 5 },
{ "name": "category", "type": "string", "enum": ["general", "support", "billing"] }
]
Submitting
POST to /forms/:id. JSON and form-encoded bodies are both accepted:
curl -X POST https://your-cms.dev/forms/<form-id> \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "message": "Hello!"}'
| Status | Description |
|---|---|
201 | Success — {"success":true,"id":"<entry-id>"} |
400 | Missing/invalid body or unsupported Content-Type |
404 | Form not found |
422 | Validation failed — returns details array |
Submissions are stored in the form_entries table with the validated data as JSON.
Managing entries (admin)
GET /api/forms/:id/entries # list entries for a form
DELETE /api/forms/:id/entries/:entryId # delete an entry
Frontend helpers
Submission fires a form_entry.created webhook, so you can trigger emails, notifications, or CRM syncs without polling. For spam protection, configure Turnstile, reCAPTCHA, or hCaptcha per form — the frontend fetches the provider config from /captcha-config and the submission includes the captcha token for server-side verification.
Rendering forms
The seeded form component renders a styled form from props and submits via AJAX:
{{ component name:"form" props:data.contactForm }}
Pass form_id, fields (name, label, type, placeholder, required, minLength, maxLength, rows), title, description, and submit_text — typically through a static data source on the page.