Skip to content

Forms API

Public API

The form config and submit endpoints are part of Studio's public, versioned API (/api/forms/v1/), designed to be called directly from your site. Submission management (review, approve, convert) is part of the internal application API.

Studio supports public form submissions that map to collection models. Forms can be embedded on external websites to collect data that flows into the content pipeline.

Public Endpoints

These endpoints require no authentication and are designed for external embedding.

Get Form Configuration

Get the public schema for a form-enabled model.

GET /api/forms/v1/:projectId/:modelId/config

Response

json
{
  "modelId": "contact-form",
  "fields": {
    "name": { "type": "string", "required": true },
    "email": { "type": "email", "required": true },
    "message": { "type": "text", "required": true },
    "newsletter": { "type": "boolean", "required": false }
  },
  "captcha": "turnstile",
  "successMessage": "Thank you for your submission!",
  "honeypotField": "_hp"
}

Only fields listed in the model's exposedFields configuration are returned. Internal fields are never exposed.

Example

bash
curl https://studio.example.com/api/forms/v1/{projectId}/{modelId}/config

CORS

The endpoint returns Access-Control-Allow-Origin: * headers for cross-origin embedding.


Submit Form

Submit data to a form-enabled model.

POST /api/forms/v1/:projectId/:modelId/submit

Request Body

FieldTypeRequiredDescription
dataobjectYesForm field values
captchaTokenstringConditionalTurnstile token (when captcha is configured)
_hpstringNoHoneypot field (must be empty -- bots fill it)

Response

Success:

json
{
  "success": true,
  "message": "Thank you for your submission!"
}

Validation Error:

json
{
  "success": false,
  "errors": [
    { "field": "email", "message": "email must be a valid email" }
  ]
}

Security Features

FeatureDescription
Rate limitingPer-IP sliding window (configurable, default 10/min)
HoneypotHidden field -- bots fill it, humans do not. Silent 200 rejection.
CaptchaCloudflare Turnstile verification (Starter+ plan)
HTML sanitizationAll string values stripped of HTML tags, JS patterns, entities
Field filteringOnly exposed fields are accepted; others are silently dropped
ValidationSchema-based validation against model field definitions
Monthly limitsAtomic check + insert prevents race conditions

Plan Limits

PlanForm ModelsSubmissions/Month
Free00
Starter1100
Pro153,000
EnterpriseUnlimitedUnlimited

Auto-Approve

When configured and the plan supports forms.auto_approve, submissions are automatically converted to content entries and merged into the repository.


Admin Endpoints

These endpoints require authentication and workspace membership.

List Submissions

GET /api/workspaces/:workspaceId/projects/:projectId/forms/:modelId/submissions

Query Parameters

ParameterTypeDefaultDescription
statusstringpendingFilter: pending, approved, rejected, spam
pagenumber1Page number
limitnumber20Items per page
sortstringnewestSort: newest, oldest

Response

json
{
  "submissions": [
    {
      "id": "uuid",
      "model_id": "contact-form",
      "data": { "name": "John", "email": "[email protected]", "message": "Hello" },
      "status": "pending",
      "source_ip": "192.168.1.1",
      "created_at": "2026-01-01T00:00:00Z"
    }
  ],
  "total": 15
}

Update Submission Status

PATCH /api/workspaces/:workspaceId/projects/:projectId/forms/:modelId/submissions/:submissionId
FieldTypeRequiredDescription
status'approved' | 'rejected' | 'spam'YesNew status

Delete Submission

DELETE /api/workspaces/:workspaceId/projects/:projectId/forms/:modelId/submissions/:submissionId

Bulk Update

POST /api/workspaces/:workspaceId/projects/:projectId/forms/:modelId/submissions/bulk
FieldTypeRequiredDescription
submissionIdsstring[]YesSubmission IDs to update
status'approved' | 'rejected' | 'spam'YesTarget status

Released under the AGPL-3.0 License.