API Integration Overview
Overview
The WittyForm API lets you programmatically interact with your forms and submissions. Use it to build custom integrations, automate workflows, embed form data in your own applications, or create submissions from external sources.
API access requires a Pro or higher plan. On the Free tier the API is unavailable and requests return 403 with the error code PLAN_REQUIRED.
Getting Your API Key
- Log in to your WittyForm dashboard.
- Go to Settings.
- Click Generate API Key. Your key will be displayed once: copy it and store it securely.
- If you need to revoke a key, click Revoke next to the key and generate a new one. Revoking a key immediately stops all API requests using that key.
You can generate multiple API keys for different applications or environments (e.g., one for your production app and one for development).
Authentication
All API requests require authentication. Send your API key in either the Authorization header (Bearer scheme) or the X-API-Key header:
Authorization: Bearer wf_live_xxx
# or, equivalently:
X-API-Key: wf_live_xxxRequests without a valid API key receive a 401 response. Passing the key as a URL query parameter (for example ?api_key= or ?key=) is rejected with a 400 response and the error code KEY_INVALID: always use a header.
Base URL
All API endpoints are available at:
https://wittyform.com/apiAll requests must use HTTPS. HTTP requests are rejected.
Common Endpoints
List Forms
Retrieve all forms in your workspace.
GET /v1/formsResponse includes form ID, name, status (published/draft), creation date, and response count.
Get Form Details
Retrieve details about a specific form, including its fields and settings.
GET /v1/forms/:form_idList Responses
Retrieve all submissions for a specific form.
GET /v1/forms/:form_id/responsesSupports pagination with page and per_page query parameters. Results include all submitted field data, submission timestamp, and metadata.
Get Single Response
Retrieve a specific submission by its ID.
GET /v1/forms/:form_id/responses/:response_idCreate Submission
Programmatically submit data to a form. This is useful for creating submissions from external sources or migrating data. Send your field values under an answers object keyed by field ID. The form must be published to accept new responses.
POST /v1/forms/:form_id/responses
Content-Type: application/json
{
"answers": {
"9a1b2c3d-4e5f-4061-8273-8495a6b7c8d9": "Jane Smith",
"1f2e3d4c-5b6a-4798-9a8b-7c6d5e4f3a2b": "[email protected]",
"7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f": "Hello from the API"
}
}Delete Response
Delete a specific submission.
DELETE /v1/forms/:form_id/responses/:response_idPagination
List endpoints return paginated results. Use the following query parameters:
page: The page number (default: 1).per_page: Number of results per page (default: 25, max: 100).
The response includes a pagination object with total, page, per_page, and total_pages fields.
Rate Limits
API requests are rate-limited per API key (not per IP) to ensure fair usage and platform stability:
- Free plan: no API access.
- Pro plan: 1,000 requests per minute.
- Enterprise plan: 5,000 requests per minute.
Rate limit information is included on every response:
X-RateLimit-Limit: Your rate limit ceiling.X-RateLimit-Remaining: Number of requests remaining in the current window.X-RateLimit-Reset: Unix timestamp when the rate limit resets.X-Request-Id: A unique identifier for the request (useful for support).
If you exceed the rate limit, the API returns a 429 Too Many Requests response that also includes a Retry-After header. Wait until the reset time before making more requests.
Error Handling
Successful responses use the envelope { "success": true, "data": { ... } } (status 200, 201 for creates, or 204 with no body for deletes). Every error uses the same envelope shape with a stable code and a human-readable message (some errors also include an error.detail field):
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Form not found"
}
}The full list of error codes and their HTTP statuses:
UNAUTHENTICATED(401): No API key was provided.KEY_INVALID(401; 400 when the key is passed in the URL): The key is wrong, revoked, or supplied as a query parameter.KEY_EXPIRED(401): The key has expired.INSUFFICIENT_SCOPE(403): The key lacks the scope this endpoint requires.PLAN_REQUIRED(403): API access requires a Pro or higher plan.RATE_LIMITED(429): Too many requests; see theRetry-Afterheader.NOT_FOUND(404): The resource does not exist.FORM_NOT_PUBLISHED(422): The form is not published, so it cannot accept responses.FORM_CLOSED(422): The form is closed and no longer accepts responses.RESPONSE_LIMIT_REACHED(403): The form has reached its response limit.VALIDATION_ERROR(422): Invalid or missing field, or malformed body.UNSUPPORTED_MEDIA_TYPE(415): The request was not sent asapplication/json.INTERNAL_ERROR(500): An unexpected server error occurred.
Calling the API from Your Code
The WittyForm API is plain HTTP + JSON, so any HTTP client in any language will work. There is no proprietary SDK to install. Use fetch, axios, Python requests, curl, or whatever you already have. Send your workspace API key in the Authorization: Bearer header and POST/GET against the endpoints documented above.
Best Practices
- Keep your API key secret: Never expose your API key in client-side code or public repositories. Use environment variables to store it.
- Handle rate limits gracefully: Implement exponential backoff when you receive a 429 response.
- Use pagination: Always paginate list requests instead of trying to fetch all records at once.
- Cache when possible: Cache form structure data that does not change frequently to reduce API calls.