FormForge API
FormForge converts JSON form definitions into beautiful, self-contained HTML forms with built-in CSS, client-side validation, and accessible markup. The API requires no SDK — just a single POST request.
Base URL: https://formforge-api.vercel.app
Version: 1.0.0 | Format: JSON over HTTPS
Authentication
Pass your API key in the Authorization header using Bearer scheme:
Authorization: Bearer ff_live_your_api_key_here
Alternatively, use the X-Api-Key header for legacy clients. Keys always start with ff_live_ (live) or ff_test_ (test).
Unauthenticated requests are allowed on the free anonymous tier (20 forms/day per IP).
Error Responses
All errors return a JSON object with error, code, and an optional details field.
{
"error": "The 'fields' array is required.",
"code": "INVALID_INPUT"
}
| Code | HTTP | Description |
|---|---|---|
| INVALID_INPUT | 400 | Bad request body or missing required field |
| PARSE_ERROR | 400 | Request body is not valid JSON |
| UNAUTHORIZED | 401 | API key missing, invalid, or inactive |
| RATE_LIMITED | 429 | Daily form limit exceeded for your tier |
| INPUT_TOO_LARGE | 413 | Request body exceeds your tier's size limit |
| INTERNAL_ERROR | 500 | Server-side rendering error |
Rate Limits
Limits reset at midnight UTC. Authenticated requests return rate-limit headers on every response:
X-RateLimit-Limit: 20 X-RateLimit-Remaining: 17 X-RateLimit-Reset: 1740787200
| Tier | Forms/day | Input limit | Price |
|---|---|---|---|
| Free (anonymous) | 20 | 50 KB | $0 |
| Free (keyed) | 20 | 50 KB | $0 |
| Builder | 300 | 512 KB | $14/mo |
| Enterprise | Unlimited | 5 MB | $39/mo |
POST /api/json-to-form
Request body
| Field | Type | Description |
|---|---|---|
| fieldsrequired | array | Array of field definition objects (1–100 items). See Field Schema. |
| titleoptional | string | Form heading displayed above the fields. |
| descriptionoptional | string | Subtitle text below the title. |
| themeoptional | string | modern | corporate | playful | minimal. Default: modern. |
| submitUrloptional | string | URL to POST the form data to. If omitted, the form shows a success message on submit without making an HTTP request. |
| submitLabeloptional | string | Label on the submit button. Default: Submit. |
| methodoptional | string | GET | POST. Default: POST. |
| showRequiredoptional | boolean | Show asterisk on required fields. Default: true. |
| stepsoptional | array | Multi-step wizard mode. Each item has title (string) and fields (array). When provided, fields are grouped into wizard steps with Next/Previous navigation. See Multi-Step Forms. |
Responses
{
"html": "<!DOCTYPE html>\n<html lang=\"en\">...",
"meta": {
"theme": "modern",
"fieldCount": 3,
"fieldTypes": ["email", "text", "textarea"],
"title": "Contact Us",
"generatedAt": "2026-02-28T12:00:00.000Z"
}
}
Try it out
POST /api/json-to-embed
Request body
| Field | Type | Description |
|---|---|---|
| fieldsrequired | array | Array of field definition objects (1–100 items). See Field Schema. |
| titleoptional | string | Form heading displayed above the fields. |
| descriptionoptional | string | Subtitle text below the title. |
| themeoptional | string | modern | corporate | playful | minimal. Default: modern. |
| actionoptional | string | URL to submit the form data to. If omitted, the form shows a success message on submit. |
| methodoptional | string | GET | POST. Default: POST. |
| optionsoptional | object | Additional settings: submitText (button label), successMessage, redirectUrl, honeypot (boolean, default true). |
Responses
{
"html": "<!DOCTYPE html>\n<html lang=\"en\">...",
"embedSnippet": "<iframe src=\"data:text/html;base64,...\" ...></iframe>",
"meta": {
"fieldCount": 3,
"requiredFields": ["name", "email"],
"estimatedHeight": 420,
"validationRules": 4,
"generatedAt": "2026-02-28T12:00:00.000Z"
}
}
Try it out
POST /api/signup
Request body
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Valid email address. Maximum 3 active keys per address. |
Responses
{
"message": "API key created successfully. Save this key — it will not be shown again.",
"api_key": "ff_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"tier": "free",
"email": "[email protected]",
"rate_limit": {
"forms_per_day": 20,
"max_input_bytes": 51200
}
}
Field Schema
Each item in the fields array supports the following properties:
| Property | Type | Description |
|---|---|---|
| namerequired | string | Unique field identifier used as the HTML name attribute. |
| typerequired | string | Field type. See Field Types. |
| labelrequired | string | Human-readable label displayed above the field. |
| required | boolean | If true, the field is validated as non-empty on submit. |
| placeholder | string | Placeholder text inside the input (not for checkbox/radio). |
| helpText | string | Small helper text shown below the field. |
| options | string[] | Required for select and radio. Optional for checkbox (creates a multi-select group). |
| value | string | Default/pre-filled value. |
| min / max | number|string | Min/max value for number and date fields. |
| minLength / maxLength | number | Character limits for text and textarea. |
| pattern | string | Regex pattern for custom input validation. |
| disabled | boolean | Renders the field in a disabled state. |
| readonly | boolean | Renders the field as read-only. |
| autocomplete | string | HTML autocomplete hint (e.g. email, name). |
Themes
The theme property controls the visual style of the generated form. All themes are self-contained CSS — no external fonts or stylesheets are loaded.
| Theme | Description | Accent color |
|---|---|---|
| modern | Clean, minimal. System sans-serif font, 8px border radius. Good default for most products. | #10b981 (emerald) |
| corporate | Professional blue. Tighter radius, bold labels. Suitable for B2B and SaaS dashboards. | #1d4ed8 (blue) |
| playful | Rounded, colorful. Cursive font stack, large radius, purple accent. Great for consumer apps. | #8b5cf6 (violet) |
| minimal | Borderless, spacious. Monospace labels, bottom-border-only inputs, uppercase accents. Ultra-clean aesthetic for developer tools and modern apps. | #2563eb (blue) |
Field Types
| Type | HTML element | Notes |
|---|---|---|
| text | <input type="text"> | Supports minLength, maxLength, pattern |
| <input type="email"> | Validates email format on blur and submit | |
| number | <input type="number"> | Supports min, max |
| textarea | <textarea> | Resizable. Supports minLength, maxLength |
| select | <select> | Requires options array. Renders a blank placeholder option |
| checkbox | <input type="checkbox"> | No options: single toggle. With options: multi-select group |
| radio | <input type="radio"> | Requires options array. Single-select group |
| date | <input type="date"> | Browser date picker. Supports min, max as YYYY-MM-DD strings |
| tel | <input type="tel"> | Validates phone number format |
| url | <input type="url"> | Validates URL format (requires https://) |
Multi-Step Forms
Use the steps parameter instead of (or alongside) fields to create wizard-style multi-step forms with a progress indicator and Next/Previous navigation.
steps is not provided, the API behaves exactly as before with a flat fields array. Maximum 20 steps, 100 total fields across all steps.
Step schema
| Property | Type | Description |
|---|---|---|
| titlerequired | string | Step title shown in the progress indicator. |
| fieldsrequired | array | Array of field objects for this step. Same schema as top-level fields. |
Example request
{
"title": "Registration",
"theme": "modern",
"steps": [
{
"title": "Personal Info",
"fields": [
{ "name": "name", "type": "text", "label": "Full Name", "required": true },
{ "name": "dob", "type": "date", "label": "Date of Birth" }
]
},
{
"title": "Contact",
"fields": [
{ "name": "email", "type": "email", "label": "Email", "required": true },
{ "name": "phone", "type": "tel", "label": "Phone" }
]
},
{
"title": "Preferences",
"fields": [
{ "name": "plan", "type": "radio", "label": "Plan", "options": ["Free", "Pro", "Team"], "required": true },
{ "name": "terms", "type": "checkbox", "label": "I agree to the Terms", "required": true }
]
}
]
}
Behavior
- Each step is shown one at a time with a numbered progress indicator at the top.
- The Next button validates the current step's fields before advancing.
- The Previous button navigates back without re-validating.
- The Submit button only appears on the last step.
- On successful submission, the form resets to step 1.
- The response
meta.stepCountfield tells you how many steps were rendered.