Skip to content

REST API

Namespace: ad-form/v1

Base: /wp-json/ad-form/v1

Authentication: WordPress cookie + X-WP-Nonce: wp_rest for admin routes. Application passwords work for the same capability checks.

Discovery

GET /status

Public. Plugin identity only.

GET /system

Capability: manage_ad_form_settings

Forms

GET /forms/schema

Capability: edit_ad_form_forms

Returns JSON Schema for the definition document and the REST resource.

GET /forms/picker

Capability: edit_posts or edit_pages or edit_ad_form_forms or manage_ad_form_forms.

Published forms only (per_page 100, orderby=title ASC). Optional search.

Items are { id, title, slug, shortcode } — no definition, UUID or counts. Used by the Gutenberg block picker.

GET /forms

Capability: edit_ad_form_forms or manage_ad_form_forms

Query: page, per_page (max 100), status, search, orderby (id|title|slug|status|created_at|updated_at|submission_count), order (ASC|DESC)

json
{
  "items": [
    {
      "id": 1,
      "uuid": "...",
      "title": "Contact",
      "slug": "contact",
      "status": "draft",
      "version": 1,
      "created_at": "2026-08-20 09:00:00",
      "updated_at": "2026-08-20 09:00:00",
      "submission_count": 0,
      "shortcode": "[ad_form id=\"1\"]"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20,
  "pages": 1
}

POST /forms

Capability: create_ad_form_forms

Body: title (required), slug, status, definition, starts_at, ends_at

Returns 201 and the full resource. Location header points to the new form.

GET /forms/{id}

Full resource including parsed definition.

PUT / PATCH /forms/{id}

Capability: edit_ad_form_forms

Partial updates. Send version for optimistic locking (409 version_conflict on mismatch). Sending definition replaces the whole definition document.

DELETE /forms/{id}

Capability: delete_ad_form_forms

force=false (default): 409 form_has_entries when submission_count > 0.

force=true: deletes the form and form meta. Submissions are kept.

POST /forms/{id}/duplicate

Capability: create_ad_form_forms

Copies title, definition and creates a draft with a new UUID and slug.

Fields

GET /fields

Capability: edit_ad_form_forms or manage_ad_form_forms

Returns the builder palette: field types, inspector schema, default settings and categories.

json
{
  "items": [
    {
      "type": "text",
      "label": "Text",
      "category": "basic",
      "icon": "editor-textcolor",
      "supports_required": true,
      "default_settings": {},
      "inspector": []
    }
  ],
  "categories": [
    { "id": "basic", "label": "Basic" }
  ]
}

Actions

GET /actions

Capability: edit_ad_form_forms or manage_ad_form_forms

Returns the submit-action catalogue and documented merge tags.

json
{
  "items": [
    {
      "type": "email",
      "label": "Email notification",
      "default_settings": {
        "to": "{admin:email}",
        "subject": "New submission: {form:title}",
        "message": "{all_fields}"
      },
      "inspector": []
    }
  ],
  "merge_tags": [
    { "tag": "{field:key}", "description": "Submitted value for the field with this key." }
  ]
}

Conditions

GET /conditions

Capability: edit_ad_form_forms

Returns operator, effect and logic catalogues for the builder.

json
{
  "operators": [
    { "id": "is", "label": "Is", "needs_value": true }
  ],
  "effects": [
    { "id": "show", "label": "Show this field if" }
  ],
  "logic": [
    { "id": "all", "label": "All rules match" }
  ]
}

Calculations

GET /calculations

Capability: edit_ad_form_forms

Returns formula functions and documented syntax.

json
{
  "functions": [
    { "id": "min", "label": "min", "hint": "min(a, b)" }
  ],
  "syntax": {
    "operators": ["+", "-", "*", "/"],
    "variables": ["{key}", "{field:key}", "key"]
  }
}

Submit

POST /forms/{id}/submit

Public. Body:

json
{
  "nonce": "...",
  "honeypot": "",
  "source": "shortcode",
  "values": {
    "name": "Ada",
    "email": "ada@example.com"
  }
}

The nonce is created with ad_form_submit_{id} (not wp_rest). Filled honeypot fields return a success confirmation without storing an entry and without running submit actions.

Logged-in visitors must also send X-WP-Nonce (wp_rest) because WordPress cookie authentication requires it. The form markup exposes that value as data-wp-rest-nonce. The per-form nonce remains the handler’s authorization.

Success 201:

json
{
  "success": true,
  "confirmation": {
    "type": "message",
    "message": "Thank you. Your message has been sent.",
    "redirect_url": ""
  },
  "submission": {
    "uuid": "..."
  }
}

Validation errors: 400 validation_failed with errors keyed by field key. Unavailable form: 404. Login required: 401. Invalid nonce: 403.

Submissions

Capability: view_ad_form_submissions for reads. Status/star changes need edit_ad_form_submissions. Permanent delete needs delete_ad_form_submissions. manage_ad_form_forms satisfies all three.

GET /submissions

Query: paged or page, per_page (max 100), form_id, view (inbox|unread|read|spam|trash|starred|any; status is an alias), search, orderby (id|created_at|updated_at|status), order.

Inbox (default) is unread + read. Search uses submission_meta, not the JSON payload. List items include a preview string, not the full payload.

json
{
  "items": [
    {
      "id": 1,
      "uuid": "...",
      "form_id": 1,
      "status": "unread",
      "is_starred": false,
      "preview": "ada@example.com",
      "created_at": "2026-08-20 10:00:00"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20,
  "pages": 1,
  "counts": {
    "inbox": 1,
    "unread": 1,
    "read": 0,
    "spam": 0,
    "trash": 0,
    "starred": 0
  }
}

GET /submissions/{id}

Full resource including payload. Opening an unread entry marks it as read. ip_hash is never returned; ip_stored and ip_hash_prefix are.

PATCH /submissions/{id}

Body: status (unread|read|spam|trash), is_starred.

DELETE /submissions/{id}

force=false (default) moves the entry to trash. force=true deletes the row and meta and decrements submission_count.

POST /submissions/bulk

json
{
  "ids": [1, 2],
  "action": "spam"
}

Actions: read, unread, spam, unspam, trash, restore, star, unstar, delete.

Planned

MethodRoutePhase
GET/templates12

Error shape

json
{
  "code": "invalid_definition",
  "message": "The form definition is invalid.",
  "data": {
    "status": 400,
    "data": {
      "success": false,
      "code": "invalid_definition",
      "message": "The form definition is invalid.",
      "errors": {
        "fields.1.key": "Field keys must be unique."
      }
    }
  }
}

Digitale Lösungen. Persönlich. Zukunftssicher.