REST → OpenAPI Inventory
Phase 3: canonical YAML is a full contract (requestBody / security / WpError / response codes), not only a path catalog. URLs are {product}/{slug}/v1. Canonical YAML lives in the plugin at docs/openapi/*.yaml. The site copies the specs (npm run sync:openapi) and generates MDX (npm run gen-api-docs). Audit: npm run audit:openapi (path-coverage plus depth: body or x-empty-body, security, ru/en status codes). Scanner exclusions: vendor, vendor-lib, tests, includes/analogwp-*. License is registered from wp2platform/plugin.php through the wordpress-core controller and is added to the audit explicitly.
OpenAPI column: contract — the operation is described in YAML with input/output/errors.
WP_REST_Server::EDITABLE in PHP = POST|PUT|PATCH; OpenAPI usually documents PATCH (this is sufficient for coverage). CREATABLE = POST, READABLE = GET, DELETABLE = DELETE.
wp2platform
Spec: docs/openapi/wp2platform-modules.yaml → /docs/api/wp2platform. Default auth: cookie / Application Password (DualRest), network.
Site Manager — wp2/site-manager/v1
Clients: Site Manager admin UI. blog_id in path.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | /wp-json/wp2/site-manager/v1/sites | contract |
| POST | …/sites | contract |
| GET | …/sites/slug-availability | contract |
| POST | …/sites/bulk | contract |
| GET | …/sites/{blog_id} | contract |
| PATCH (EDITABLE) | …/sites/{blog_id} | contract |
| DELETE | …/sites/{blog_id} | contract |
| POST | …/sites/{blog_id}/archive | contract |
| POST | …/sites/{blog_id}/unarchive | contract |
| POST | …/sites/{blog_id}/activate | contract |
| POST | …/sites/{blog_id}/deactivate | contract |
| GET | …/sites/{blog_id}/users | contract |
| POST | …/sites/{blog_id}/users | contract |
| DELETE | …/sites/{blog_id}/users/{user_id} | contract |
| GET/POST | …/categories | contract |
| PATCH/DELETE | …/categories/{id} | contract |
| GET/POST | …/statuses | contract |
| PATCH/DELETE | …/statuses/{id} | contract |
| GET | …/jobs | contract |
| GET | …/jobs/{job_id} | contract |
| GET | …/jobs/{job_id}/events | contract |
Site Duplicator — wp2/site-duplicator/v1
| METHOD | Path | OpenAPI |
|---|---|---|
| POST | /wp-json/wp2/site-duplicator/v1/sites/{blog_id}/duplicate | contract |
| GET | …/jobs, …/jobs/{job_id}, …/jobs/{job_id}/events | contract |
Post Duplicator — wp2/post-duplicator/v1
| METHOD | Path | OpenAPI |
|---|---|---|
| POST | /wp-json/wp2/post-duplicator/v1/posts/{post_id}/duplicate | contract |
| POST | …/posts/{post_id}/duplicate-batch | contract |
Multi Network — wp2/multi-network/v1
| METHOD | Path | OpenAPI |
|---|---|---|
| GET/POST | /wp-json/wp2/multi-network/v1/networks | contract |
| GET | …/networks/{network_id} | contract |
Media Converter — wp2/media-converter/v1
Clients: media-hls-encode, media-whisper-tracks skills (formats, attachments, artifacts/pack). Query blog_id on some endpoints.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | …/media-converter/v1/formats | contract |
| GET/PATCH | …/settings | contract |
| POST | …/media, …/encode | contract |
| GET | …/attachments/{id} | contract |
| POST | …/attachments/{id}/encode | contract |
| GET | …/queue, …/queue/{key} | contract |
| POST | …/queue/control, …/queue/clear | contract |
| DELETE | …/queue/{key} | contract |
| POST | …/queue/{key}/formats/{format}/cancel | contract |
| GET/POST/DELETE | …/attachments/{id}/frame-miniatures | contract |
| GET/POST | …/attachments/{id}/thumbnails | contract |
| PATCH/DELETE | …/attachments/{id}/thumbnails/poster | contract |
| GET | …/attachments/{id}/artifacts | contract |
| POST | …/attachments/{id}/artifacts/pack | contract |
| PATCH/DELETE | …/attachments/{id}/artifacts/{folder} | contract |
Subtitles & Timecodes — wp2/media-subtitles-timecodes/v1
Client: media-whisper-tracks skill.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET/POST/PUT | …/media-subtitles-timecodes/v1/attachments/{id}/tracks | contract |
| POST | …/tracks/upload | contract |
| PATCH/DELETE | …/tracks/{index} | contract |
Enable Media Replace — wp2/enable-media-replace/v1
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | …/enable-media-replace/v1/attachments/{id}/replace-info | contract |
| POST | …/attachments/{id}/replace | contract |
Error: playback_artifacts_present (409) if playback artifacts are associated with the attachment.
Studio Sync — wp2/studio-sync/v1 (already the phase 2 canonical form)
Client: WP2Studio (STUDIO_SYNC_REST_BASE). Auth: public on POST /desktop/connect; then Bearer. PHP: src/Modules/StudioSync/. Do not rework.
| METHOD | Path | Auth | OpenAPI |
|---|---|---|---|
| POST | /wp-json/wp2/studio-sync/v1/desktop/connect | public (one-time token) | contract |
| GET | …/desktop/status | Bearer | contract |
| POST | …/desktop/disconnect | Bearer | contract |
| GET | …/sites | Bearer | contract |
| GET | …/status | Bearer (legacy) | contract |
| GET | …/sync/items | Bearer | contract |
| GET | …/sync/posts/{post_id} | Bearer | contract |
| PATCH (EDITABLE) | …/sync/posts/{post_id} | Bearer, body base_hash+content | contract |
Local Sync — wp2/local-sync/v1
Clients: 09-local-sync skill, page-builder pipeline (POST /validate). Capability: manage_network (MS) / edit_pages. Query blog_id.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | /wp-json/wp2/local-sync/v1/projects | contract |
| POST | …/sync | contract |
| POST | …/validate | contract |
Sections Folder — wp2/sections-folder/v1
Client: Gutenberg sidebar admin UI. manage_categories + edit_posts. Creating/deleting sections uses core /wp/v2/{taxonomy}, not this API.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | /wp-json/wp2/sections-folder/v1/sidebar | contract |
| PUT | …/reorder | contract |
| PUT | …/assign | contract |
| PATCH (EDITABLE) | …/sections/{id} | contract |
Passwordless — wp2/passwordless/v1 (public)
Client: WP2 App SPA (AuthContext).
| METHOD | Path | OpenAPI |
|---|---|---|
| POST | /wp-json/wp2/passwordless/v1/request | contract |
| POST | …/verify | contract |
Magic Links — wp2/magic-links/v1 (public)
Client: WP2 App SPA.
| METHOD | Path | OpenAPI |
|---|---|---|
| POST | /wp-json/wp2/magic-links/v1/consume | contract |
Elementor Style Presets — wp2/elementor-style-presets/v1
Client: Elementor admin UI. edit_posts.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET/POST | /wp-json/wp2/elementor-style-presets/v1/presets | contract |
| GET | …/presets/{id} | contract |
| PATCH (EDITABLE) | …/presets/{id} | contract |
Media Playback — wp2/media-playback/v1
Clients: players (Vidstack and others). Query blog_id, lang.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | /wp-json/wp2/media-playback/v1/attachments/{id} | contract |
License — wp2/license/v1 (platform product)
Registration: plugin.php → LicenseRestController('wp2', 'license', $hub). The wp2-wordpress-core repository is not documented separately. Auth: manage_network_options / manage_options.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | /wp-json/wp2/license/v1/products | contract |
| POST | …/{product_id}/activate | contract |
| POST | …/{product_id}/deactivate | contract |
| GET | …/{product_id}/status | contract |
| GET | …/{product_id}/data | contract |
wp2lms
Spec: docs/openapi/wp2lms.yaml.
Static Builder — wp2lms/static-builder/v1
Clients: 10-static-builder skill, CLI bin/static-builder/*. Auth: edit_pages / manage_network. Query blog_id.
WP_Error: wp2lms_static_builder_invalid_blog, blog_not_found, busy, not_found, no_pages, cannot_stop, invalid_id, invalid_api_type, invalid_version, invalid_export_mode, pages_required, invalid_page_ids, page_not_found, create_failed, configure_failed, update_failed, delete_failed, page_cache_rebuild.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET | /wp-json/wp2lms/static-builder/v1/pages | contract |
| GET/POST | …/builds | contract |
| GET/PATCH/DELETE | …/builds/{id} | contract |
| POST | …/builds/{id}/run | contract |
| POST | …/builds/{id}/stop | contract |
Turbo — wp2lms/turbo/v1
Clients: Turbo frontend (Gutenberg/Twig), Gravity Forms bridge, xAPI session.
| METHOD | Path | Auth | OpenAPI |
|---|---|---|---|
| POST | /wp-json/wp2lms/turbo/v1/xapi-actor/session | cookie (email) | contract |
| POST | …/gravity-forms/submit | cookie | contract |
| POST | …/dsh/expand | cookie | contract |
| GET | …/static/{id} | edit_posts | contract |
wp2lms-pro
Spec: docs/openapi/wp2lms-pro.yaml.
Embed Packages — wp2lms-pro/embed-packages/v1
The wp2platform/module/embed-packages/v1 alias is removed. Auth: manage_network / edit_pages. Query blog_id.
WP_Error: embed_packages_not_found, delete_failed, page_not_found, invalid_blog, unknown_blog.
| METHOD | Path | OpenAPI |
|---|---|---|
| GET/POST | /wp-json/wp2lms-pro/embed-packages/v1/packages | contract |
| GET/PATCH/DELETE | …/packages/{id} | contract |
| POST | …/packages/{id}/content | contract |
| POST | …/packages/{id}/materialize-pages | contract |
| GET/PUT/DELETE | …/pages/{page_id}/package | contract |
| POST | …/batch | contract |
wp2tutor
Spec: docs/openapi/wp2tutor.yaml. Namespaces are split per module. Bot is not in this spec (see wp2tutor-bot).
| METHOD | Path | Auth | OpenAPI |
|---|---|---|---|
| GET / POST | /wp-json/wp2tutor/ai/v1/chat | GET public; POST X-Ai-Chat-Secret | contract |
| POST | /wp-json/wp2tutor/embedding/v1/sync | manage_options | contract |
| POST | …/statuses | manage_options | contract |
| POST | …/diagnostics | manage_options | contract |
| GET/POST | /wp-json/wp2tutor/rag/v1/datatables | admin | contract |
| GET | …/chunk/{id_chunk} | admin | contract |
wp2tutor-forms
Spec: docs/openapi/wp2tutor-forms.yaml. Own namespaces wp2tutor-forms/form/v1 and wp2tutor-forms/i18n/v1 (not shared wp2tutor/v1). Form: cookie (logged-in). i18n: public.
| METHOD | Path | OpenAPI |
|---|---|---|
| POST | /wp-json/wp2tutor-forms/form/v1/updateDefinition | contract |
| POST | …/updateShortcode | contract |
| POST | …/updateStyles | contract |
| POST | …/updateL10n | contract |
| POST | …/updateRunner | contract |
| GET | …/getRunnerData | contract |
| GET | /wp-json/wp2tutor-forms/i18n/v1/locale | contract |
| GET | …/translation | contract |
wp2tutor-bot
Spec: docs/openapi/wp2tutor-bot.yaml. Public webhooks. Change the URL in Telegram/VK when deploying.
| METHOD | Path | Auth | OpenAPI |
|---|---|---|---|
| POST | /wp-json/wp2tutor-bot/telegram/v1/webhook/{bot_id} | public | contract |
| POST | /wp-json/wp2tutor-bot/vk/v1/callback/{channel_id} | public | contract |
| POST | /wp-json/wp2tutor-bot/deepchat/v1/chat/{channel_id} | public + X-Wp2tutor-Bot-Secret | contract |
| OPTIONS | …/chat/{channel_id} | public CORS | contract |
Clients: Telegram/VK, Deep Chat UI; WP2 App proxies Deep Chat through wp2app/ai-chat/v1/chat (the secret is not in the bundle).
wp2app
Spec: onepix/wp2app/docs/openapi/wp2app.yaml → /docs/api/wp2app. Cookie + wp_rest nonce. Passwordless/magic-links are not here (platform).
WP_Error: wp2app_auth_missing, wp2app_passwordless, wp2app_auth_failed, wp2app_reserved, wp2app_ai_chat_config, wp2app_ai_chat_secret.
| METHOD | Path | Auth | OpenAPI |
|---|---|---|---|
| GET | /wp-json/wp2app/auth/v1/me | public (user: null for guests) | contract |
| POST | …/login | public | contract |
| POST | …/logout | logged-in | contract |
| GET | …/nonce | public | contract |
| POST | …/lost-password | public | contract |
| POST | …/reset-password | public | contract |
| GET | /wp-json/wp2app/content/v1?path= | logged-in / guests if Private Site is off | contract |
| GET | …/{id} | same | contract |
| POST | /wp-json/wp2app/ai-chat/v1/chat | logged-in (wp2app/ai_chat/can_chat) | contract |
| OPTIONS | …/chat | public | contract |
Out of scope (intentionally absent from product YAML)
- AJAX
admin-ajax.php, WP-CLI. - Core
/wp/v2/*, AnalogWP REST, third-party Elementor/WPML namespaces. - The
wp2-wordpress-corelibrary as a separate API (License is documented under platform). - Themes / skin blocks,
wp2app-starter, deprecated standalone plugins. - WP2 Wrapper is a JS API, not WordPress REST.