Skip to main content

Profiles, comments and uploads

All paths below are relative to https://api.vrchatlegends.com/api. :id is the current profile slug or community profile ID, not the permanent account ID. Resolve the current profile using the user directory when you need a durable account reference. URL-encode path parameters.

Read profiles​

Method and pathResult
GET /playersCurated Legends; community profiles are excluded
GET /players/communityDiscoverable community profiles
GET /players/featuredFeatured Legends
GET /players/meYour linked profile; requires authentication
GET /players/:idA profile, subject to visibility rules
GET /players/:id/follow-statusFollower count and optional signed-in follow state
GET /players/:id/relationships/followersFollowers, subject to relationship-list privacy
GET /players/:id/relationships/followingFollowing, subject to relationship-list privacy

Public discovery does not grant access to private profiles or private relationship lists. Do not infer account identity from a display name: names can change and need not be unique.

Edit a profile​

PUT /players/:id accepts a JSON object with the fields to update. Authentication and ownership are required. API keys need profile:write or legends:write. Field permissions, tier entitlements and community limits still apply.

// Run on your server. Never ship API_KEY in client-side JavaScript.
const response = await fetch(
`https://api.vrchatlegends.com/api/players/${encodeURIComponent(profileId)}`,
{
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ bio: 'My updated profile biography.' }),
},
);
const result = await response.json();
if (!response.ok) throw new Error(result.error || `HTTP ${response.status}`);

Array fields such as world_links, avatar_links, group_links, videos, and gallery replace their respective values. Read the current profile first and preserve entries you intend to keep. Do not send empty arrays for fields you did not edit.

POST /players/:id/rename changes a curated profile's name/slug where allowed; it requires legends:write for API keys. Community profile IDs cannot be renamed. DELETE /players/:id deletes your page where allowed. Both operations can affect existing links; deletion is not a routine update.

Profile comments​

Method and pathInput / behavior
GET /players/:id/commentsOptional sort=newest, oldest, or popular; nested tree with like counts
POST /players/:id/commentsJSON body and optional parentId for a reply
PUT /players/:id/comments/:commentIdJSON body; edit your own comment
DELETE /players/:id/comments/:commentIdAuthor, profile owner or authorized moderator
POST /players/:id/comments/:commentId/likeToggle your like
POST /players/:id/comments/:commentId/pinProfile-owner/moderator pin action
POST /players/:id/comments/:commentId/reportReport for moderation

Comment writes require a linked profile and comments:write for API keys. Ownership, blocks, content filtering and archived-profile restrictions are checked separately. A toggle is not idempotent: do not automatically replay a like request after losing its response.

curl --fail-with-body 'https://api.vrchatlegends.com/api/players/PROFILE_ID/comments' \
-H "Authorization: Bearer $VRCL_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"body":"Hello from my integration!"}'

Uploads​

Use multipart form data. Let your HTTP library set the multipart boundary; do not manually set a JSON content type. Upload routes require authentication, appropriate ownership or comment rights, and the legends:write permission check (with its supported aliases). Tier checks cannot be bypassed with a key.

POST path under /players/:idFile fieldPurpose
/uploadimageAvatar, banner, gallery or comment image; type selects the use
/upload-feed-mediamediaImage/GIF/video for a social post
/upload-fontfontSupported WOFF2, WOFF, TTF or OTF profile font
/upload-intro-videovideoPatron introduction video
/upload-comment-voiceaudioVoice comment, subject to membership and duration limits
/upload-audioaudioPatron profile soundtrack; optional title

Read GET /social/limits for the current viewer's social upload limits. Uploading feed media returns a media descriptor; send that descriptor with the subsequent post. Do not invent media URLs.

Profile audio uploads are screened before publication. Matching recordings are blocked; unavailable screening fails closed. Screening is not proof of ownership or a comprehensive copyright detector. Only upload audio you have permission to publish. The successful upload response includes the saved background_audio; arbitrary external URLs cannot be added through a profile update.

Linking and invitations​

Use the website's create-profile flow for VRChat verification. Its API steps are POST /players/verify-vrchat/start and POST /players/verify-vrchat/check. The code belongs in VRChat status, not bio. An existing verified account can be reused.

GET /invite/:inviteId returns invitation state. POST /invite/:inviteId/merge migrates an existing community profile after the invited Discord account signs in. The operation preserves profile content, ID and existing privacy; it must not be replayed after success. A used invite returns a conflict. The browser invitation flow handles Discord authorization at /invite/:inviteId/auth.