Skip to content

REST API Reference

MediaVerse overviewFree + ProGet MediaVerse →

Included in Free - Everything documented below ships in the free plugin. Pro adds routes under its own namespace, see the Pro REST API reference.

Base URL: /wp-json/mvs/v1/

All routes below use the mvs/v1 namespace (the messaging routes share the same namespace). The messaging routes exist only while Settings > Messages > Messages is on; with it off they are not registered and answer WordPress’s standard 404 rest_no_route, so check features.messaging in GET /app/config first.

Authentication. Reads of public data are open. Every write - and every /me/* route - requires an authenticated user. Pass the X-WP-Nonce header with a nonce generated via wp_create_nonce( 'wp_rest' ) and send cookies with credentials: 'same-origin', or use a WordPress Application Password for non-browser clients.

Private-community gate (2.2.0). When the host community is private, the entire mvs/v1 surface - including public reads - requires authentication, and with Pro active the mvs-pro/v1 namespace is covered by the same gate. Unauthenticated requests get 401 with code mvs_community_private. The gate is off by default and controlled by three filters: mvs_rest_require_auth (return true to arm the gate; BuddyNext arms it automatically when its private-community mode is on), mvs_rest_can_access (defaults to is_user_logged_in(); override to allow specific unauthenticated callers, e.g. a trusted server-to-server integration), and mvs_rest_gated_route_prefixes (the covered route prefixes; Pro appends its own namespace here, and sites can add more).

Authorization model. Three levels are used throughout:

  • Public - no auth; privacy is enforced inside the query so private rows never leak.
  • Authenticated - any logged-in user (is_user_logged_in()).
  • Capability - a specific capability such as upload_mvs_media, moderate_mvs_media, or manage_mvs_access.

Update methods. Every route documented below with PUT also accepts PATCH and POST. WordPress registers these three together as its “editable” method group, so all three reach the same handler with the same arguments and the same response. PUT is used throughout this page as the canonical form; pick whichever your HTTP client handles most comfortably.

Timestamps. Datetime fields such as created_at, updated_at and last_read_at are stored in UTC and sent as YYYY-MM-DD HH:MM:SS with no timezone marker, the shape the mobile app and older clients parse. Every one of them also has an ISO-8601 sibling ending in _gmt (created_at_gmt: "2026-09-24T17:56:07Z"), in every mvs/v1 response including messaging and the poll endpoint. Read the _gmt field: passing the bare value to JavaScript’s new Date() reads it as the browser’s local time and shifts the clock by the viewer’s UTC offset. Add your own UTC keys to the list with the mvs_rest_timestamp_keys filter.

Rate limiting. Many routes are throttled per user/IP (the limit is noted where it is unusually tight). Exceeding a limit returns 429 Too Many Requests.


Auth: Public (privacy enforced in query). Rate-limited to 120/min.

List media items. Returns only rows the caller is allowed to see.

Parameters:

Parameter Type Default Description
page int 1 Page number
per_page int 20 Items per page (max: 100, filterable via mvs_rest_pagination_max)
media_type string (all) Filter by type: image, video, audio, document
author int (all) Filter by user ID
slug string (none) Fetch a single item by post slug
tag string (all) Filter by mvs_tag slug
category string (all) Filter by mvs_category slug
orderby string date Sort: date, trending, popular, created_at, title, views (filterable via mvs_feed_sort_options)
order string desc asc or desc
include int[] [] Return only these media IDs
scope string all all returns everything the caller may see; public limits the list to public items; self returns the caller’s own uploads; followers returns media from members the caller follows. self and followers need a logged-in caller
s string (none) Full-text search term
group_covers bool false Collapse gallery groups to a single cover item
group int (none) Only one BuddyPress group’s media (2.6.2). Members of that group also get items shared with the group. In a private or hidden group, everyone else gets an empty list. In a public group they get what they may see anyway

Listings show a gallery (items uploaded together) as one tile. The first item the viewer may see carries the gallery count, and the media_type, tag, category, s and group filters apply to it. See GET /media/{id}/group to open the same set.

Response:

{
"items": [
{
"id": 123,
"title": "Sunset Photo",
"description": "",
"media_type": "image",
"file_url": "https://example.com/wp-content/uploads/wpmediaverse/2025/03/photo.jpg",
"privacy": "public",
"author_id": 1,
"album_id": null,
"views": 42,
"reactions_count": 5,
"comments_count": 2,
"created_at": "2025-03-27T12:00:00Z",
"can_edit": false,
"is_favorited": false,
"viewer_reaction": null
}
],
"total": 50,
"pages": 5
}

Alt text (2.6.1). Every media object includes alt (string): the AI description when there is one, otherwise the title. Change it with the mvs_media_alt_text filter.

Viewer-aware fields. Every media item carries three fields resolved against the requesting user, not cached statically: can_edit (bool - true when the viewer is the author or has manage_options), is_favorited (bool), and viewer_reaction (string reaction slug, or null if the viewer hasn’t reacted). All three are false/null for anonymous requests. List endpoints batch-load this state per page (MediaController::prime_viewer_state()) rather than querying per row.

Auth: Capability - upload_mvs_media (or manage_options).

Upload a new media file.

Body (multipart/form-data):

Field Required Description
file Yes The file to upload
title No Media title (defaults to filename)
description No Text description
privacy No Privacy level (default: site setting)
group_id No BuddyPress group ID (required when privacy=group)
album_id No Add to this album after upload
is_story No true to mark as a story

Response: 201 Created with the new media object.

Auth: Public (privacy check in permission callback). Returns 403 if the caller cannot view it, 404 if it does not exist.

Get a single media item.

Auth: Capability - owner with edit_mvs_medias, or edit_others_mvs_medias.

Update a media item. Also accepts slug, allow_download (bool), tags (array) and categories (array). Changing privacy also updates the item’s BuddyPress activity post (fixed in 2.6.2).

Body (JSON):

{
"title": "Updated Title",
"description": "Updated description",
"privacy": "private"
}

Auth: Capability - owner with delete_mvs_medias, or delete_others_mvs_medias.

Delete a media item and its stored file.

Auth: Capability - same as PUT /media/{id} (edit permission).

Replace the underlying file of an existing media item while keeping its ID, comments, reactions, and stats. Send the new file as multipart/form-data with a file field.

Auth: Public.

Record a view for the item. Increments the view counter and writes a row to mvs_media_views.

Auth: Public. Rate-limited to 30/min.

Record a download event and increment mvs_media_stats.downloads. Refused with 403 when the global Allow Downloads toggle is off OR the per-media allow_download meta is '0'.

Auth: Public. Rate-limited to 60/min.

Record a share event and increment mvs_media_stats.shares. Called by the lightbox Share button after a successful navigator.share / clipboard copy.

Auth: Public.

Report whether the current user can view the item (resolves privacy rules and any access grants). Returns an access decision, not the file.

Response:

{
"media_id": 123,
"can_view": true,
"privacy": "members",
"is_owner": false
}

privacy and is_owner are only populated when the caller can view the item or owns it; a caller with neither returns 403 before these fields are built.

Auth: Public (privacy enforced per item).

Return the items of the same gallery/upload group as {id} that the caller may see, in position order. It builds multi-item lightboxes. A caller who may not view {id} gets 404 mvs_not_found. When the gallery has fewer than two visible members, the response is just {id}.

Pass the same filter as the listing so the lightbox opens the set its badge counted (2.6.2):

Parameter Type Description
media_type string Only members of this type
tag string Only members with this mvs_tag slug
category string Only members in this mvs_category slug
s string Only members matching this search term
group int Only members shared with this BuddyPress group

Auth: Authenticated with view access to the media.

Generate a time-limited signed URL for a private file. The signed URL points at /serve and carries an HMAC-SHA256 signature binding the request to a user, media ID, and expiry.

Parameter Type Default Description
download bool false Issue a download (attachment) URL
ttl int (setting) Override the signed-URL lifetime, in seconds

Auth: Public - the HMAC signature on the URL is the credential (analogue of an S3 pre-signed URL). For non-public media the handler also re-checks can_view per request.

Stream the underlying file (full file or a thumbnail variant) for a validated signed URL. Drains output buffers and disables zlib.output_compression before streaming so byte counts match Content-Length. Honours Range: headers for video/audio.

Param Required Description
mvs_id yes Media ID
mvs_uid yes User ID the URL was signed for (0 for anonymous public media)
mvs_exp yes Unix expiration timestamp
mvs_sig yes HMAC-SHA256 signature
mvs_size no large / medium / thumbnail / watermark to serve a variant
mvs_dl no When 1, sets Content-Disposition: attachment and increments the download counter

Auth: Authenticated.

List the current user’s own media, including private and pending items. Accepts the same parameters as GET /media.


Auth: Public (privacy enforced in query).

List albums. Supports page, per_page, author, album_type (default or playlist), s (search), orderby (date or title) and order (asc or desc).

Since 2.6.2 the list carries a count for each album but omits its item ids. Pass with_items=1 to include them. To restore the old shape for every request, return true from the mvs_album_list_include_items filter.

Auth: Authenticated with album-create permission.

Create an album.

{
"title": "My Album",
"description": "Optional",
"privacy": "public"
}

Auth: Public (private albums 404 for non-owners).

Get an album with its media list.

Auth: Authenticated - owner / edit permission.

Update an album. Besides the album fields, cover_media_id (int, 0 clears it) sets the cover.

Auth: Public (privacy enforced in query).

List the media in an album, paged: page (default 1) and per_page (default 20, max 100).

Auth: Authenticated - owner / delete permission.

Delete an album (does not delete the media items it contains).

Auth: Authenticated - owner / edit permission.

Reorder the items inside an album.

{ "order": [103, 101, 102] }

Auth: Authenticated - owner / edit permission.

Add media to an album.

{ "media_ids": [101, 102, 103] }

Auth: Authenticated - owner / edit permission.

Remove a single media item from an album.

Auth: Authenticated - owner / edit permission.

Set the album cover.

{ "media_id": 101 }

Auth: Authenticated. Returns the current user’s collections.

Supports page, per_page (max 100), s (search), orderby (date or title) and order (asc or desc).

Auth: Authenticated.

Create a collection (manual or smart).

{
"title": "Nature",
"type": "smart",
"rules": { "tags": ["nature"], "media_type": "image" },
"privacy": "public"
}

Auth: Public (privacy check in permission callback).

Get a collection with its resolved item list.

Auth: Authenticated - owner only.

Update a collection. privacy is public or members.

Auth: Public (privacy check in permission callback).

List the items of a collection, paged: page (default 1) and per_page (default 20, max 100).

Auth: Authenticated - owner only.

Delete a collection.

Auth: Authenticated - owner only.

Set the smart-collection rules used to resolve its items.

{ "rules": [ { "field": "tag", "value": "nature" } ] }

All reaction operations live on a single route that varies by HTTP method.

Auth: Public.

Get reaction counts grouped by type. When a logged-in user calls it, the response also indicates that user’s own reaction.

Auth: Authenticated.

Add or change your reaction. Note the field name is reaction_type.

{ "reaction_type": "love" }

Auth: Authenticated.

Remove your reaction.


Auth: Public (visibility follows the parent media’s privacy).

List comments. Supports page, per_page (max 100).

Auth: Authenticated. Use @username syntax for mentions.

{
"content": "Great photo @jane!",
"parent": 0,
"from_activity": 0
}
Field Required Description
content Yes Comment text
parent No Parent comment ID for threaded replies (default 0)
from_activity No Source BuddyPress activity ID, when posted from the activity stream

Auth: Authenticated - owner (within the edit window) or moderate_mvs_media.

Edit a comment. Body: content (string, required).

Auth: Authenticated - owner or moderate_mvs_media.

Delete a comment. Since 2.6.2 its replies are deleted with it, however the comment is deleted (this route, moderation or the wp-admin comments screen). Return false from mvs_comment_delete_replies to keep the replies. On a BuddyPress site the activity copy of the comment and its notifications are removed too.


Auth: Authenticated.

Return whether the current user has favorited the item.

Auth: Authenticated.

Add the item to favorites (toggles on). Optional collection_id saves it into a specific collection.

Auth: Authenticated.

Remove the item from favorites.

Auth: Authenticated.

List the current user’s favorites. Supports collection_id, s (search), page, per_page, orderby (favorited default, title, date) and order (asc or desc, default desc).


Access rules and grants (/media/{id}/rules, /media/{id}/grant, /me/grants, /access/options) were removed in 2.6.0. Access is decided by the item’s privacy; documents are shared through Pro’s document sharing.


Auth: Authenticated. Rate-limited to 30/min.

Follow a user.

Auth: Authenticated.

Unfollow a user.

Auth: Public.

List a user’s followers (display name + avatar). Supports page and per_page (default 20, max 100).

Auth: Public.

List who a user follows. Supports page and per_page (default 20, max 100).

Auth: Authenticated.

List who the current user follows. Supports page and per_page (default 20, max 100).

Auth: Authenticated.

List the current user’s followers. Supports page and per_page (default 20, max 100).


Auth: Authenticated.

Get the current user’s profile.

Besides the profile fields, the response carries what a client needs to render the member’s settings honestly:

Field Meaning
dm_access “Who can message you” as the site enforces it: the member’s choice, or the site setting when that is stricter
dm_access_choices The values the member may pick: the site setting and everything stricter, least to most restrictive
email_activity_available false when the owner has no member email type switched on; hide the activity-email switch then

Show the messaging and online-status controls only when features.messaging in GET /app/config is true.

Auth: Authenticated.

Update profile fields. A dm_access looser than the site setting is saved as the site setting, so the stored value is always one the site honours.

{
"first_name": "Jane",
"last_name": "Smith",
"display_name": "jsmith",
"description": "Photographer"
}

Also accepted: dm_access (everyone, followers, mutual or nobody), online_status (everyone or nobody, who can see when you are online) and email_activity (on or off).

Auth: Authenticated.

Upload a new profile avatar (multipart/form-data, file field).

Auth: Authenticated.

Remove the custom avatar and revert to Gravatar.


Auth: Public. Rate-limited to 60/min.

Get a user’s public profile: bio, avatar URL, follower/following counts, and public media count. user_login / user_registered are returned only to the user themselves or to admins (enumeration hardening).

Auth: Public (privacy enforced in query).

List a user’s visible media. Supports page, per_page.

Auth: Public.

Search for users by display name or username.

Parameter Type Default Description
q string (required) Search term
per_page int 10 Results per page (max: 50)

Auth: Authenticated.

The member’s storage use and limit, in bytes: { "used": 52428800, "limit": 524288000 }. limit is 0 when no limit applies (the default). Usage counts every item the member owns that is not in the trash, plus chat attachments sent from 2.6.0 on.

GET /users/{id}/storage and PUT /users/{id}/storage

Section titled “GET /users/{id}/storage and PUT /users/{id}/storage”

Auth: edit_users.

Read or set one member’s own limit. The response adds limit_mb: the member’s own limit in MB, or null when they follow the site limit. Send limit_mb as a number (0 = no limit for this member) or null to go back to the site limit.


Auth: Authenticated. Rate-limited to 10/min.

Submit a content report against a media item.

{
"reason": "inappropriate",
"details": "Optional explanation"
}

reason must be one of ReportService::REASONS.

Auth: Authenticated.

Report a user. Same reason / details body as media reports.

Auth: Authenticated. Rate-limited to 10/min. (New in 2.6.0)

Report a comment. Same reason / details body as media reports. A comment on media the caller cannot open answers 404 mvs_not_found, the same as a missing one. Reporting your own comment answers 400 mvs_report_own.

Auth: Authenticated. Rate-limited to 10/min. (New in 2.6.0)

Report a message in a conversation the caller is an active participant of. Same body as media reports. A message in any other conversation answers 404 mvs_not_found; your own message, including one you unsent, answers 400 mvs_report_own; with Messages turned off it answers 404 mvs_messaging_disabled. Moderators see the message text on the Reports screen.

Auth: Authenticated.

Block a user.

Auth: Authenticated.

Unblock a user.

Auth: Authenticated.

List the users the current user has blocked.


All moderation routes require the moderate_mvs_media capability, except GET /ai/usage, which requires manage_options or manage_mvs_settings.

List media items in the moderation queue. Supports status (pending, flagged default, or rejected), page and per_page (max 100).

The route is /moderation, not /moderation/queue. Earlier revisions of this page showed /moderation/queue, which returns 404.

Return queue counts (pending, flagged, etc.) for building badges and tabs.

Approve a media item.

Reject a media item. Optional reason string is recorded.

Trigger AI analysis (description / tagging / safety) on a media item.

Return AI usage / budget figures for the moderation dashboard.


Auth: Authenticated with the relevant per-action capability. Rate-limited to 10/min, max 100 IDs per call.

Perform a bulk action on multiple media items.

{
"action": "delete",
"media_ids": [101, 102, 103]
}
Field Required Description
action Yes One of delete, move_to_album, change_privacy, add_tags
media_ids Yes Array of media IDs (max 100)
album_id When action=move_to_album Destination album ID
privacy When action=change_privacy New privacy value
tags When action=add_tags Array of tags to add

Auth: Public for public media; 403 for media the caller cannot view.

Per-item statistics (views, reactions, comments, downloads).

Auth: Authenticated.

Aggregate statistics across the current user’s own media.


Auth: Public.

List / autocomplete mvs_tag terms. Since 2.6.1, logged-out visitors get only tags used on public items (top 200 by use); signed-in members get the full list.

Removed in 2.6.1: the core routes /wp/v2/mvs-albums, /wp/v2/mvs-collections and /wp/v2/mvs_tag. Use the mvs/v1 albums, collections and tags routes. /wp/v2/mvs_category remains.

Parameter Type Default Description
search string (none) Filter by name
per_page int 20 Results per page (max: 100)
orderby string name name or count

Auth: Capability - create_tag_permissions_check (any user who can upload media).

Create a new tag. Body: name (required), optional slug.

Auth: Public.

Return top tags with usage counts for a tag cloud. Optional limit (default 50, max 200).

Auth: Capability - admin (moderate_mvs_media).

Merge one tag into another. All media on source_id are re-tagged with target_id and source_id is deleted.

{ "source_id": 12, "target_id": 7 }

Auth: Capability - admin.

Rename a tag.

{ "name": "New Tag Name" }

Auth: Capability - admin.

Delete a tag.


Auth: Authenticated.

List the current user’s notifications.

Parameter Type Default Description
per_page int 20 Items per page (max: 100)
page int 1 Page number
filter string all Filter set (e.g. all, unread)

The total count is returned in the X-WP-Total header.

Auth: Authenticated.

Return the current user’s unread notification count.

Auth: Authenticated.

Mark notifications as read. Pass an ids array to mark specific notifications, or omit it to mark all as read.

{ "ids": [12, 13, 14] }

Auth: Authenticated. (New in 2.6.0)

Where the current user was @mentioned (comments and media descriptions), newest first. Each item is the standard media object plus a mention object:

{
"id": 123,
"title": "Harbour at dusk",
"mention": {
"context": "description",
"comment_id": 0,
"created_at": "2026-09-24 10:15:00",
"by": { "id": 7, "name": "Ana" }
}
}

by is the comment’s author for a comment mention and the media owner for a description mention. Items the caller can no longer open are left out, and X-WP-Total / X-WP-TotalPages drop with them. Supports page and per_page (max 100).


Register a member’s device so the site can deliver push notifications for new in-app notifications. Added in 2.4.0. Both routes require an authenticated member and upsert into the mvs_device_tokens table. This is the Free generic device-token surface, backed by Social/PushService.php; when a new in-app notification is created, PushService fires the action mvs_push_send( int $user_id, array $tokens, array $payload ) for a push-delivery integration to send, gated by the filter mvs_push_should_send (return false to suppress). Pro’s Expo push at POST /mvs-pro/v1/push/register-device (table mvs_pro_push_devices) is separate and additional - neither replaces the other.

Auth: Authenticated.

Register (upsert) a device push token for the current member.

Field Required Description
platform Yes One of ios, android, web
token Yes The push token string
{ "platform": "ios", "token": "abc123..." }

Auth: Authenticated.

Unregister a device push token.

Field Required Description
token Yes The push token string to remove
{ "token": "abc123..." }

Added in 1.9.0 to support a native mobile/headless client: a public pre-login config call, an interest-picker onboarding flow, and “people you may know” suggestions. See mvs_app_config_features and related filters for how Free/Pro contribute to /app/config.

Auth: Public.

Single call a client makes before theming itself and deciding which feature surfaces to mount. Returns only what the core /wp-json/ index cannot express (branding + feature flags) - site name, description, icon, and auth come from the core index, never restated here.

Response:

{
"accent_color": null,
"logo_url": null,
"login_bg_url": null,
"dark_mode_default": false,
"layout": "grid",
"pro_active": true,
"features": {
"messaging": true,
"reactions": true,
"comments": true,
"favorites": true,
"albums": true,
"collections": true,
"follows": true,
"notifications": true,
"activity": true
}
}

features.messaging is false when the Messages switch is off (mvs_messaging_enabled) or mvs_dm_access is nobody/disabled/none. Hide the app’s Messages tab when it is false. Pro extends features with its own toggles (battles, challenges, tournaments, boosts, streaks, video, stories, …) and can populate accent_color / logo_url / login_bg_url / dark_mode_default / layout from its Mobile App Branding settings.

Auth: Public.

Available interest chips for the onboarding picker - the top 40 mvs_category terms by usage count, each with a representative public cover thumbnail. Cached (transient, default 1 hour, filterable via mvs_app_interests_cache_ttl).

Response:

[
{ "id": 12, "name": "Nature", "slug": "nature", "count": 84, "cover_url": "https://example.com/.../serve?..." }
]

Auth: Authenticated.

The current user’s saved interest picks.

Response:

{ "interest_ids": [12, 19] }

Auth: Authenticated.

Save the current user’s interest picks. Only valid mvs_category term IDs are kept; unknown IDs are silently dropped. Saving also marks the viewer as onboarded (mvs_onboarded user meta), so a client doesn’t have to separately call /me/onboarding/complete.

{ "interest_ids": [12, 19, 4] }
Field Required Description
interest_ids Yes Array of mvs_category term IDs

Response: { "interest_ids": [12, 19, 4] } (filtered to valid term IDs).

Auth: Authenticated.

“People you may know” - ranked creators (popularity + interest overlap with the viewer’s picks), excluding the viewer, users they already follow, and blocked users. Each result carries up to 3 sample public-media thumbnails for the suggestion card.

Parameter Type Default Description
limit int (service default) Max results, clamped to 1-50

Response:

[
{
"id": 55,
"name": "Jane Smith",
"avatar": "https://example.com/avatar.jpg",
"profile_url": "https://example.com/media/@jane/",
"follower_count": 120,
"is_following": false,
"sample_media": ["https://example.com/.../thumb1.jpg"]
}
]

The candidate pool is cached (default 1 hour, filterable via mvs_suggestions_cache_ttl).

Auth: Authenticated.

Explicitly flag the current user as onboarded (mvs_onboarded user meta), for clients whose first-session flow doesn’t end with saving interests. Idempotent.

Response: { "onboarded": true }


Auth: Authenticated (per-user state).

Dismiss the admin welcome banner for the current user.


Auth: Authenticated.

Record that the current member has closed a dismissible frontend banner, so it never renders again for them on any device. Server-side rather than localStorage, because a banner painted and then removed by JavaScript collapses the layout under the reader’s cursor.

Field Required Description
key Yes Identifier of the banner being dismissed (sanitized with sanitize_key)
{ "key": "profile_prompt" }

Auth: Public (private events never appear; following scope is empty for anonymous callers).

Return the activity feed.

Parameter Type Default Description
scope string public public (all public media) or following (followed users)
per_page int 20 Items per page (max: 100)
page int 1 Page number

Auth: Public.

Return a user’s public activity (uploads, album creations, reactions). Supports page, per_page.

The feed (mvs_activity) keeps 90 days by default; older events are removed by the daily retention job. Change the window with the mvs_activity_retention_days filter (0 keeps everything).


Direct-messaging routes share the mvs/v1 namespace. All require authentication. Conversations started by users you do not follow land in the Requests tab until accepted or declined.

List the current user’s conversations.

Parameter Type Default Description
tab string all all, unread, or requests
per_page int 20 Conversations per page (max: 50)
page int 1 Page number

Start a new conversation.

{ "recipient_id": 42, "as_request": false }
Field Required Default Description
recipient_id Yes - User ID to start (or resume) a conversation with
as_request No false When true, force the conversation to open as a pending message request (lands in the recipient’s Requests tab and must be accepted/declined) instead of an active thread - even if the sender/recipient relationship would otherwise allow a direct thread. Lets a native app open a “message request” flow explicitly through mvs/v1 alone (1.8.0).

Response: 201 Created with the new conversation object, or 200 with the existing one when the two members already have a direct conversation. Refusals carry an error code and a readable message: 403 cannot_message_self (your own ID), 403 blocked, 403 dms_disabled, 403 account_too_new, 429 rate_limited, 400 invalid_recipient.

Get a single conversation’s metadata and participants.

Conversation objects carry is_pinned, is_muted and is_archived as booleans (true or false), not 0 and 1 strings. Before 2.6.2 a client in JavaScript read every conversation as pinned, because "0" is truthy.

Update the current user’s per-conversation preferences.

{
"is_muted": true,
"is_pinned": false,
"is_archived": false
}

Leave (soft-delete) the conversation for the current user.

List messages in a conversation (newest-first).

Parameter Type Default Description
per_page int 30 Messages per page (max: 100)
before int 0 Return messages with ID less than this (cursor pagination)

Send a message.

{
"content": "Hey, love the photo!",
"message_type": "text",
"media_id": null,
"attachment_id": null,
"parent_id": null,
"metadata": {}
}
Field Required Description
content Yes (unless an attachment/media is sent) Message text
message_type No text (default) or media
media_id No Attach an existing media post
attachment_id No Attach a file uploaded via POST /messages/upload
parent_id No Reply to this message ID
metadata No Arbitrary structured metadata

Mark all messages in the conversation as read for the current user.

Send a typing-indicator event (no persistent storage; fires a real-time event only).

Accept a message request - moves the conversation from Requests to All.

Decline a message request - removes the conversation from the inbox.

Soft-delete a message for the current user (content hidden, record retained).

Hard-delete (unsend) a message. Only available within the edit window and only for the message owner.

Add an emoji reaction to a message.

{ "emoji": "heart" }

Remove your emoji reaction from a message.

Upload an attachment for use in a DM. Returns a reference ID to pass as attachment_id (or media_id) when sending the message. Body: multipart/form-data with a single file field.

{ "media_id": 204, "url": "https://example.com/..." }

Since 2.6.2 a chat attachment lives only in its conversation. It is not listed in My Media, GET /media or the WordPress Media Library, and it opens only for the people in the conversation. A file uploaded but never sent is deleted after 24 hours (filter mvs_unsent_chat_file_hours).

Return the total unread message count for the current user.

{ "count": 3 }

Long-poll for new messages. The server holds the connection open and responds as soon as a new message arrives or the timeout is reached.

Parameter Type Default Description
since int (required) Return messages with ID greater than this value
conversation_id int 0 Scope the poll to a single conversation

All errors follow the WP REST API error format:

{
"code": "mvs_invalid_type",
"message": "This file type is not allowed.",
"data": { "status": 400 }
}

Common error codes:

Code Status Meaning
mvs_invalid_type 400 MIME type not in allowed list
mvs_file_too_large 400 File exceeds max upload size
mvs_blocked_extension 400 Dangerous file extension
mvs_no_ids 400 Bulk request had no media IDs
mvs_duplicate 409 Duplicate file (when duplicate_action=skip)
mvs_not_found 404 Resource not found
mvs_user_not_found 404 User not found
mvs_not_logged_in / mvs_unauthorized 401 Authentication required
mvs_forbidden / rest_forbidden 403 Access denied by privacy/capability rules
mvs_storage_failed 500 Storage driver error
(rate limit) 429 Too many requests

Routes for obtaining the credentials the rest of the API expects. The app-auth filters that govern this flow (mvs_app_password_login_enabled, mvs_app_connect_schemes, mvs_app_scheme, mvs_app_credential_issued) are documented in Hooks & Filters.

Return a fresh wp_rest nonce for the current session.

Auth: Authenticated (cookie).

{ "nonce": "a1b2c3d4e5" }

Browser clients that keep a page open longer than the nonce lifetime call this to refresh rather than reloading the page.

Exchange a WordPress username and password for an Application Password - the credential a mobile or desktop client actually stores.

Auth: Public by necessity. This is how a member obtains their first credential, so there is nothing to authenticate with yet.

Parameter Type Required Description
username string yes Email address or username.
password string yes Account password.
app_name string no Name shown beside this credential in the member’s profile.
app_id string no Stable per-install id, so a repeat sign-in replaces the existing row instead of adding another.

Because it is unauthenticated, this route is guarded harder than any other: a site-owner switch (mvs_app_password_login_enabled), a TLS requirement, uniform failure responses that do not reveal whether a username exists, the suspension gate, and rate limiting applied before any credential is read. Accounts with two-factor authentication receive 409 rather than a silent 2FA bypass.

Always send this over HTTPS. Store the returned credential in the platform keychain, never in plain preferences.


Schedule deletion of the authenticated member’s own account.

Auth: Authenticated.

Parameter Type Required Description
confirm string yes Must be the literal string DELETE.
password string conditional The account password, re-entered. Required unless mvs_account_deletion_password_required is filtered to false.

Deletion is not immediate. The request starts a grace period (default 30 days, filterable via mvs_account_deletion_grace_days; return 0 to delete on request). During the grace period the member can still cancel.

Return the authenticated member’s pending deletion request, if any - including when it is scheduled to execute.

Auth: Authenticated.

Cancel a pending deletion request and restore the account to normal standing.

Auth: Authenticated.

These three routes are the member-facing half of GDPR erasure. The admin-facing export and erasure tools are covered in GDPR & Privacy.

The authenticated member’s own usage ledger - one row per upload.

Auth: Authenticated.

Parameter Type Default Description
per_page integer 20 Rows per page.
page integer 1 Page number.

Pairs with the [mvs_usage_history] shortcode, which renders the same data.


These sit alongside the messaging routes documented above.

Every media attachment shared in one conversation, newest first. This is what backs the “shared media” panel in a chat.

Auth: Authenticated, and the caller must be a participant.

Parameter Type Default Range Description
per_page integer 60 1-200 Attachments per page.

Full-text search within a single conversation.

Auth: Authenticated, and the caller must be a participant.

Parameter Type Required Default Range Description
q string yes - - Search term.
per_page integer no 50 1-100 Results per page.

Search is scoped to the one conversation in the path. There is no cross-conversation search endpoint.