AI Summary
WPForms 1.9.9 introduced a read-only REST API built on top of the WordPress Abilities API. You can list forms, fetch form configuration, retrieve and search entries, and pull form statistics from any HTTP client, the command line, your own PHP code, or AI assistants that speak the Model Context Protocol (MCP).
If you searched for “WPForms REST API” and landed here, this is it. There is no separate REST API; the Abilities API integration is how WPForms exposes its data over HTTP.
What Is the Abilities API
The Abilities API is a WordPress core feature added in WordPress 6.9. It lets plugins declare individual capabilities (called abilities) with a name, an input schema, an output schema, and a permission callback. WordPress then exposes every registered ability automatically over the REST API at /wp-json/wp-abilities/v1/abilities/<ability>/run and to MCP-compatible AI clients through the official MCP adapter plugin.
WPForms registers a set of read-only abilities under the wpforms/ namespace. Each ability runs the same WPForms capability checks used in the admin (wpforms_current_user_can()), so the REST and MCP surfaces inherit the existing permission model rather than introducing a new one.
Requirements:
- WordPress 6.9 or later
- WPForms Lite or Pro 1.9.9 or later (some abilities are Pro only; see the reference table below)
- For MCP clients: the wordpress/mcp-adapter plugin
Calling an Ability
Every ability can be invoked through two transports. The result is identical; pick whichever fits the calling environment.
REST API
Send an authenticated GET request to /wp-json/wp-abilities/v1/abilities/<ability>/run. Because every WPForms ability is read-only, only GET is accepted; POST returns 405 Method Not Allowed.
Note: Pass parameters as bracketed query string fields under the input key, for example input[limit]=10&input[status]=publish. URL-encode the brackets if your client does not do it automatically (%5B for [, %5D for ]).
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/list-forms/run?input%5Blimit%5D=10&input%5Bstatus%5D=publish"
PHP
From any plugin, theme, or custom code that runs after the wp_abilities_api_init action has fired, fetch the ability with wp_get_ability() and call its execute() method. Pass the input as an associative array of parameters (the same names listed in each ability’s parameters table).
$ability = wp_get_ability( 'wpforms/list-forms' );
if ( $ability ) {
$result = $ability->execute(
[
'limit' => 10,
'status' => 'publish',
]
);
if ( is_wp_error( $result ) ) {
// Handle error.
return;
}
// $result['forms'] array of form summaries
// $result['total'] total count (integer)
}
Authentication
The REST transport uses standard WordPress authentication. The recommended method for external clients is Application Passwords, which are built into WordPress core and do not require any extra plugin.
Generating an Application Password
- Sign in as the WordPress user whose permissions the calls should run under.
- Go to Users » Profile and scroll to the Application Passwords section.
- Enter a name for the integration and click Add New Application Password.
- Copy the generated password. WordPress only shows it once.
For a deeper reference, including REST endpoints for managing application passwords programmatically, see the WordPress core team’s Application Passwords Integration Guide.
Sending the Credentials
Pass the username and application password as HTTP Basic authentication on every request.
With curl
Set your site URL as an environment variable so the examples in this doc are runnable as-is:
export WP_SITE="https://your-wordpress-site.com"
Then add the -u flag to every curl command. The flag’s value is your username, followed by a colon, followed by your application password (no spaces).
With Postman, Insomnia, or other clients
Set the request’s Auth type to Basic Auth and provide your username and application password. The client handles the encoding for you.
Setting the header manually
Send your credentials as a base64-encoded Authorization header:
Combine your username and application password into a single string, separated by a colon (no spaces), and base64-encode the result using a tool of your choice (base64 command, an online encoder, or your language’s standard library). Send the encoded value on every request as the Authorization header, in the form Authorization: Basic <encoded>.
The request examples in the rest of this doc omit the authentication flag for readability. Add the -u flag (or the Authorization header) to every real request, or the API returns 401 Unauthorized.
Permissions
Each ability checks a specific WPForms capability before executing. Failed checks return a WP_Error with HTTP status 403.
| Ability | Capability |
|---|---|
wpforms/list-forms | view_forms |
wpforms/get-form | view_form_single |
wpforms/get-form-stats (Lite) | view_form_single |
wpforms/get-form-stats (Pro) | view_entries_form_single |
wpforms/get-entry-summaries | view_entries_form_single |
wpforms/get-entry | view_entry_single |
wpforms/search-entries (with form_id) | view_entries_form_single |
wpforms/search-entries (without form_id) | view_entries |
Ability Reference
All abilities are read-only and idempotent. Errors are returned as WP_Error objects serialized to JSON with code, message, and data.status fields.
wpforms/list-forms
List forms with summary metadata. Available in Lite and Pro.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
status | string | No | publish | Form status. One of publish, draft, trash. |
limit | integer | No | 20 | Maximum number of forms to return. Range 1 to 100. |
offset | integer | No | 0 | Number of forms to skip. |
Example Request
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/list-forms/run?input%5Blimit%5D=10&input%5Bstatus%5D=publish"
Example Response
{
"forms": [
{
"id": 123,
"title": "Contact Form",
"status": "publish",
"created": "2026-01-27 10:00:00",
"modified": "2026-02-15 14:30:00",
"author": 1
}
],
"total": 5
}
wpforms/get-form
Retrieve a single form, including a curated subset of its settings and, optionally, its field configuration. Available in Lite and Pro.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
form_id | integer | Yes | — | The ID of the form to retrieve. |
include_fields | boolean | No | true | Include the form’s field configuration in the response. |
Example Request
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/get-form/run?input%5Bform_id%5D=123&input%5Binclude_fields%5D=true"
Example Response
{
"id": 123,
"title": "Contact Form",
"status": "publish",
"created": "2026-01-27 10:00:00",
"modified": "2026-02-15 14:30:00",
"author": 1,
"settings": {
"form_title": "Contact Form",
"form_desc": "Get in touch with us",
"submit_text": "Submit",
"ajax_submit": true,
"honeypot": true,
"antispam": true
},
"fields": [
{
"id": 1,
"type": "text",
"label": "Name",
"description": "",
"required": true,
"size": "medium"
}
]
}
The settings object returned by this ability is a curated, non-sensitive subset (title, description, submit text, AJAX submit flag, honeypot, anti-spam). Notification, confirmation, and integration settings are not exposed.
wpforms/get-form-stats
Return submission statistics for a form. The response shape differs between Lite and Pro.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
form_id | integer | Yes | — | The ID of the form. |
Example Request
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/get-form-stats/run?input%5Bform_id%5D=123"
Lite Response
{
"form_id": 123,
"entries_available": false,
"message": "Entry statistics require WPForms Pro. Upgrade to access detailed form submission data."
}
Pro Response
{
"form_id": 123,
"total_entries": 156,
"unread_entries": 12,
"starred_entries": 8,
"entries_available": true
}
wpforms/get-entry-summaries
Paginated list of entry summaries for a single form. Pro only.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
form_id | integer | Yes | — | The ID of the form to fetch entries for. |
status | string | No | "" | One of partial, abandoned, spam, trash. Empty returns all completed entries. |
type | string | No | "" | One of read, unread, starred. |
include_fields | boolean | No | false | Include each entry’s field values in the response. |
limit | integer | No | 20 | Maximum number of entries to return. Range 1 to 100. |
offset | integer | No | 0 | Number of entries to skip. |
Example Request
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/get-entry-summaries/run?input%5Bform_id%5D=123&input%5Btype%5D=unread&input%5Blimit%5D=20"
Example Response
{
"entries": [
{
"id": 456,
"form_id": 123,
"date": "2026-02-15 14:32:10",
"status": "",
"viewed": false,
"starred": true
}
],
"total": 15,
"form_id": 123
}
wpforms/get-entry
Retrieve a single entry by ID, including all field values. Pro only.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
entry_id | integer | Yes | — | The ID of the entry to retrieve. |
include_fields | boolean | No | true | Include the entry’s field values in the response. |
Example Request
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/get-entry/run?input%5Bentry_id%5D=456"
Example Response
{
"id": 456,
"form_id": 123,
"date": "2026-02-15 14:32:10",
"modified": "2026-02-15 15:00:00",
"status": "",
"viewed": true,
"starred": false,
"ip_address": "192.168.1.100",
"fields": [
{
"id": 1,
"name": "Name",
"value": "John Doe",
"type": "text"
}
]
}
The IP address in the response can be masked. Add
add_filter( 'wpforms_abilities_mask_ip_address', '__return_true' )to your site’s code; when enabled, IPv4 addresses appear with their last three octets replaced by asterisks (for example,***.***.***.100).
wpforms/search-entries
Search entries across one form or all forms with full-text, field-specific, status, and date range filters. Pro only.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
form_id | integer | No | — | Restrict the search to a single form. Omit to search across all forms. |
search | string | No | "" | Full-text query matched against all entry fields. |
field_id | integer | No | — | Restrict the search to a specific field ID. Use with field_value. |
field_value | string | No | — | Exact value to match in the field specified by field_id. |
date_from | string | No | — | Start of date range, format YYYY-MM-DD. |
date_to | string | No | — | End of date range, format YYYY-MM-DD. |
status | string | No | "" | One of partial, abandoned, spam, trash. |
type | string | No | "" | One of read, unread, starred. |
include_fields | boolean | No | true | Include entry field values in the response. |
limit | integer | No | 20 | Maximum number of entries per page. Range 1 to 100. |
page | integer | No | 1 | Page number. Note that this ability uses page-based pagination, unlike list-forms and get-entry-summaries, which use offset. |
orderby | string | No | date | One of entry_id, date, status. |
order | string | No | DESC | One of ASC, DESC. |
Example Request
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/search-entries/run?input%5Bform_id%5D=5&input%5Bsearch%5D=john%40example.com&input%5Bpage%5D=1&input%5Blimit%5D=20"
Example Response
{
"entries": [
{
"id": 142,
"form_id": 5,
"date": "2026-02-15 14:32:10",
"status": "",
"viewed": false,
"starred": true,
"fields": [
{ "id": 1, "name": "Name", "value": "John Doe", "type": "text" },
{ "id": 2, "name": "Email", "value": "[email protected]", "type": "email" }
]
}
],
"total": 47,
"total_pages": 5,
"page": 1,
"limit": 20
}
Using WPForms With MCP Clients
Every WPForms ability is registered with mcp.public set to true, which means MCP-compatible AI clients (Claude Desktop, Cursor, and others) discover them automatically once the WordPress site is connected through the wordpress/mcp-adapter plugin. After install, no further WPForms-side configuration is required; abilities appear in the client’s tool list under the WPForms category and respect the same permission callbacks used by the REST API.
Discovering Abilities Programmatically
To enumerate the abilities available on a site instead of hard-coding their IDs:
# List all registered abilities on the site
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities"
# Fetch the schema for a single ability
curl "$WP_SITE/wp-json/wp-abilities/v1/abilities/wpforms/list-forms"
The response includes each ability’s ID, label, description, category, and full input and output schemas, which is enough information to build a generic client without prior knowledge of the WPForms-specific surface.
Related Links
- Introducing the WordPress Abilities API (developer.wordpress.org)
- wordpress/mcp-adapter on GitHub
- Model Context Protocol