WB Listora exposes 58 REST endpoints under the listora/v1 namespace. Every customer-facing surface (frontend listing UI, submission wizard, user dashboard, search, reviews, claims, favorites) is REST-driven; AJAX is reserved for admin-only operations (per the plugin’s REST-first architecture rule).
Base URL:<your-site>/wp-json/listora/v1/
Auth model:
Public - GET reads (listings, search, single listing). No authentication required.
Owner - only the listing’s author (or a user with the listing’s edit capability) can modify.
Admin - requires manage_options or manage_listora_settings.
Nonce header for browser clients: X-WP-Nonce: <wp_create_nonce("wp_rest")>. Apps using Application Passwords don’t need this.
Response envelope (lists):
{
"listings": [ /* array of resource objects */ ],
"total": 247,
"pages": 21,
"has_more": true,
"cursor": "WyJsaXN0aW5nIiwxMjM0XQ==",
"next_cursor": "WyJsaXN0aW5nIiwxNDQ0XQ=="
}
Error contract:
{
"code": "listora_invalid_field",
"message": "Field 'price' is required",
"data": { "status": 400 }
}
Permission-denial codes: since 1.1.0, denied requests return structured codes instead of the generic rest_forbidden - listora_unauthorized with HTTP 401 when the caller is not authenticated, and listora_forbidden with HTTP 403 when an authenticated caller lacks the required capability or ownership. This applies to the Settings + notification-log endpoints (Free) and the Analytics + Photo Reviews endpoints (Pro); ownership failures correctly return 403.
Generated from audit/manifest.json. Re-run /wp-plugin-onboard --refresh after non-trivial commits to regenerate.
User’s listings (cursor pagination). Optional listing_type=<slug> narrows the list to one listing type; a slug that is not a type on the site returns an empty list, never the unfiltered one. /dashboard/stats is deliberately NOT scoped - it reports the member across every type.
GET
/listora/v1/listings
Public
Listings_Controller::get_items
List published listings (cursor pagination)
POST
/listora/v1/listings/bulk
Public
Listings_Controller::get_bulk
Fetch up to 50 listings by ID (offline cache)
DELETE
/listora/v1/listings/{id}
delete_listing_permissions
Listings_Controller::delete_listing
Owner soft-delete
POST
/listora/v1/listings/{id}/deactivate
deactivate_listing_permissions
Listings_Controller::deactivate_listing
Owner hides their listing from the directory (sets listor…
GET
/listora/v1/listings/{id}/detail
Public
Listings_Controller::get_listing
Single listing detail (card or full). Carries owner: { name, url } - the public “Listed by” name. The key is ABSENT, not null, when the Show Who Listed It feature is off. List and card payloads omit it deliberately, to avoid a user lookup per row.
Resend email verification. Deprecated in 1.3.0 with guest submission; submission now requires a logged-in account, so this endpoint is no longer used.
GET
/listora/v1/submission/verify
Public
Submission_Controller::verify_endpoint
REST mirror of email verify URL. Deprecated in 1.3.0 with guest submission; submission now requires a logged-in account, so this endpoint is no longer used.
A member submits a listing they own to a BuddyNext space; the space team approves it before it
appears in that space’s Businesses tab. These routes are the partner-facing API: BuddyNext owns
spaces and space roles, so Listora never resolves a space_id itself and asks two filters instead
(see the hooks reference). Both default to false, so with no BuddyNext installed every route here
is closed.
Method
Route
Auth
Handler
Purpose
POST
/listora/v1/listings/{id}/spaces
Listing owner
Space_Listings_Controller::submit
Submit a listing you own to a space (lands as pending)
GET
/listora/v1/spaces/{space_id}/listings
wb_listora_user_can_view_space
Space_Listings_Controller::showcase
Approved listings for the space. Paginated: page, per_page (capped at 48), returns X-WP-Total / X-WP-TotalPages
GET
/listora/v1/spaces/{space_id}/listings/pending
wb_listora_user_can_moderate_space
Space_Listings_Controller::pending
Moderation queue, newest first Paginated: page, per_page (default 20, max 100), with X-WP-Total and X-WP-TotalPages.
Reject a submission, take an approved listing down, or withdraw your own
Known limits, so an integrator is not surprised:
…/listings/pendingis paginated since 1.8.0 — page and per_page (default 20, max 100),
with X-WP-Total and X-WP-TotalPages, the same headers the reviews and favourites routes send.
Rows are ordered created_at DESC, listing_id DESC; the id tiebreaker matters, because several
submissions in one second would otherwise sort arbitrarily and shuffle between pages.
There is no count endpoint. Space_Listings_Model::pending_count() exists but is not exposed,
so a queue badge currently has to fetch the whole queue to show a number.
A member may hold at most 5 pending submissions per space by default; the 6th returns 429
with code listora_too_many_pending. Tune with wb_listora_space_pending_submission_limit.
DELETE fires the same action whether the team rejected the submission or the member withdrew it.
WordPress core localizes the REST nonce automatically. Read it from wp.apiFetch (when using @wordpress/api-fetch) or the page’s localized wpApiSettings.nonce:
// In a block's view.js (uses the apiFetch helper):
import apiFetch from'@wordpress/api-fetch';
const data = await apiFetch( { path: '/listora/v1/listings?per_page=12' } );
// Plain fetch with manual nonce:
const res = await fetch('/wp-json/listora/v1/favorites', {
When wb-listora-pro is active, every route below registers under the same listora/v1 namespace and respects the same auth + nonce + rate-limit rules as Free. Permission per route is annotated as public (anyone), auth (logged-in only), cap:foo (requires that capability), or pro-toggle (feature toggle must be on at Settings → Features, where Pro toggles register since 1.1.0).
Every endpoint that returns a resource also fires a wb_listora_rest_prepare_{resource} filter so Pro / themes / third-party code can inject custom fields without forking the controller:
Public-write endpoints (POST /submissions, POST /listings/{id}/reviews, POST /claims, POST /listings/{id}/contact-form) are rate-limited per IP via sliding-window counters. Since 1.1.0, when WB Listora Pro is active its public read-only endpoints (credit packs, pricing plans, needs feed, comparisons, service search, badges) are also throttled - a per-IP cap of 60 requests/minute that fails open. See Rate Limiting & Abuse Controls for the default caps + per-endpoint windows + how to tune.