Endpoints for form submissions — both public submission and admin retrieval.
POST /formforge/v1/forms/{id}/submit
This route returns HTTP501 Not Implemented and does not accept submissions.
Submissions go through the AJAX handler (wp_ajax_formforge_submit /
wp_ajax_nopriv_formforge_submit), which enforces nonce verification,
structural anti-spam (honeypot, timing, HMAC token), file uploads, payment
intents, and all integrations — guards a tokenless REST POST cannot satisfy.
Use the AJAX path below.
AJAX Submission (the supported path for frontend forms):const formEl = document.querySelector( '.formforge-form' );
const formData = new FormData( formEl );
formData.append( 'action', 'formforge_submit' );
fetch( formforgeFront.ajaxUrl, {
method: 'POST',
body: formData
} )
.then( r => r.json() )
.then( data => {
if ( data.success ) {
console.log( 'Success:', data.data.message );
if ( data.data.redirect ) {
window.location.href = data.data.redirect;
}
} else {
console.error( 'Error:', data.data.message );
// data.data.errors is a list of messages, data.data.field_id names the first field that failed
}
} );{
"success": true,
"data": {
"message": "Thank you! We will get back to you within 24 hours.",
"redirect": "",
"actions": [],
"submit_action": "message"
}
}When the form’s After submit setting is message, the bundled frontend renders a single completion state, hides the completed form controls, and resets non-payment forms after the saved submission succeeds. Payment forms lock the completed controls instead of clearing the captured payment context.
When the setting is redirect, redirect contains a root-relative or same-site URL and the bundled frontend navigates immediately instead of rendering a success-message delay. When the setting is custom_js, Fillin Forge does not return raw JavaScript; it returns a safe structured action list such as:
{
"actions": [
{
"type": "add_class",
"selector": "#modal",
"value": "is-active"
}
]
}The frontend runner only supports add_class, remove_class, and toggle_class on ID or class selectors. The server rejects arbitrary script execution, external requests, cookie/storage access, assignments, eval, and markup injection.
{
"success": false,
"data": {
"message": "Email must be a valid email.",
"errors": [
"Email must be a valid email."
],
"field_id": "field_2"
}
}message joins the messages with <br>. errors is a list of messages, not an object keyed by field. field_id is the id of the first field that failed, when there is one.
There is no PHP method that takes a form id and values and saves a submission. The handler reads the request and answers in JSON, and it checks the nonce and the anti-spam first. To react to a saved submission, listen to formforge/submission_created (see Submission Hooks).
GET /formforge/v1/submissions/{form_id}
Get submissions for a form. Requires manage_options. Returns up to 100 most recent submissions ordered by date descending. The test submissions sent from the form builder are left out; add ?status=test to get only those. Abandoned drafts of the Pro tracking are in the list with the status abandoned. Each row is the table row as it is stored, so the numbers are strings.
curl -s -u "admin:XXXX XXXX XXXX XXXX" \
https://example.com/wp-json/formforge/v1/submissions/1[
{
"id": "42",
"form_id": "1",
"data": {
"field_1": {
"label": "Name",
"value": "John Doe",
"type": "text"
},
"field_2": {
"label": "Email",
"value": "[email protected]",
"type": "email"
}
},
"ip_address": "203.0.113.50",
"user_agent": "Mozilla/5.0 ...",
"user_id": "0",
"status": "new",
"session_id": "",
"payment_status": "",
"created_at": "2025-01-20 14:35:22"
}
]Admin AJAX: PDF and Delete Actions
The Submissions screen uses admin AJAX for per-submission PDF download and deletion:
| Action | Method | Capability | Nonce | Response |
|---|---|---|---|---|
formforge_download_pdf | GET | manage_options | formforge_pdf via nonce | application/pdf attachment named submission-{id}.pdf |
formforge_delete_submission | POST | manage_options | formforge_delete_submission_{id} via _wpnonce | JSON success with { "deleted": id } |
Delete also removes any private files attached to that submission from uploads/formforge-private/. Public form submission continues to use formforge_submit; File Upload is a Free field, while locked PRO field types are skipped or rejected server-side after a downgrade.
—