Forms API

10 min read

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

ParameterTypeDefaultDescription
pageinteger1Page number
per_pageinteger25Results per page (max 100)
statusstringallFilter by status: published, draft, archived
searchstringnoneSearch 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

ParameterTypeDescription
idstringThe 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

StatusCodeDescription
401UNAUTHENTICATEDNo API key was provided
401KEY_INVALIDThe key is wrong, revoked, or expired
403INSUFFICIENT_SCOPEThe key lacks the scope this endpoint requires
403PLAN_REQUIREDAPI access requires a Pro or higher plan
404NOT_FOUNDForm ID does not exist
415UNSUPPORTED_MEDIA_TYPEThe request was not sent as application/json
422VALIDATION_ERRORInvalid field type, missing required property, or malformed JSON
429RATE_LIMITEDToo many requests: see Rate Limits
$37 · paid once

Ready to Build Forms That Actually Convert?

Start free and keep the five forms for good, or pay once and unlock all of it — unlimited forms, ten team members, AI, CRM, white label and the API. No renewal, ever.

14-day money-backInstant accessNo subscription, ever
Forms API