Skip to main content

Forms Block

Forms Block

Dynamic form builder API with 20+ field types, validation, and workflows

The Forms Block provides a complete form building solution. Create unlimited forms with any combination of field types, validation rules, conditional logic, and submission workflows - all through a RESTful API.

Key Features​

  • Dynamic Form Builder - Create forms programmatically with JSON configuration
  • 20+ Field Types - Text, email, phone, date, file upload, signature, rating, and more
  • Validation Engine - Built-in validators with custom rule support
  • Conditional Logic - Show/hide fields based on user responses
  • Submission Workflows - Trigger webhooks, emails, and CRM integrations on submit
  • Multi-Page Forms - Build wizard-style forms with step navigation
  • Form Analytics - Track submissions, completion rates, and field drop-off
  • Real-time Webhooks - Instant notifications for form events

API Endpoint​

ServiceURL
Formshttps://forms.api.us.23blocks.com

Environment Routing: One URL, one environment. All shared-platform API keys are live keys:

  • pk_live_* / sk_live_* → your production tenant. Need a separate staging environment? It is available as a paid add-on on deployments in your own cloud account — see 23blocks in a Box.

Quick Start​

Installation​

npm install @23blocks/sdk

Basic Usage​

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { forms: 'https://forms.api.us.23blocks.com' },
apiKey: 'your-api-key',
});

// Create a contact form
const form = await client.forms.create({
name: 'Contact Form',
fields: [
{
type: 'text',
name: 'full_name',
label: 'Full Name',
required: true
},
{
type: 'email',
name: 'email',
label: 'Email Address',
required: true,
validators: ['email']
},
{
type: 'textarea',
name: 'message',
label: 'Your Message',
placeholder: 'How can we help?',
maxLength: 1000
}
]
});

// Submit form data
const submission = await client.forms.submit(form.id, {
full_name: 'Jane Smith',
email: 'jane@example.com',
message: 'I would like to learn more about your API.'
});

Authentication​

Required Headers​

All API requests require authentication:

Authorization: Bearer [JWT_TOKEN]
X-API-Key: [COMPANY_API_KEY]
Content-Type: application/json

API Reference​


Forms​

Create Form​

Create a new form with field definitions.

POST /api/v1/forms

Request Body:

{
"data": {
"type": "forms",
"attributes": {
"name": "Contact Form",
"description": "Get in touch with our team",
"slug": "contact",
"status": "active",
"settings": {
"submit_button_text": "Send Message",
"success_message": "Thank you! We'll be in touch soon.",
"redirect_url": null,
"collect_ip": true,
"enable_captcha": true
},
"fields": [
{
"type": "text",
"name": "full_name",
"label": "Full Name",
"required": true,
"placeholder": "John Smith"
},
{
"type": "email",
"name": "email",
"label": "Email Address",
"required": true,
"validators": ["email"]
}
],
"actions": [
{
"type": "webhook",
"url": "https://api.example.com/leads",
"method": "POST"
},
{
"type": "email",
"to": "team@company.com",
"subject": "New Contact Form Submission"
}
]
}
}
}

Response:

{
"data": {
"id": "form_xyz789",
"type": "forms",
"attributes": {
"name": "Contact Form",
"description": "Get in touch with our team",
"slug": "contact",
"status": "active",
"fields": [...],
"actions": [...],
"settings": {...},
"submission_count": 0,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
}
}

Get Form​

Retrieve a form by ID.

GET /api/v1/forms/:id

Query Parameters:

ParameterTypeDescription
includestringRelated resources: submissions,analytics

List Forms​

Retrieve a paginated list of forms.

GET /api/v1/forms

Query Parameters:

ParameterTypeDescription
page[number]integerPage number (default: 1)
page[size]integerItems per page (default: 25, max: 100)
filter[status]stringFilter by status: active, draft, archived
filter[slug]stringFilter by slug (exact match)
sortstringSort field: created_at, -created_at, name

Update Form​

Update an existing form.

PATCH /api/v1/forms/:id

Delete Form​

Delete a form (soft delete by default).

DELETE /api/v1/forms/:id

Duplicate Form​

Create a copy of an existing form.

POST /api/v1/forms/:id/duplicate

Field Types​

Forms Block supports 20+ field types:

Basic Fields​

TypeDescriptionOptions
textSingle-line text inputplaceholder, minLength, maxLength, pattern
textareaMulti-line text inputplaceholder, minLength, maxLength, rows
numberNumeric inputmin, max, step, placeholder
emailEmail input with validationplaceholder
phonePhone number inputplaceholder, format
urlURL input with validationplaceholder
passwordPassword inputminLength, requireUppercase, requireNumber

Selection Fields​

TypeDescriptionOptions
dropdownSingle-select dropdownoptions, placeholder
multiselectMulti-select dropdownoptions, maxSelections
radioRadio button groupoptions, layout
checkboxCheckbox groupoptions, minSelections, maxSelections
booleanSingle yes/no checkboxlabel

Date & Time Fields​

TypeDescriptionOptions
dateDate pickerminDate, maxDate, format
timeTime pickerminTime, maxTime, format
datetimeDate and time pickerminDateTime, maxDateTime

Advanced Fields​

TypeDescriptionOptions
fileFile uploadaccept, maxSize, maxFiles
signatureSignature padwidth, height
ratingStar ratingmax, allowHalf
sliderRange slidermin, max, step
addressAddress autocompletecountries, types
richtextRich text editortoolbar, maxLength
hiddenHidden fieldvalue

Field Configuration Example​

{
"type": "file",
"name": "resume",
"label": "Upload Resume",
"required": true,
"options": {
"accept": [".pdf", ".doc", ".docx"],
"maxSize": 5242880,
"maxFiles": 1
},
"helpText": "PDF or Word document, max 5MB"
}

Submissions​

Submit Form​

Submit data to a form.

POST /api/v1/forms/:form_id/submissions

Request Body:

{
"data": {
"type": "submissions",
"attributes": {
"values": {
"full_name": "Jane Smith",
"email": "jane@example.com",
"message": "Hello!"
},
"metadata": {
"source": "website",
"utm_source": "google"
}
}
}
}

Response:

{
"data": {
"id": "sub_abc123",
"type": "submissions",
"attributes": {
"form_id": "form_xyz789",
"values": {
"full_name": "Jane Smith",
"email": "jane@example.com",
"message": "Hello!"
},
"metadata": {
"source": "website",
"utm_source": "google",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0..."
},
"status": "completed",
"created_at": "2025-01-15T14:30:00Z"
}
}
}

Get Submission​

Retrieve a submission by ID.

GET /api/v1/submissions/:id

List Submissions​

Get submissions for a form.

GET /api/v1/forms/:form_id/submissions

Query Parameters:

ParameterTypeDescription
page[number]integerPage number (default: 1)
page[size]integerItems per page (default: 25, max: 100)
filter[status]stringFilter by status: completed, partial, spam
filter[created_after]datetimeFilter by date range start
filter[created_before]datetimeFilter by date range end
sortstringSort: created_at, -created_at

Export Submissions​

Export submissions as CSV or JSON.

GET /api/v1/forms/:form_id/submissions/export

Query Parameters:

ParameterTypeDescription
formatstringExport format: csv, json (default: csv)
filter[created_after]datetimeFilter by date range
filter[created_before]datetimeFilter by date range

Delete Submission​

Delete a submission.

DELETE /api/v1/submissions/:id

Validation​

Built-in Validators​

ValidatorDescriptionOptions
requiredField must have a value-
emailValid email format-
phoneValid phone formatformat
urlValid URL formatprotocols
minLengthMinimum character countvalue
maxLengthMaximum character countvalue
minMinimum numeric valuevalue
maxMaximum numeric valuevalue
patternRegex pattern matchregex, message

Custom Validation Rules​

{
"type": "text",
"name": "company_email",
"label": "Work Email",
"validators": [
"required",
"email",
{
"type": "pattern",
"regex": "^[a-zA-Z0-9._%+-]+@company\\.com$",
"message": "Please use your company email address"
}
]
}

Server-Side Validation​

POST /api/v1/forms/:form_id/validate

Request Body:

{
"values": {
"email": "invalid-email",
"full_name": ""
}
}

Response:

{
"valid": false,
"errors": {
"email": ["Please enter a valid email address"],
"full_name": ["This field is required"]
}
}

Conditional Logic​

Show or hide fields based on user responses.

Condition Types​

TypeDescription
equalsField value equals specified value
not_equalsField value does not equal specified value
containsField value contains specified string
greater_thanNumeric value is greater than
less_thanNumeric value is less than
is_emptyField has no value
is_not_emptyField has a value

Configuration Example​

{
"fields": [
{
"type": "radio",
"name": "contact_method",
"label": "Preferred Contact Method",
"options": [
{ "value": "email", "label": "Email" },
{ "value": "phone", "label": "Phone" }
]
},
{
"type": "phone",
"name": "phone_number",
"label": "Phone Number",
"conditions": {
"show_when": {
"field": "contact_method",
"operator": "equals",
"value": "phone"
}
}
}
]
}

Multiple Conditions​

{
"conditions": {
"show_when": {
"logic": "and",
"rules": [
{ "field": "country", "operator": "equals", "value": "US" },
{ "field": "age", "operator": "greater_than", "value": 18 }
]
}
}
}

Multi-Page Forms​

Create wizard-style forms with multiple pages.

Configuration​

{
"name": "Application Form",
"settings": {
"multi_page": true,
"show_progress": true,
"allow_back_navigation": true
},
"pages": [
{
"title": "Personal Information",
"fields": [
{ "type": "text", "name": "first_name", "label": "First Name" },
{ "type": "text", "name": "last_name", "label": "Last Name" }
]
},
{
"title": "Contact Details",
"fields": [
{ "type": "email", "name": "email", "label": "Email" },
{ "type": "phone", "name": "phone", "label": "Phone" }
]
},
{
"title": "Review",
"fields": [],
"settings": {
"show_summary": true
}
}
]
}

Save Progress​

POST /api/v1/forms/:form_id/progress

Request Body:

{
"session_id": "sess_abc123",
"current_page": 2,
"values": {
"first_name": "Jane",
"last_name": "Smith"
}
}

Actions & Workflows​

Available Actions​

ActionDescription
webhookSend submission data to a URL
emailSend email notification
crmCreate CRM contact (via CRM Block)
slackPost to Slack channel
zapierTrigger Zapier webhook

Webhook Action​

{
"type": "webhook",
"url": "https://api.example.com/leads",
"method": "POST",
"headers": {
"Authorization": "Bearer {{secrets.api_key}}"
},
"payload_template": {
"lead_name": "{{values.full_name}}",
"lead_email": "{{values.email}}"
}
}

Email Action​

{
"type": "email",
"to": "{{values.email}}",
"cc": ["team@company.com"],
"subject": "Thank you for your submission",
"template": "submission_confirmation",
"variables": {
"name": "{{values.full_name}}"
}
}

CRM Integration​

{
"type": "crm",
"action": "create_contact",
"mapping": {
"first_name": "{{values.first_name}}",
"last_name": "{{values.last_name}}",
"email": "{{values.email}}",
"tags": ["website-lead"]
}
}

Analytics​

Get Form Analytics​

GET /api/v1/forms/:form_id/analytics

Response:

{
"data": {
"form_id": "form_xyz789",
"period": "last_30_days",
"metrics": {
"views": 5420,
"starts": 2150,
"completions": 1823,
"completion_rate": 84.79,
"average_time_seconds": 145,
"submissions_by_day": [
{ "date": "2025-01-15", "count": 62 },
{ "date": "2025-01-14", "count": 58 }
]
},
"field_analytics": [
{
"field": "email",
"drop_off_rate": 2.3,
"average_time_seconds": 12
},
{
"field": "message",
"drop_off_rate": 8.5,
"average_time_seconds": 45
}
]
}
}

Webhooks​

Webhook Events​

EventDescription
form.createdNew form created
form.updatedForm updated
form.deletedForm deleted
submission.createdNew submission received
submission.updatedSubmission updated
submission.deletedSubmission deleted

Create Webhook​

POST /api/v1/webhooks

Request Body:

{
"data": {
"type": "webhooks",
"attributes": {
"url": "https://api.example.com/forms-webhook",
"events": ["submission.created"],
"form_id": "form_xyz789"
}
}
}

Webhook Payload​

{
"event": "submission.created",
"timestamp": "2025-01-15T14:30:00Z",
"data": {
"submission_id": "sub_abc123",
"form_id": "form_xyz789",
"form_name": "Contact Form",
"values": {
"full_name": "Jane Smith",
"email": "jane@example.com"
}
}
}

SDK Examples​

TypeScript​

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { forms: 'https://forms.api.us.23blocks.com' },
apiKey: process.env.BLOCKS_API_KEY!,
});

// Create a survey form with conditional logic
async function createSurveyForm() {
const form = await client.forms.create({
name: 'Customer Satisfaction Survey',
fields: [
{
type: 'rating',
name: 'satisfaction',
label: 'How satisfied are you?',
required: true,
options: { max: 5 }
},
{
type: 'textarea',
name: 'feedback',
label: 'What could we improve?',
conditions: {
show_when: {
field: 'satisfaction',
operator: 'less_than',
value: 4
}
}
},
{
type: 'textarea',
name: 'testimonial',
label: 'Would you like to share a testimonial?',
conditions: {
show_when: {
field: 'satisfaction',
operator: 'greater_than',
value: 3
}
}
}
],
actions: [
{
type: 'webhook',
url: 'https://api.example.com/surveys'
}
]
});

return form;
}

// Handle form submission with validation
async function submitForm(formId: string, data: Record<string, any>) {
// Validate first
const validation = await client.forms.validate(formId, data);

if (!validation.valid) {
throw new Error(`Validation failed: ${JSON.stringify(validation.errors)}`);
}

// Submit
const submission = await client.forms.submit(formId, {
values: data,
metadata: {
source: 'mobile-app',
version: '2.1.0'
}
});

return submission;
}

// Export submissions
async function exportSubmissions(formId: string, startDate: Date, endDate: Date) {
const csv = await client.forms.exportSubmissions(formId, {
format: 'csv',
filter: {
created_after: startDate.toISOString(),
created_before: endDate.toISOString()
}
});

return csv;
}

Error Codes​

CodeDescription
FORMS001Form not found
FORMS002Submission not found
FORMS003Validation failed
FORMS004File upload failed
FORMS005File size exceeds limit
FORMS006Invalid file type
FORMS007Form is inactive
FORMS008Submission limit reached
FORMS009Duplicate submission detected

Rate Limits​

PlanRequests/minuteFormsSubmissions/month
Free60101,000
Starter3005010,000
Pro1,000200100,000
EnterpriseCustomUnlimitedUnlimited

Use This Block with AI Agents​

This block ships an official Claude Code plugin from the public 23blocks marketplace (19 plugins, 205 skills). Your agent gets full working knowledge of this API — endpoints, identity registration, and conventions.

# one-time: add the 23blocks marketplace
claude plugin marketplace add https://github.com/23blocks-OS/ai-agents

# install this block's plugin
claude plugin install forms-block

Configure BLOCKS_API_URL, BLOCKS_API_KEY, and BLOCKS_AUTH_TOKEN. Register identity first: each block is autonomous — register the user with this block's identity endpoint before private calls (only user_unique_id is required; email/phone are optional notification-routing fields).

Full reference: AI Agents & Claude Code Plugins · github.com/23blocks-OS/ai-agents