Forms API
The Forms API lets you create, retrieve, update, and delete forms programmatically. All endpoints require an API key with the appropriate scope.
Base URL: https://wittyform.com/api/v1
List forms
GET /api/v1/forms
Returns all forms in your workspace. Requires read scope.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Results per page (max 100) |
status | string | all | Filter by status: published, draft, archived |
search | string | none | Search forms by title |
Example request
curl -X GET "https://wittyform.com/api/v1/forms?page=1&per_page=10&status=published" \
-H "Authorization: Bearer wf_live_abc123"Example response
{
"success": true,
"data": {
"forms": [
{
"id": "b3f1c2d4-1a2b-4c3d-9e8f-001122334455",
"title": "Contact Form",
"description": null,
"status": "published",
"fields": [],
"settings": {},
"short_id": "a1b2c3d4",
"created_at": "2025-06-01T10:00:00.000Z",
"updated_at": "2025-09-10T08:30:00.000Z",
"published_at": "2025-06-02T09:00:00.000Z"
},
{
"id": "c4e2d3f5-2b3c-4d5e-af90-112233445566",
"title": "Feedback Survey",
"description": null,
"status": "published",
"fields": [],
"settings": {},
"short_id": "e5f6g7h8",
"created_at": "2025-07-15T14:00:00.000Z",
"updated_at": "2025-09-12T11:20:00.000Z",
"published_at": "2025-07-15T15:00:00.000Z"
}
],
"pagination": {
"total": 2,
"page": 1,
"per_page": 10,
"total_pages": 1
}
}
}Get a form
GET /api/v1/forms/:id
Returns the full details of a single form including its field definitions. Requires read scope.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The form ID, a UUID (e.g., b3f1c2d4-1a2b-4c3d-9e8f-001122334455) |
Example request
curl -X GET "https://wittyform.com/api/v1/forms/b3f1c2d4-1a2b-4c3d-9e8f-001122334455" \
-H "Authorization: Bearer wf_live_abc123"Example response
{
"success": true,
"data": {
"form": {
"id": "b3f1c2d4-1a2b-4c3d-9e8f-001122334455",
"title": "Contact Form",
"description": null,
"status": "published",
"short_id": "a1b2c3d4",
"created_at": "2025-06-01T10:00:00.000Z",
"updated_at": "2025-09-10T08:30:00.000Z",
"published_at": "2025-06-02T09:00:00.000Z",
"fields": [
{
"id": "9a1b2c3d-4e5f-4061-8273-8495a6b7c8d9",
"type": "short_text",
"label": "Full Name",
"required": true,
"placeholder": "Enter your name"
},
{
"id": "1f2e3d4c-5b6a-4798-9a8b-7c6d5e4f3a2b",
"type": "email",
"label": "Email",
"required": true,
"placeholder": "[email protected]"
},
{
"id": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
"type": "long_text",
"label": "Message",
"required": false,
"placeholder": "How can we help?"
}
],
"settings": {
"redirect_url": null,
"confirmation_message": "Thanks for reaching out!",
"notifications_enabled": true
}
}
}
}Create a form
POST /api/v1/forms
Creates a new form. Requires write scope.
Request body
New forms are always created as a draft. Provide a title (required), and optionally a description, fields, and settings. Send the request with Content-Type: application/json: other content types are rejected with a 415 response (UNSUPPORTED_MEDIA_TYPE).
{
"title": "Job Application",
"description": "Apply for the open role",
"fields": [
{
"type": "short_text",
"label": "Full Name",
"required": true
},
{
"type": "email",
"label": "Email Address",
"required": true
},
{
"type": "file_upload",
"label": "Resume",
"required": true,
"allowed_types": ["pdf", "docx"],
"max_size_mb": 10
},
{
"type": "long_text",
"label": "Cover Letter",
"required": false
}
],
"settings": {
"confirmation_message": "Thank you for applying!",
"notifications_enabled": true
}
}Idempotent creates
To make a create safe to retry, send an Idempotency-Key header with a unique value (a UUID works well). If the request reaches WittyForm but your client never sees the response (a dropped connection, a timeout), retry with the same key: instead of creating a second form, the API replays the original response and adds an Idempotent-Replayed: true header. Reusing the same key with a different request body returns 422 (VALIDATION_ERROR). Keys are remembered for 24 hours, after which the same value starts a fresh request.
Example request
curl -X POST "https://wittyform.com/api/v1/forms" \
-H "Authorization: Bearer wf_live_abc123" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7b9c1d2e-3f40-4a51-8b62-9c0d1e2f3a4b" \
-d '{
"title": "Job Application",
"fields": [
{ "type": "short_text", "label": "Full Name", "required": true },
{ "type": "email", "label": "Email Address", "required": true }
]
}'Example response (201 Created)
{
"success": true,
"data": {
"form": {
"id": "d5f3e4a6-3c4d-4e6f-b0a1-223344556677",
"title": "Job Application",
"description": "Apply for the open role",
"status": "draft",
"short_id": "n3w1d2e3",
"created_at": "2025-09-15T16:00:00.000Z",
"updated_at": "2025-09-15T16:00:00.000Z",
"published_at": null,
"fields": [
{ "id": "9a1b2c3d-4e5f-4061-8273-8495a6b7c8d9", "type": "short_text", "label": "Full Name", "required": true },
{ "id": "1f2e3d4c-5b6a-4798-9a8b-7c6d5e4f3a2b", "type": "email", "label": "Email Address", "required": true }
],
"settings": {}
}
}
}Update a form
PUT /api/v1/forms/:id
Updates an existing form. Requires write scope. Despite the PUT verb, this is a partial (PATCH-like) update: send only the fields you want to change (title, description, fields, settings, status). Any field you omit is preserved, not cleared.
Example request
curl -X PUT "https://wittyform.com/api/v1/forms/b3f1c2d4-1a2b-4c3d-9e8f-001122334455" \
-H "Authorization: Bearer wf_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Contact Form",
"status": "published",
"settings": {
"redirect_url": "https://example.com/thank-you"
}
}'Example response (200 OK)
{
"success": true,
"data": {
"form": {
"id": "b3f1c2d4-1a2b-4c3d-9e8f-001122334455",
"title": "Updated Contact Form",
"status": "published",
"updated_at": "2025-09-15T17:00:00.000Z",
"settings": {
"redirect_url": "https://example.com/thank-you",
"confirmation_message": "Thanks for reaching out!",
"notifications_enabled": true
}
}
}
}Delete a form
DELETE /api/v1/forms/:id
Permanently deletes a form and all its responses. Requires admin scope. This action cannot be undone.
Example request
curl -X DELETE "https://wittyform.com/api/v1/forms/b3f1c2d4-1a2b-4c3d-9e8f-001122334455" \
-H "Authorization: Bearer wf_live_abc123"Example response (204 No Content)
An empty response body with status 204 indicates success.
Error codes
| Status | Code | Description |
|---|---|---|
401 | UNAUTHENTICATED | No API key was provided |
401 | KEY_INVALID | The key is wrong, revoked, or expired |
403 | INSUFFICIENT_SCOPE | The key lacks the scope this endpoint requires |
403 | PLAN_REQUIRED | API access requires a Pro or higher plan |
404 | NOT_FOUND | Form ID does not exist |
415 | UNSUPPORTED_MEDIA_TYPE | The request was not sent as application/json |
422 | VALIDATION_ERROR | Invalid field type, missing required property, or malformed JSON |
429 | RATE_LIMITED | Too many requests: see Rate Limits |