Skip to content

REST API ​

The WordPress REST API and application passwords, for headless sites, apps and agents.

kitloom/api · admins: kitloom/api-filament, kitloom/api-nova

The WordPress REST API on a kitloom site, for headless front ends, mobile apps and agents: /wp-json/wp/v2/ with WordPress's JSON for the core fields, so WordPress clients work for the basics, and application passwords on laravel/sanctum tokens. The admin pages are kitloom/api-filament or kitloom/api-nova.

The root, /wp-json/, is the site's (kitloom/site): its index lists every module's namespace, and this package is the wp/v2 one. Other modules answer under the same root in namespaces of their own (kitloom/forms: contact-form-7/v1) without this package.

Routes ​

RouteMethodsWhat
/wp-json/wp/v2GETThe namespace and its routes (/wp-json/ itself is the site's index)
/wp/v2/types, /wp/v2/types/{type}GETShown post types with their rest_base (media is attachment)
/wp/v2/taxonomies, /wp/v2/taxonomies/{taxonomy}GETShown taxonomies; ?type=post
/wp/v2/{posts base}GET, POSTposts, pages, any shown type: the list, a new record
/wp/v2/{posts base}/{id}GET, POST/PUT/PATCH, DELETEOne record; DELETE trashes, force=true deletes
/wp/v2/{terms base}GET, POSTcategories, tags, any shown taxonomy (id is the term_id)
/wp/v2/{terms base}/{id}GET, POST/PUT/PATCH, DELETEOne term; DELETE trashes (kitloom's term trash — WordPress has none), force=true deletes; each term carries its status
/wp/v2/media, /wp/v2/media/{id}GETThe media library, with media_details.sizes
/wp/v2/users/meGETThe password's user; context=edit adds username, email, names

Lists take page, per_page (10, at most 100), offset, search, include/exclude, slug, order, orderby (date, id, include, title, slug, modified, parent, menu_order, author, include_slugs); posts also author/author_exclude, parent/parent_exclude, status (other than publish for editors of the type), after/before/modified_*, sticky, and each taxonomy's base with _exclude; terms hide_empty, parent, post. Answers carry X-WP-Total, X-WP-TotalPages and Link; _fields narrows them; context=edit adds raw values for those who may edit. Errors are WordPress's: {"code": "rest_post_invalid_id", "message": "…", "data": {"status": 404}}, also for routes that do not exist under the prefix.

The routes are registered by the package without the web group — no session, no CSRF — under the site's REST root, which matches before the site's fallback route, so /wp-json/* never reaches the site.

Who sees and writes what ​

A request with no password is a visitor: it sees what is published. A password makes it its user's request: Visibility::forUser() — editors see everything, authors their own drafts too. Writes go through Content\PostWriter and Content\TermWriter as that user, which refuse what the user's capabilities do not allow (a contributor publishing, an author editing someone else's post). Content filters render content.rendered as the record's page would.

Application passwords ​

Sanctum tokens of users, stored in personal_access_tokens (the package's migration creates it unless Sanctum's is there) as a SHA-256 hash only; the user copies {id}|{secret} once. Clients send it

  • as a Bearer token: Authorization: Bearer 12|…, or
  • with the username or email as Basic auth, the way WordPress clients send application passwords: curl -u admin:12|… https://example.com/wp-json/wp/v2/users/me.

A wrong, expired or revoked password is refused with 401 even where a visitor would be let in. A password is read-only (read) or reads and writes as the user (*); it may expire. It never signs in to the site: the API does not touch the session guard. ApplicationPasswords makes, finds and revokes them: a user revokes their own, whoever has manage_options anyone's. Owners are read through the auth user provider the site signs in with (kitloom-api.user_provider names another).

With kitloom/privacy, Tools → Export Personal Data lists the user's passwords — the name, read-only or not, when each was made, last used and runs out — never the password or its hash. Erase Personal Data revokes them all; the account stays, and its owner makes new ones if they want.

Web servers that drop the Authorization header (Apache with CGI/FPM) need it passed on, as WordPress needs: RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}].

Settings ​

OptionDefaultWhat
rest_api_enabledonOff — every wp/v2 route answers rest_disabled (404); other modules' namespaces stay
rest_api_post_typesevery public typeJSON list of post types shown
rest_api_taxonomiesevery public taxonomyJSON list of taxonomies shown
rest_api_rate_limit120Requests a minute per user, or per address without a password; 0 — none. Answers carry X-RateLimit-*; over it, rest_too_many_requests (429)

Configuration ​

php artisan vendor:publish --tag=kitloom-api-config for kitloom-api.php: routes.register, user_provider, wrong_passwords ('10,1': after ten wrong application passwords in a minute an address gets rest_too_many_attempts, 429, before any password of it is checked — kitloom/ai's agent address counts with it; '' — no limit), rest_bases ('book' => 'books'), per_page/max_per_page, privacy.register (the personal data export and erasure) and the admin pages (filament.register, nova.register). The prefix (wp-json) and CORS are the root's, kitloom-site.rest; the pagination headers join cors.exposed_headers. Sanctum's token_prefix and expiration apply to application passwords.

Tests ​

From the application that installs the package: php vendor/bin/phpunit --testsuite Api.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]