API Reference
Complete documentation for all FormLeap API endpoints with request and response examples.
Base URL
https://formleap.app/api/v1
All endpoints are relative to this base URL. See API Overview for authentication and error handling.
Forms
List Forms
Get all forms in your workspace.
GET /forms
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page (max: 100) |
status |
string | - |
Filter by status: draft, published, archived |
Example Request:
curl "https://formleap.app/api/v1/forms?page=1&per_page=20&status=published" \
-H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch('https://formleap.app/api/v1/forms?status=published', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const data = await response.json();
console.log(data.data); // Array of forms
Example Response:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"workspace_id": "660e8400-e29b-41d4-a716-446655440000",
"name": "Contact Form",
"description": "Website contact form",
"status": "published",
"submission_count": 42,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-20T14:22:00Z",
"published_at": "2025-01-15T11:00:00Z"
},
{
"id": "770e8400-e29b-41d4-a716-446655440000",
"workspace_id": "660e8400-e29b-41d4-a716-446655440000",
"name": "Customer Feedback",
"description": "Post-purchase feedback survey",
"status": "published",
"submission_count": 128,
"created_at": "2025-01-10T09:15:00Z",
"updated_at": "2025-01-18T16:45:00Z",
"published_at": "2025-01-10T10:00:00Z"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total_count": 2,
"total_pages": 1
}
}
Get Form
Retrieve a single form with its complete structure.
GET /forms/:id
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Form ID |
Example Request:
curl "https://formleap.app/api/v1/forms/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY"
const formId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(`https://formleap.app/api/v1/forms/${formId}`, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const form = await response.json();
console.log(form.structure); // AST structure
Example Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"workspace_id": "660e8400-e29b-41d4-a716-446655440000",
"name": "Contact Form",
"description": "Website contact form",
"status": "published",
"structure": {
"type": "form",
"attrs": {
"name": "Contact Form"
},
"children": [
{
"type": "step",
"attrs": {
"title": "Your Information"
},
"children": [
{
"type": "text",
"attrs": {
"id": "name",
"label": "Full Name",
"required": true
},
"children": []
},
{
"type": "email",
"attrs": {
"id": "email",
"label": "Email Address",
"required": true
},
"children": []
},
{
"type": "textarea",
"attrs": {
"id": "message",
"label": "Message",
"required": true
},
"children": []
}
]
}
]
},
"settings": {
"access": "public",
"confirmation_message": "Thank you for your message!",
"notification_email": "team@example.com"
},
"submission_count": 42,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-20T14:22:00Z",
"published_at": "2025-01-15T11:00:00Z"
}
Create Form
Create a new form from an AST structure.
POST /forms
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
structure |
object | Yes | Form AST structure |
publish |
boolean | No | Publish immediately (default: false) |
Example Request:
curl -X POST "https://formleap.app/api/v1/forms" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"structure": {
"type": "form",
"attrs": {
"name": "Newsletter Signup",
"description": "Subscribe to our newsletter"
},
"children": [
{
"type": "step",
"attrs": {
"title": "Subscribe"
},
"children": [
{
"type": "email",
"attrs": {
"id": "email",
"label": "Email Address",
"required": true
},
"children": []
},
{
"type": "yes_no",
"attrs": {
"id": "consent",
"label": "I agree to receive emails",
"required": true
},
"children": []
}
]
}
]
},
"publish": true
}'
const newForm = {
structure: {
type: 'form',
attrs: {
name: 'Newsletter Signup',
description: 'Subscribe to our newsletter'
},
children: [
{
type: 'step',
attrs: { title: 'Subscribe' },
children: [
{
type: 'email',
attrs: {
id: 'email',
label: 'Email Address',
required: true
},
children: []
},
{
type: 'yes_no',
attrs: {
id: 'consent',
label: 'I agree to receive emails',
required: true
},
children: []
}
]
}
]
},
publish: true
};
const response = await fetch('https://formleap.app/api/v1/forms', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(newForm)
});
const form = await response.json();
console.log('Form created:', form.id);
console.log('Public URL:', form.public_url);
Example Response:
{
"id": "880e8400-e29b-41d4-a716-446655440000",
"workspace_id": "660e8400-e29b-41d4-a716-446655440000",
"name": "Newsletter Signup",
"description": "Subscribe to our newsletter",
"status": "published",
"structure": { ... },
"public_url": "https://formleap.app/f/880e8400-e29b-41d4-a716-446655440000",
"builder_url": "https://formleap.app/forms/880e8400-e29b-41d4-a716-446655440000",
"created_at": "2025-01-21T10:00:00Z",
"updated_at": "2025-01-21T10:00:00Z",
"published_at": "2025-01-21T10:00:00Z"
}
Validation Errors:
If the AST structure is invalid, you'll receive a 422 Unprocessable Entity response:
{
"error": "validation_error",
"message": "Form structure validation failed",
"errors": [
{
"message": "Missing required attribute: label",
"path": [0, 1]
},
{
"message": "Element IDs must be unique",
"path": [0, 2]
}
]
}
Update Form
Update an existing form's structure.
PUT /forms/:id
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Form ID |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
structure |
object | Yes | Updated form AST structure |
Example Request:
curl -X PUT "https://formleap.app/api/v1/forms/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"structure": {
"type": "form",
"attrs": {
"name": "Updated Contact Form"
},
"children": [ ... ]
}
}'
const formId = '550e8400-e29b-41d4-a716-446655440000';
const updatedStructure = {
structure: {
type: 'form',
attrs: { name: 'Updated Contact Form' },
children: [ /* updated fields */ ]
}
};
const response = await fetch(`https://formleap.app/api/v1/forms/${formId}`, {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(updatedStructure)
});
const updatedForm = await response.json();
Example Response:
Same as Get Form response with updated data.
Delete Form
Delete a form permanently.
DELETE /forms/:id
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Form ID |
Example Request:
curl -X DELETE "https://formleap.app/api/v1/forms/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY"
const formId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(`https://formleap.app/api/v1/forms/${formId}`, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
if (response.status === 204) {
console.log('Form deleted successfully');
}
Example Response:
204 No Content
Note: Deleting a form also deletes all associated submissions. This action cannot be undone.
Submissions
List Submissions
Get all submissions for a specific form.
GET /forms/:form_id/submissions
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
form_id |
UUID | Form ID |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page (max: 100) |
status |
string | - |
Filter by status: completed, incomplete |
Example Request:
curl "https://formleap.app/api/v1/forms/550e8400-e29b-41d4-a716-446655440000/submissions?status=completed" \
-H "Authorization: Bearer YOUR_API_KEY"
const formId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://formleap.app/api/v1/forms/${formId}/submissions?status=completed`,
{
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(`${data.pagination.total_count} submissions`);
Example Response:
{
"data": [
{
"id": "990e8400-e29b-41d4-a716-446655440000",
"form_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"answers": {
"name": "John Doe",
"email": "john@example.com",
"message": "I love your product!"
},
"metadata": {
"fields": {
"name": {
"label": "Full Name",
"type": "text",
"required": true
},
"email": {
"label": "Email Address",
"type": "email",
"required": true
},
"message": {
"label": "Message",
"type": "textarea",
"required": true
}
},
"form_name": "Contact Form",
"reference": {
"source": "website",
"page": "/contact"
}
},
"completed_at": "2025-01-20T14:30:00Z",
"created_at": "2025-01-20T14:28:00Z"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total_count": 42,
"total_pages": 3
}
}
Get Submission
Retrieve a single submission with full details.
GET /submissions/:id
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Submission ID |
Example Request:
curl "https://formleap.app/api/v1/submissions/990e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY"
const submissionId = '990e8400-e29b-41d4-a716-446655440000';
const response = await fetch(`https://formleap.app/api/v1/submissions/${submissionId}`, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const submission = await response.json();
console.log(submission.answers);
Example Response:
Same structure as individual submission in List Submissions.
Search Submissions
Search submissions across all forms using full-text search.
GET /submissions/search
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
q |
string | Yes | Search query |
form_id |
UUID | No | Limit to specific form |
page |
integer | No | Page number (default: 1) |
per_page |
integer | No | Items per page (default: 20) |
Example Request:
curl "https://formleap.app/api/v1/submissions/search?q=urgent&form_id=550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY"
const searchQuery = 'urgent customer';
const formId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://formleap.app/api/v1/submissions/search?q=${encodeURIComponent(searchQuery)}&form_id=${formId}`,
{
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
}
);
const results = await response.json();
console.log(`Found ${results.data.length} matching submissions`);
Example Response:
Same structure as List Submissions, but results are ranked by relevance.
Search Features:
- Weighted Results - Subject field matches rank highest
- Stemming - "running" matches "run"
- Multiple Terms - All terms must be present
AST Structure Reference
Forms are represented as Abstract Syntax Trees (AST) using nested tuples. The API accepts and returns this structure as JSON.
Form Node
{
"type": "form",
"attrs": {
"name": "Form Name",
"description": "Optional description"
},
"children": [ /* step nodes */ ]
}
Step Node
{
"type": "step",
"attrs": {
"title": "Step Title",
"description": "Optional step description",
"layout": "stack"
},
"children": [ /* element nodes */ ]
}
Input Element Node
{
"type": "text",
"attrs": {
"id": "unique_id",
"label": "Field Label",
"placeholder": "Optional placeholder",
"help_text": "Optional help text",
"required": true,
"col_span": 1
},
"children": []
}
Supported Element Types
Input Types:
-
text- Single-line text -
textarea- Multi-line text -
email- Email address -
phone- Phone number -
url- Website URL -
number- Numeric input -
date- Date picker -
time- Time picker -
datetime- Date and time -
dropdown- Single select -
radio- Radio buttons -
multiple_choice- Checkboxes -
yes_no- Boolean toggle -
file_upload- File upload
Content Types:
-
heading- Section heading -
paragraph- Text content -
divider- Visual separator
Composite Type:
-
composite- Grouped fields (can contain children)
Selection Elements
For dropdown, radio, and multiple_choice, include options:
{
"type": "dropdown",
"attrs": {
"id": "country",
"label": "Country",
"required": true,
"options": ["United States", "Canada", "United Kingdom"]
},
"children": []
}
Composite Elements
Composite elements group related fields:
{
"type": "composite",
"attrs": {
"id": "address",
"label": "Mailing Address",
"layout": "grid_2",
"repeatable": false
},
"children": [
{
"type": "text",
"attrs": { "id": "street", "label": "Street", "col_span": 2 },
"children": []
},
{
"type": "text",
"attrs": { "id": "city", "label": "City" },
"children": []
},
{
"type": "text",
"attrs": { "id": "postal", "label": "Postal Code" },
"children": []
}
]
}
Composite Layouts:
-
stack- Vertical (default) -
row- Horizontal -
grid_2- 2-column grid -
grid_3- 3-column grid -
grid_4- 4-column grid
Rate Limiting
See API Overview for rate limit details.
All responses include rate limit headers:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 285
X-RateLimit-Reset: 1642694400
Error Responses
See API Overview for complete error handling documentation.
Common Errors:
| Status | Error Code | Description |
|---|---|---|
| 400 |
bad_request |
Invalid request format |
| 401 |
unauthorized |
Invalid API key |
| 404 |
not_found |
Resource doesn't exist |
| 422 |
validation_error |
Data validation failed |
| 429 |
rate_limit_exceeded |
Too many requests |
Next Steps
- API Overview - Authentication and getting started
- MCP Integration - AI-powered form creation
- Webhooks - Real-time event notifications
Questions? Contact support@formleap.app