Friends API
Endpoints for friend links, requests, moderation, and live social snapshots.
Permissions
social:friends.readfor listing friends, requests, blocks, and live snapshotssocial:friends.writefor creating requests and reportssocial:friends.editfor accepting, declining, canceling, removing, blocking, unblocking, and metadata updates
If a permission node is missing in the database, the route currently allows access by default.
Endpoints
GET /v1/social/friends
Returns the authenticated user's friend list plus summary counts.
GET /v1/social/friends/requests
Returns incoming and outgoing requests for the authenticated user.
POST /v1/social/friends/requests
Creates a new friend request. Requests are rejected when the recipient has disabled allowFriendRequests in GET /v1/profile/settings.
Body:
{
"targetId": "uuid",
"targetName": "playerName",
"note": "optional"
}Either targetId or targetName is required.
POST /v1/social/friends/requests/{id}/accept
Accepts an incoming request and creates the friend link in both directions.
POST /v1/social/friends/requests/{id}/decline
Declines an incoming request.
DELETE /v1/social/friends/requests/{id}
Cancels an outgoing request or removes a pending request visible to the caller.
PATCH /v1/social/friends/{friendId}
Updates caller-owned metadata for one friend link.
Body:
{
"favorite": true,
"visibility": "DEFAULT"
}Supported visibility values:
DEFAULTLIMITEDHIDDEN
Unknown values currently normalize back to DEFAULT.
DELETE /v1/social/friends/{friendId}
Removes the friendship in both directions.
GET /v1/social/friends/blocks
Lists blocked users for the authenticated caller.
POST /v1/social/friends/blocks
Creates or updates a block entry and removes any existing friend links or pending requests between the caller and the blocked user.
Body:
{
"targetId": "uuid",
"reason": "optional"
}DELETE /v1/social/friends/blocks/{targetId}
Removes an existing block entry.
POST /v1/social/friends/reports
Creates a profile moderation report for a target user.
Body:
{
"targetId": "uuid",
"reason": "optional"
}GET /v1/social/friends/live
WebSocket endpoint that emits an initial snapshot and then only sends a new payload when the friend/request snapshot changes.
Auth:
Authorization: Bearer <token>header, orSec-WebSocket-Protocol: uebliche-bearer.<base64url-token>for WebSocket clients that cannot set custom headers.
Optional query parameters:
interval: polling interval in seconds, clamped server-side
Server friends endpoints
Server friends endpoints require Authorization: Bearer <CONNECT_SERVER_SECRET> and X-Server-Id. They use the same Public API friends service as the user endpoints, including blocks, allowFriendRequests, permission-based friend limits, request TTLs, notifications, flame-streak enrichment, and party enrichment.
POST /v1/social/friends/server/overviewwith{ "actorId": "uuid" }POST /v1/social/friends/server/requestswith{ "actorId": "uuid", "targetId": "uuid", "targetName": "optional fallback", "note": "optional" }POST /v1/social/friends/server/requests/acceptwith{ "actorId": "uuid", "targetId": "uuid", "targetName": "optional fallback" }POST /v1/social/friends/server/requests/declinewith{ "actorId": "uuid", "targetId": "uuid", "targetName": "optional fallback" }POST /v1/social/friends/server/requests/cancelwith{ "actorId": "uuid", "targetId": "uuid", "targetName": "optional fallback" }DELETE /v1/social/friends/serverwith{ "actorId": "uuid", "targetId": "uuid", "targetName": "optional fallback" }
Request mutations may identify the other player by targetId or targetName, so server-side clients do not need to duplicate Public API user lookup behavior. Sending a request returns the created request entry. Accept, decline, cancel, and remove return 204 No Content.
Server overview response:
{
"friends": [],
"counts": {
"total": 0,
"favorites": 0,
"online": 0,
"max": 250
},
"self": null,
"incoming": [],
"outgoing": [],
"requests": {
"incoming": [],
"outgoing": []
}
}GET /v1/social/party
Returns the caller's current party and pending invites.
POST /v1/social/party
Creates a party for the caller when none exists, or returns the existing party snapshot. This is a breaking change from the old leave behavior.
POST /v1/social/party/leave
Leaves the caller's current party. If the last member leaves, the party is removed.
PUT /v1/social/party/lobby/selection
Updates the current party lobby selection. The caller must be the party leader or be included in party.lobby.selectorIds. Updating the selection increments party.lobby.revision and clears all ready states.
{
"targetKind": "minigame",
"targetId": "ffa-ragemode-round",
"displayName": "FFA RageMode Round",
"serverAddress": "uebliche.games",
"minigame": {
"mode": "ffa",
"variant": "ragemode-round",
"roundBased": true
},
"profileRequirement": {
"minecraftVersion": "1.20.4",
"loader": "fabric",
"recommendedProfileId": "uebliche-games",
"recommendedProfileName": "Uebliche.games",
"recommendedProfileShareCode": "438Z2V",
"requiredMods": []
}
}PUT /v1/social/party/lobby/selectors
Updates which current party members may change the lobby selection. Only the party leader may call this endpoint. The leader is always kept in selectorIds.
{
"selectorIds": ["uuid"]
}PUT /v1/social/party/lobby/ready
Updates the caller's ready state for the selected party lobby target. ready=true requires profilePrepared=true. For round-based minigames, the API creates party.lobby.launchSignal once all current party members are ready.
{
"ready": true,
"profilePrepared": true,
"profileId": "uebliche-games",
"temporaryProfile": false,
"requirementHash": "profile-requirement-hash"
}DELETE /v1/social/party
Disbands the caller's current party. The caller must be the party leader.
POST /v1/social/party/invites
Sends a party invite and creates the caller's party when needed.
{
"targetId": "uuid",
"targetName": "optional fallback"
}POST /v1/social/party/invites/{partyId}/accept
Accepts a pending invite for the caller.
POST /v1/social/party/invites/{partyId}/decline
Declines a pending invite for the caller.
GET /v1/social/party/live
WebSocket endpoint that emits an initial party snapshot and then only sends a new payload when party membership or pending party invites change.
Auth:
Authorization: Bearer <token>header, orSec-WebSocket-Protocol: uebliche-bearer.<base64url-token>for WebSocket clients that cannot set custom headers.
Optional query parameters:
interval: polling interval in seconds, clamped server-side
Server party endpoints
Server party endpoints require Authorization: Bearer <CONNECT_SERVER_SECRET> and X-Server-Id.
POST /v1/social/party/server/overviewwith{ "actorId": "uuid" }POST /v1/social/party/serverwith{ "actorId": "uuid" }POST /v1/social/party/server/leavewith{ "actorId": "uuid" }DELETE /v1/social/party/serverwith{ "actorId": "uuid" }POST /v1/social/party/server/inviteswith{ "actorId": "uuid", "targetId": "uuid" }POST /v1/social/party/server/invites/{partyId}/acceptwith{ "actorId": "uuid" }POST /v1/social/party/server/invites/{partyId}/declinewith{ "actorId": "uuid" }POST /v1/social/party/server/lookupwith{ "playerIds": ["uuid"] }
Lookup response:
{
"memberships": [
{
"playerId": "uuid",
"partyId": "uuid",
"leader": true
}
],
"parties": []
}GET /v1/users/{id}/friends
Returns the same overview shape as the server friends overview for a specific user id. Requires social:friends.read.
Payloads
Friend entry
{
"friendId": "uuid",
"favorite": false,
"visibility": "DEFAULT",
"note": "optional",
"createdAt": "2026-01-07T12:00:00Z",
"acceptedAt": "2026-01-07T12:00:00Z",
"updatedAt": "2026-01-07T12:00:00Z",
"online": true,
"partyId": "uuid",
"name": "Player",
"status": {
"state": "ONLINE",
"timestamp": "2026-01-07T12:00:00Z"
},
"player": {
"id": "uuid",
"name": "Player",
"online": true,
"status": {
"state": "ONLINE",
"timestamp": "2026-01-07T12:00:00Z"
},
"partyId": "uuid"
},
"lastSeenAt": "2026-01-07T12:00:00Z"
}Request entry
{
"id": "objectId",
"senderId": "uuid",
"recipientId": "uuid",
"direction": "incoming",
"note": "optional",
"createdAt": "2026-01-07T12:00:00Z",
"expiresAt": "2026-01-14T12:00:00Z",
"player": {
"id": "uuid",
"name": "Player",
"online": false,
"status": {
"state": "OFFLINE",
"timestamp": "2026-01-07T12:00:00Z"
},
"partyId": null
}
}Block entry
{
"blockedUserId": "uuid",
"reason": "optional",
"createdAt": "2026-01-07T12:00:00Z",
"updatedAt": "2026-01-07T12:00:00Z"
}Friends snapshot
GET /v1/social/friends returns:
{
"friends": [],
"counts": {
"total": 0,
"favorites": 0,
"online": 0,
"max": 250
},
"self": null
}GET /v1/users/{id}/friends returns:
{
"friends": [],
"counts": {
"total": 0,
"favorites": 0,
"online": 0,
"max": 250
},
"self": null,
"incoming": [],
"outgoing": [],
"requests": {
"incoming": [],
"outgoing": []
}
}GET /v1/social/friends/live emits:
{
"type": "friends_snapshot",
"friends": [],
"counts": {
"total": 0,
"favorites": 0,
"online": 0
},
"requests": {
"incoming": [],
"outgoing": []
}
}GET /v1/social/party/live emits the same shape as GET /v1/social/party:
{
"party": null,
"invites": []
}