Skip to main content

Club management: VRChat permissions and action research

Research date: 2026-09-09. Status: source-backed capability research and current recommendations. No authenticated requests, credentials, provider writes, or application changes. This extends the analytics research into the separately requested member-management screen and bot actions.

Findings​

VRChat exposes a usable set of group-management operations in the community API specification: member lookup, join requests, invitations, removals, bans, role assignment/editing, posts, and instance creation/closure. The bot can be an ordinary group member with explicit permissions; ownership is not the minimum for these routine features. However, most endpoint pages do not specify the complete authorization predicate. The matrix below is a candidate minimum role configuration, not a claim of successful live execution.

Three identities must stay distinct: the VRDex staff member requesting the action, the VRChat service account executing it, and the target member. Analytics access must not automatically grant management powers.

Evidence levels​

  • The official VRChat Groups page describes UI permissions and their dependencies. It identifies itself as reviewed official information.
  • The community-maintained permission enum supplies machine keys. It is source code for the unofficial specification, not a first-party stable API contract.
  • Endpoint references below establish methods, paths, request shapes, and documented responses. An undocumented permission condition, role restriction, or failure remains UNKNOWN until a bounded proof.

Capability matrix​

All group-relative paths below begin /groups/{groupId}. Permission mapping combines the official UI descriptions with the community enum. A plus sign means a dependency/additional grant, not an alternative.

CapabilityDocumented endpointCandidate minimum bot permissionConfidence and detail
Member directoryGET /membersgroup-members-viewall; add group-members-manage for management sorting/filteringUI-derived. Directory excludes caller; merge its myMember separately.
Search membersGET /members/searchgroup-members-viewall + candidate group-members-manageExact minimum UNKNOWN. Search is display-name based; query minimum three characters, page maximum 100.
Member detailGET /members/{userId}Candidate group-members-viewall; group-members-manage for management dataExact field visibility UNKNOWN. Do not assume all returned management fields belong in analytics.
Audit historyGET /auditLogsgroup-audit-viewUI-derived. Independent of permission to perform the logged action.
List requestsGET /requestsgroup-invites-manageUI-derived; verify read behavior with the intended role.
Accept/deny join requestPUT /requests/{userId}group-invites-manageAPI documents accept/deny; accept example uses action: accept. Exact block-request payload not verified.
List/send/cancel invitationsGET /invites, POST /invites, DELETE /invites/{userId}group-invites-manageInvite body identifies user. Sending an invitation does not accept it for the recipient.
Remove group memberDELETE /members/{userId}group-members-remove + group-members-manageEndpoint explicitly names Remove Group Members; dependency comes from official UI. This removes group membership, not merely presence in one instance.
Ban/unban and ban listPOST /bans, DELETE /bans/{userId}group-bans-manage + group-members-manageUI-derived; verify effects for current members and nonmembers. Do not treat unban as automatic rejoin.
Assign/remove a member's rolePUT / DELETE /members/{userId}/roles/{groupRoleId}group-roles-assign + group-members-manageUI-derived. Assignment is a distinct permission from editing role definitions.
Create/edit/delete rolePOST /roles, PUT / DELETE /roles/{groupRoleId}group-roles-manageUI-derived. Grantable permissions, management roles, and target restrictions need validation.
Edit Everyone permissionsSame role-edit familygroup-default-role-manage + group-roles-manageSeparate high-impact capability. Do not bundle into routine member operations.
Publish announcements as postsPOST /postsCandidate group-announcement-managePayload includes title/text, visibility, and sendNotification; exact permission and limits need proof.
Create public group instancePOST /instances, absolute pathgroup-instance-public-createUI-derived. Private groups cannot create public instances.
Create Group+ instanceSame instance-create endpointgroup-instance-plus-createUI-derived.
Create members-only instanceSame instance-create endpointCandidate group-instance-open-createUI-to-key mapping inferred; confirm against live permission catalog help text.
Restrict members-only instance by roleSame instance-create familyCandidate group-instance-restricted-create + group-instance-open-createInferred key mapping plus official dependency.
Add age restriction / calendar linkSame instance-create familygroup-instance-age-gated-create / group-instance-calendar-link, in addition to base creation permissionUI-derived; selected instance options add requirements.
Close group instanceDELETE /instances/{worldId}:{instanceId}, absolute pathgroup-instance-manageExplicit endpoint authorization for group-owned instances. Personal instances may instead be closed by their owner.
Live in-instance moderationNo corresponding remote warn/mute/kick route established heregroup-instance-moderate existsPermission existence is not proof of a remote management endpoint. Keep separate from group remove/ban and from closing an instance.

The dependencies for role assignment, bans, member removal, and Everyone editing are documented in the official permission table. Do not request * as a convenience. Unknown minima should be tested with a purpose-built role, not resolved by permanently granting every permission.

Discovering actual bot capability​

GET /groups/{groupId}/permissions returns the available permission catalog, not a statement that the caller possesses every listed permission. Its schema includes allowedToAdd, dependsOn, machine name, display name, help text, and management classification. allowedToAdd means the caller may add that permission to a role; it is not the same fact as the bot holding the permission itself.

The GroupMyMember schema exposes the bot's own permissions, role IDs, membership status, and has2FA. The role schema includes requiresTwoFactor, self-assignment, automatic-on-join, management classification, default-role flag, order, and purchase requirements.

Current recommendation: onboarding compares the selected VRDex features with refreshed own-member grants and catalog metadata, then shows missing permissions per capability. Perform a fresh authorization check before writes. Revoke a capability when its grants disappear, without disabling unrelated analytics. Role names such as Admin are not authorization evidence.

The official page says 2FA-gated roles only apply permissions to members meeting that requirement. It also protects owner permissions and the Everyone role. The inspected sources do not establish a Discord-style numeric hierarchy rule for editing or assigning higher roles. An order field alone does not prove such a rule. Test management-role assignment, roles with permissions the bot lacks, self-role changes, and protected targets before exposing them. Official roles, role schema

Important action semantics​

Announcements: the legacy POST /announcement endpoint warns that it removes existing announcements and directs callers to posts instead. Use the modern post family for a new composer. The post response exposes author/editor IDs. Notification delivery should be an explicit composer choice, separately previewed from saving/publishing content.

Instance closure: the close reference supports a future closedAt and hardClose, default false. Its description defines closedAt as preventing subsequent joins. Do not label normal closure as kicking all current occupants or final instance destruction. Hard-close effects need their own proof and confirmation copy. Re-closing an already closed instance can return 403, so not every 403 means a missing grant.

Invitations: a manager sends or cancels another user's invitation; the recipient joins as themselves. The join endpoint uses the authenticated account and optionally an invite ID. Bot onboarding may accept an invitation for the bot, but the bot cannot use its session to accept an invitation as a human recipient.

Ownership: transfer initiation explicitly requires authentication as current owner; acceptance requires the targeted recipient. A management role does not substitute. Keep transfer outside routine bot permissions. The delete-group endpoint exists but the inspected page does not establish its complete authorization requirements. Exclude deletion from routine club management until separately scoped; do not claim an unverified owner-only predicate as fact.

Actor attribution and execution design​

The audit entry schema records actor, target, event type, ID, and time. Inference: when a shared bot performs a provider action, upstream account attribution identifies the bot, not automatically the human who clicked VRDex. No impersonation field was established by these action references.

Current recommendation: retain a private VRDex action record containing requesting staff ID, executing service-account reference, immutable group/target IDs, requested operation, time, result, and correlated provider audit ID where available. Display the requester and bot actor separately. A provider audit row is valuable corroboration, but its delay or absence cannot prove a timed-out write failed.

Permission to use an action is the intersection of the human's VRDex capability, connected group's feature enablement, and the bot's current provider grant. Giving the bot ban permission must not give every analytics viewer ban permission. Role changes must not allow a user to escalate their own VRDex authority indirectly.

Limits, failures, and proof checklist​

Member listing supports maximum 100 per page; search additionally requires a three-character query. Pagination is not a point-in-time snapshot. Member list, search

The action references document combinations of 400, 401, 403, and 404, but their lists/examples are not exhaustive. For example, canceling a nonexistent invitation can return 400. Treat already-changed state separately from insufficient permission; refresh the target before offering a retry. Cancel invite

VRChat requires identifying User-Agent, caching, metering, randomized polling, and error backoff. No stable numeric write quota or general mutation-idempotency guarantee was established. Its guidelines also retain restrictions on credentials and acting from a different device/IP; expanded write scope is not a new provider exemption. Creator Guidelines

Before enabling writes, perform a separately authorized test-group proof of each chosen permission bundle, dependency, 2FA state, protected target, duplicate/already-completed action, permission revocation, and upstream audit attribution. Use an internal action ID and serialize conflicting actions for the same target. A network timeout after submission is indeterminate: reconcile state before retrying, especially for invitations, posts, and instance creation. Bulk operations require per-target outcomes and bounded concurrency, not a single misleading success banner.

Recommended onboarding bundles for discussion: directory and audit; membership operations; announcements; instance operations; role administration. Each is optional and exposes its actual provider requirements. A single bot can execute multiple bundles if granted them; the product should not require role editing, ownership, or live-instance entry merely to show analytics or approve a join request.

Follow-up: bulk invitations to running instances​

User direction: bulk invitations cover both group membership and running instances. These require separate execution paths and recipient eligibility rules.

QuestionEvidence and disposition
Membership versus instance routeMembership invitations use the previously documented /groups/{groupId}/invites. Instance invitations use POST /invite/{userId}, with a target instance and optional message slot. No separate group-instance bulk-invite route was established in the inspected specification.
Friendship requirementThe instance-invite reference documents 403 when the sender and recipient are not friends. Plan eligibility around friendship with the executing bot account, not friendship with the VRDex staff requester. Group membership alone does not prove eligibility. No group-role exemption was established.
Sender location or ownershipThe request explicitly supplies an instance identifier, but the reference does not establish whether the sender must occupy, own, or merely access that instance. Therefore sending while the bot has no running VRChat client remains UNKNOWN, not impossible and not proved. Test bot-created and staff-created instances separately.
Self invitePOST /invite/myself/to/{worldId}:{instanceId} invites the authenticated account itself. It is not a way for the bot to send an arbitrary person's self-invite.
Offline recipientsOfficial 2024.3.2 release notes added invites to friends active on the website/mobile app or receiving mobile push notifications. Do not categorically exclude everyone labeled offline. Actual API behavior and totally offline retention/expiry remain unverified.
Group access and restrictionsAn invitation should not be presented as bypassing membership, role restrictions, bans, age gating, or other entry checks. Exact invite-versus-entry enforcement needs proof. Official release notes explicitly mention an error when accepting an invite request where the requester cannot be invited. Release notes
CapacityInvite success is not a reserved seat. Whether a full/queued instance accepts invite submissions is UNKNOWN here; the existing instance capacity/queue fields are observations, not delivery guarantees.
Meaning of successThe invite endpoint says it returns the sent notification. That supports “sent” or “provider accepted”, not received, read, accepted by the person, or joined. Its generic example misleadingly shows a friend-request notification, so validate actual response shape. Invite reference
Rate limits and bulkNo stable numeric invitation quota, bulk atomicity, delivery receipt, or idempotency guarantee was established. Use bounded per-recipient work and provider backoff; do not copy a guessed “safe invites per minute” figure.

Current recommendation for recipient selection: resolve immutable user IDs, distinguish bot-friend eligibility from group membership, display unknown eligibility separately, and recheck destination availability and current access before dispatch. Keep membership invitations separate from event-instance invitations even when the same person receives both. Never silently send a friend request to make someone eligible.

For scheduled event invitations, save the intended event/instance association, recipient selection, staff authorization, and send window. At execution, resolve a still-valid running destination; do not substitute another instance without an explicit rule. Skip already-observed occupants when reliable presence is available, record per-recipient outcomes, and expire unsent work when its destination or send window ends. A timeout after submission is indeterminate; avoid automatic repeated notifications unless reconciliation establishes that retry is appropriate. These are proposed VRDex safeguards, not provider guarantees.

Required bounded proof before advertising bot-sent instance invites: bot-friend and nonfriend recipients; group member and guest; members-only, Group+, and public instances; bot-created versus staff-created destinations; sender with no client versus actually present; online, web/mobile, and offline recipients; full, queued, closed, and role-restricted destinations. Verify notification identity and observed arrival separately. This research does not authorize entering instances or sending test invitations.