Contents
On this page
Plugixa Testimonial REST API - Plugixa Testimonial
The integration surface for Plugixa Testimonial: testimonials you can list, create, edit, moderate, reorder and delete, categories and custom fields, e-mailed testimonial requests, saved views and shortcodes, import and export, translations, and the public routes the front end uses. Enough to sync testimonials from a CRM or a review platform, feed a headless site, or automate moderation.
The admin app uses these same routes, under the namespace plugixatestimonial/v1 (one word, no hyphen), so anything the admin can do with content, a script can do too. Every capability the interface checks is checked again at the endpoint.
Base URL
https://your-site.example/wp-json/plugixatestimonial/v1
On a site with plain permalinks, pass the route as a parameter instead:
https://your-site.example/?rest_route=/plugixatestimonial/v1/testimonials
Authentication
Plugixa Testimonial has no API keys of its own. It uses standard WordPress authentication:
| Caller | How it signs in |
|---|---|
| A script or another system | A WordPress Application Password, sent as HTTP Basic auth |
| The admin app, or your own code in wp-admin | The logged-in cookie plus a wp_rest nonce in X-WP-Nonce, the normal WordPress way |
| The front end (lists, the submission form, request links, social proof) | Nothing: those routes are public |
Create an Application Password under Users -> Profile -> Application Passwords for the user the script should act as, then send it with the username:
curl -s "https://your-site.example/wp-json/plugixatestimonial/v1/testimonials" \
-u "admin:$WP_APP_PASSWORD"
WordPress only accepts Application Passwords over HTTPS. A request that arrives signed out is refused with 403, not 401.
Capabilities
Each route checks one of four gates. The plugin gives its capabilities to the Administrator role on activation, and each gate except the last also accepts a WordPress capability, so an untouched site works without a role editor:
| Gate | Plugin capability | Or WordPress capability | Used by |
|---|---|---|---|
| Edit | plugixa_testimonial_edit |
edit_posts (Contributors and up) |
Reading, creating and updating testimonials, categories, views and shortcodes; reordering; translations |
| Delete | plugixa_testimonial_delete |
delete_others_posts (Editors and up) |
Deleting testimonials, categories, views and shortcodes; unlinking translations |
| Approve | plugixa_testimonial_approve |
publish_posts (Authors and up) |
Change Status and Bulk Action |
| Admin | none | manage_options only |
Custom fields, testimonial requests, import and export |
plugixa_testimonial_manage and plugixa_testimonial_settings exist but no route checks them.
Responses
Every successful response is wrapped the same way, with status 200, creates included:
{
"success": true,
"message": "Testimonial created successfully",
"data": { "id": 42 }
}
message is a translated confirmation, empty on reads. A create answers only the new id in data.id: read the record back if you need it. File exports are the exception: they answer with the file itself.
Records are returned as they are stored. Numbers read from the database come back as strings ("id": "42", "rating": "5", "is_featured": "1"), null stays null, and datetimes are in the site’s time zone as 2026-11-12 09:30:00, not UTC. A request’s expires_at is the one datetime stored in UTC. Ids and counts the plugin computes itself (a new id, total) are real integers. Cast before you compare.
Lists and pagination
Paged list endpoints accept the same parameters and put the total in the body, not in headers (X-WP-Total is not sent).
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer |
20 |
Rows per page. 0 or -1 returns every row; there is no upper limit |
offset |
integer |
0 |
Rows to skip |
orderby |
string |
created_at |
One of the sortable columns each endpoint lists |
order |
string |
DESC |
ASC or DESC, in capitals: desc is rejected with 400 |
filter[...] |
object |
The filters each endpoint lists, such as filter[rating_min]=4 |
|
lang |
string |
With WPML or Polylang active: only rows in this language | |
group_by_translation |
string |
With WPML or Polylang active: send 1 for only default-language rows (plus rows with no translation group). Any non-empty value except 0 turns it on, false included |
search and status can also be sent at the top level. A page answers like this:
{
"success": true,
"message": "",
"data": {
"items": [ { "id": "42", "client_name": "Sarah Johnson" } ],
"total": 37,
"state": { "filter": { "status": "approved" }, "limit": 20, "offset": 0, "orderby": "created_at", "order": "DESC" }
}
}
To walk every page, add limit to offset until offset reaches total, or send limit=-1. With WPML or Polylang active, rows also carry a translations list of { id, language_code }. There is no trash: deleted rows are gone. The public front-end lists page differently, with page and per_page: see List Approved Testimonials.
Endpoints
| Resource | Endpoints |
|---|---|
| Testimonials | List, Create, Get, Update, Delete, Change status, Reorder, Delete several, Bulk action, Authors |
| Categories | List, Create, Get, Update, Delete, Reorder |
| Custom fields | List, Create, Get, Update, Delete, Reorder |
| Requests | List, Send, Get, Delete, Resend, Send several, Delete several, Check token (public) |
| Views | List, Create, Get, Update, Delete, Duplicate, Set default, Delete several |
| Shortcodes | List, Create, Get, Update, Delete, Duplicate, Delete several |
| Exports | CSV, JSON, PDF PRO |
| Imports | Upload file, Run import |
| Front end (public) | Approved testimonials, Rendered page, Submit, Social proof |
| Translations | Languages, List, Create, Link, Unlink |
Everything except the PDF export is in the free build. The PRO route is registered only by the Pro build: on the free build it is not there at all and answers 404, rather than an upgrade message. Settings, the dashboard, the admin’s pickers and previews, font loading, demo data and the Pro Google, Facebook and review-source connections also live under this namespace, but they serve the admin screens and are not covered here.
Updates are not all alike
The single thing most likely to cost you an afternoon:
| Endpoint | What a field you leave out does |
|---|---|
| Update Testimonial | Resets rating, is_featured and display_order, and sets status back to pending, which unpublishes it. Other fields are kept |
| Update Category | Resets everything, and an omitted slug is saved empty |
| Update Custom Field | Resets everything except the key |
| Update View | Keeps name, slug and description, but takes the default flag off and rebuilds a sent config from the defaults |
| Update Shortcode | Keeps name, slug and description, but rebuilds a sent config from the defaults |
Each answers 200 even when nothing matched the id. Read the record, merge your change into it, and send the whole thing back.
Errors
Errors use the standard WordPress shape. The plugin’s own errors carry the code rest_error and an errors object, which names the fields for a validation failure and is empty otherwise:
{
"code": "rest_error",
"message": "Validation failed",
"data": {
"status": 400,
"errors": { "testimonial_text": "Testimonial text must be at least 10 characters" }
}
}
These can come back from any endpoint. Each endpoint page lists its own errors on top of them.
| Status | Code | When |
|---|---|---|
403 |
rest_forbidden |
The user lacks the capability, or the request arrived signed out (no credentials, or a cookie without a valid nonce). |
401 |
WordPress’s own | The Application Password or username is wrong. WordPress rejects it before the plugin runs. |
403 |
rest_cookie_invalid_nonce |
A cookie request sent a stale or wrong X-WP-Nonce. |
404 |
rest_no_route |
No such route or method, or the PRO route on the free build. |
400 |
rest_invalid_param |
A parameter failed validation, for example order=desc in lower case, limit below -1, or a status or rating outside the allowed values. |
400 |
rest_missing_callback_param |
A required parameter is missing. |
500 |
rest_error |
The database refused a write. The message says which operation failed. |
There is no rate limit on any route. The public submission route has none either, which is why reCAPTCHA is worth turning on for a public form: see Submission settings.
Caching
The public front-end lists are cached. Any write to this namespace (any request that is not a GET) clears that cache, so changes made through the API show at once. Changes written to the database by other means do not clear it.
No filter changes what these routes return. To change behaviour in PHP, see Hooks.
Troubleshooting
| Symptom | Usual cause |
|---|---|
| A testimonial disappeared from the site after an update | PUT /testimonials/{id} was sent without status, which resets it to pending. Send the full record. |
| The site lost its default view | PUT /views/{id} was sent without is_default: true, or Set Default View was given an id that does not exist. |
A category update fails with 500 |
Another category already has an empty slug. Always send slug. |
| Every imported row fails with “Missing client name” | mapping was keyed by column name. Key it by column position: "0", "1", … |
400 with order |
Send ASC or DESC in capitals. |
"id": "42" compared with 42 fails |
Values read from the database are strings. Cast them. |
404 from every route |
The namespace is plugixatestimonial/v1, without a hyphen. |
404 on the PDF export |
The free build does not register it. Check which build is installed. |
403 from a script |
Missing or wrong credentials, or a user without the capability. Custom fields, requests and import/export need an Administrator. |
403 from the browser |
The nonce is missing or stale. Reload the page. |
See also
- Move testimonials in bulk without code: Import and export.
- Ask customers for testimonials by e-mail: Testimonial requests.
- Change behaviour in PHP instead: Hooks.
- Everything else: Troubleshooting.
Quick Links
Share