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 path | Result |
|---|---|
GET /players | Curated Legends; community profiles are excluded |
GET /players/community | Discoverable community profiles |
GET /players/featured | Featured Legends |
GET /players/me | Your linked profile; requires authentication |
GET /players/:id | A profile, subject to visibility rules |
GET /players/:id/follow-status | Follower count and optional signed-in follow state |
GET /players/:id/relationships/followers | Followers, subject to relationship-list privacy |
GET /players/:id/relationships/following | Following, 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 path | Input / behavior |
|---|---|
GET /players/:id/comments | Optional sort=newest, oldest, or popular; nested tree with like counts |
POST /players/:id/comments | JSON body and optional parentId for a reply |
PUT /players/:id/comments/:commentId | JSON body; edit your own comment |
DELETE /players/:id/comments/:commentId | Author, profile owner or authorized moderator |
POST /players/:id/comments/:commentId/like | Toggle your like |
POST /players/:id/comments/:commentId/pin | Profile-owner/moderator pin action |
POST /players/:id/comments/:commentId/report | Report 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/:id | File field | Purpose |
|---|---|---|
/upload | image | Avatar, banner, gallery or comment image; type selects the use |
/upload-feed-media | media | Image/GIF/video for a social post |
/upload-font | font | Supported WOFF2, WOFF, TTF or OTF profile font |
/upload-intro-video | video | Patron introduction video |
/upload-comment-voice | audio | Voice comment, subject to membership and duration limits |
/upload-audio | audio | Patron 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.