APIMutation

Mutation

120 mutations, grouped by the domain their name starts with or names, in the order the schema lists them.

Invite 2

createInvite

createInvite(input: CreateInviteInput!): CreateInvitePayload!

No description in the schema.

signupWithInvite

Unified signup mutation for all token-based and open-mode registration paths.

In invite-only mode, exactly one of instanceInviteToken or workspaceInviteToken must be supplied. In open mode, all token fields must be absent. Refused with FORBIDDEN when serverInfo.signupRequiresKeys is true: new accounts then sign up with signupWithKey.

On success, sets session and CSRF cookies via AuthIntent.

Server 2

joinServerByInvite

No description in the schema.

createServer

createServer(input: CreateServerInput!): Server!

No description in the schema.

Message 9

sendMessage

sendMessage(input: SendMessageInput!): Message!

No description in the schema.

replyToMessage

replyToMessage(input: ReplyToMessageInput!): Message!

No description in the schema.

editMessage

editMessage(input: EditMessageInput!): Message!

No description in the schema.

forwardMessage

forwardMessage(input: ForwardMessageInput!): Message!

No description in the schema.

deleteMessage

deleteMessage(input: DeleteMessageInput!): Boolean!

No description in the schema.

pinMessage

pinMessage(input: PinMessageInput!): Boolean!

No description in the schema.

unpinMessage

unpinMessage(input: UnpinMessageInput!): Boolean!

No description in the schema.

sendEncryptedMessage

sendEncryptedMessage(input: SendEncryptedMessageInput!): Message!

An encrypted message under a client-chosen id, in the group's current epoch. Sending the same id and envelope again answers the stored message.

editEncryptedMessage

editEncryptedMessage(input: EditEncryptedMessageInput!): Message!

A new envelope carrying an encrypted message's complete new content.

Conversation 11

createConversation

createConversation(input: CreateConversationInput!): Conversation!

No description in the schema.

updateConversationTopic

updateConversationTopic(input: UpdateConversationTopicInput!): Conversation!

No description in the schema.

leaveConversation

leaveConversation(serverId: ID!, conversationId: ID!): Boolean!

Leave a channel or group (not a DM).

addConversationMembers

addConversationMembers( serverId: ID! conversationId: ID! userIds: [ID!]! ): Conversation!

Add (invite) workspace members to a channel or group the caller belongs to.

removeConversationMember

removeConversationMember( serverId: ID! conversationId: ID! userId: ID! ): Boolean!

Remove a member from a channel or group: Owner/Moderator may remove anyone, others only themselves.

setConversationArchived

setConversationArchived( serverId: ID! conversationId: ID! archived: Boolean! ): Conversation!

Archive or unarchive a channel (Owner/Moderator). Archived channels are read-only.

muteConversation

muteConversation(input: MuteConversationInput!): Boolean!

No description in the schema.

unmuteConversation

unmuteConversation(input: UnmuteConversationInput!): Boolean!

No description in the schema.

setConversationNotificationLevel

setConversationNotificationLevel( serverId: ID! conversationId: ID! level: NotificationLevel ): ConversationNotificationLevel!

Set the viewer's level for one conversation they can read; level: null goes back to the workspace default. muteConversation/unmuteConversation keep working alongside.

acceptConversationInvite

acceptConversationInvite(serverId: ID!, conversationId: ID!): Conversation!

Accept the caller's pending invitation (Conversation.pendingMemberIds): they become a member and a member's device adds theirs to the group. Needs a device set up for encryption (VALIDATION otherwise); already a member, it changes nothing; NOT_FOUND when the caller was not invited.

declineConversationInvite

declineConversationInvite(serverId: ID!, conversationId: ID!): Boolean!

Decline the caller's pending invitation; NOT_FOUND when there is none.

Channel 4

joinChannel

joinChannel(serverId: ID!, conversationId: ID!): Conversation!

Join a public, unarchived channel. Idempotent.

createChannelLens

createChannelLens(input: CreateChannelLensInput!): ChannelLens!

No description in the schema.

updateChannelLens

updateChannelLens(input: UpdateChannelLensInput!): ChannelLens!

No description in the schema.

deleteChannelLens

deleteChannelLens(serverId: ID!, lensId: ID!): Boolean!

No description in the schema.

Attachment 3

createAttachment

createAttachment(input: CreateAttachmentInput!): UploadTicket!

No description in the schema.

finalizeAttachment

finalizeAttachment(input: FinalizeAttachmentInput!): Attachment!

No description in the schema.

deleteAttachment

deleteAttachment(input: DeleteAttachmentInput!): Boolean!

No description in the schema.

Command 1

executeCommand

executeCommand(input: ExecuteCommandInput!): CommandResult!

No description in the schema.

User 3

createUserCommand

createUserCommand(input: CreateUserCommandInput!): Command!

No description in the schema.

updateUserCommand

updateUserCommand(input: UpdateUserCommandInput!): Command!

No description in the schema.

deleteUserCommand

deleteUserCommand(input: DeleteUserCommandInput!): Boolean!

No description in the schema.

Keybind 3

createKeybind

createKeybind(input: CreateKeybindInput!): Keybind!

No description in the schema.

updateKeybind

updateKeybind(input: UpdateKeybindInput!): Keybind!

No description in the schema.

deleteKeybind

deleteKeybind(input: DeleteKeybindInput!): Boolean!

No description in the schema.

Emoji 2

createCustomEmoji

createCustomEmoji(input: CreateCustomEmojiInput!): CustomEmoji!

No description in the schema.

deleteCustomEmoji

deleteCustomEmoji(emojiId: ID!): Boolean!

No description in the schema.

Macro 4

createMacro

createMacro(input: CreateMacroInput!): MacroDef!

No description in the schema.

updateMacro

updateMacro(input: UpdateMacroInput!): MacroDef!

No description in the schema.

deleteMacro

deleteMacro(macroId: ID!): Boolean!

No description in the schema.

executeMacro

executeMacro(input: ExecuteMacroInput!): CommandResult!

No description in the schema.

Workspace 10

setWorkspaceState

setWorkspaceState(input: SetWorkspaceStateInput!): WorkspaceStateEntryGql!

No description in the schema.

deleteWorkspaceState

deleteWorkspaceState(input: DeleteWorkspaceStateInput!): Boolean!

No description in the schema.

addWorkspacePlugin

addWorkspacePlugin(input: AddWorkspacePluginInput!): WorkspacePlugin!

Add the statement's plugin to the workspace's registry. Owner or Moderator.

updateWorkspacePlugin

updateWorkspacePlugin(input: UpdateWorkspacePluginInput!): WorkspacePlugin!

Change an entry's statement, status or bundle URL. Owner or Moderator.

removeWorkspacePlugin

removeWorkspacePlugin(serverId: ID!, pluginId: String!): Boolean!

Remove an entry from the workspace's registry. Owner or Moderator.

joinRemoteWorkspace

joinRemoteWorkspace(input: JoinRemoteWorkspaceInput!): RemoteJoinResult!

Join a workspace on another host: the relay presents the caller's identity, proof and delegation, and records the subscription.

transferWorkspaceOwnership

transferWorkspaceOwnership(input: TransferWorkspaceOwnershipInput!): Server!

Make another member the workspace's owner. The caller becomes a moderator; a workspace has exactly one owner, so this is the only way the owner role moves (setMemberRole never grants it). Both role changes are announced with MemberRoleChanged.

Errors

  • UNAUTHENTICATED: no session.
  • FORBIDDEN: the caller is not the owner.
  • NOT_FOUND: userId is not a member.
  • VALIDATION: the direct space, a guest as the new owner, or the caller themself.

deleteWorkspace

deleteWorkspace(input: DeleteWorkspaceInput!): DeleteWorkspacePayload!

Delete the workspace for good: its members, channels and conversations with their messages and files, invites, pins, workspace state, keybinds, pipelines, macros, plugins and custom emoji, and the notification rules scoped to it. Every member gets MemberLeft for themself and their event stream for the workspace ends; after that the workspace answers NOT_FOUND or FORBIDDEN like one they never joined.

Errors

  • UNAUTHENTICATED: no session.
  • FORBIDDEN: the caller is not the owner.
  • VALIDATION: the direct space, or confirmName is not the workspace's name.

setWorkspaceDmPolicy

setWorkspaceDmPolicy( workspaceId: ID! outsideFloor: DmOutsideFloor! memberDefault: DmMembers! ): WorkspaceDmPolicy!

Set a workspace's DM rules: the floor for DMs to its members from outside their workspaces, and how a DM from a fellow member arrives unless the recipient chose. The workspace's Owner only; anyone else gets FORBIDDEN.

setMyWorkspaceDmSetting

setMyWorkspaceDmSetting(workspaceId: ID!, members: DmMembers!): MyDmSettings!

Set how a DM from the members of one of the caller's workspaces arrives, whatever the workspace's default. NOT_FOUND unless the caller is a member.

Pipeline 4

createPipeline

createPipeline(input: CreatePipelineInput!): PipelineGql!

No description in the schema.

updatePipeline

updatePipeline(input: UpdatePipelineInput!): PipelineGql!

Replace a pipeline's definition. Allowed for its creator and for an Owner or Moderator of its workspace; anyone else gets FORBIDDEN.

deletePipeline

deletePipeline(pipelineId: ID!): Boolean!

Delete a pipeline. Allowed for its creator and for an Owner or Moderator of its workspace; anyone else gets FORBIDDEN.

togglePipeline

togglePipeline(pipelineId: ID!, enabled: Boolean!): PipelineGql!

Switch a pipeline on or off. Allowed for its creator and for an Owner or Moderator of its workspace; anyone else gets FORBIDDEN.

Report 5

reportMessage

reportMessage( serverId: ID! conversationId: ID! messageId: ID! reason: String! ): MessageReport!

Report a message to the workspace moderators. Any member who can read it, once per message (CONFLICT on a second report). Audited (chat.report_message).

resolveReport

resolveReport( serverId: ID! reportId: ID! outcome: ReportOutcome! ): MessageReport!

Close an open report as resolved or dismissed (Owner/Moderator). Audited (admin.resolve_report).

reportEncryptedMessage

reportEncryptedMessage(input: ReportEncryptedMessageInput!): Boolean!

Report an encrypted message by revealing its content and franking key; the server checks them against its receipt before the moderators see them.

reportDmRequest

reportDmRequest(id: ID!, reason: String!): Boolean!

Report a DM request as abuse; a pending one is ignored too.

instanceResolveReport

instanceResolveReport(id: ID!): InstanceAbuseReport!

Mark an abuse report resolved; NOT_FOUND when there is no such report. Instance operators only; anyone else gets FORBIDDEN.

ArgumentTypeDescription
idID!

The report's id.

Notification 2

updateNotificationSettings

updateNotificationSettings(serverId: ID!, input: UpdateNotificationSettingsInput!): NotificationSettings!

Replace the viewer's notification settings in the workspace (default level, keywords, daily do-not-disturb window, digest, reactions). Keywords: at most 20, each 2 to 40 characters.

markNotificationsRead

markNotificationsRead( serverId: ID! ids: [ID!] allBefore: DateTime ): Int!

Mark the viewer's notifications read: the given ids, or every notification created at or before allBefore (exactly one of the two). Returns how many changed.

Key 7

keyLoginChallenge

keyLoginChallenge: KeyLoginChallenge!

Start a key login: a single-use challenge for a device to sign. No session needed.

loginWithKey

loginWithKey(proof: SignedStatementInput!): LoginPayload!

Sign in with a login statement signed by an enrolled device key. Sets the same session cookie as login.

enrollIdentityKey

enrollIdentityKey(input: EnrollIdentityKeyInput!): KeyIdentity!

Bind a key identity to the signed-in account. The calling session becomes the new device's and every other session of the account ends. Afterwards the password no longer signs in.

rotateIdentityKey

rotateIdentityKey(input: RotateIdentityKeyInput!): KeyIdentity!

Append a rotation to the key log. A rotation signed by the recovery key works without a session, revokes every device and session, and enrolls the device given with it.

signupWithKey

Create an account from a key identity alone, with no password. The registration mode applies as for signupWithInvite (exactly one token in invite-only mode, none in open mode). An instance invite bound to an email address gives the account that address (EMAIL_TAKEN when another account has it); otherwise the account has no email. Signs the new account in on the device that signed up, setting the same session and CSRF cookies as signupWithInvite.

uploadMlsKeyPackages

uploadMlsKeyPackages(keyPackages: [String!]!): MlsKeyPackageStatus!

Store key packages of the session's device, all or none. A last-resort package replaces the device's previous one.

claimMlsKeyPackages

claimMlsKeyPackages(input: ClaimMlsKeyPackagesInput!): [ClaimedKeyPackage!]!

One key package per device waiting to be added; devices with none usable are left out.

Device 7

addDeviceKey

addDeviceKey(certificate: SignedStatementInput!): DeviceKey!

Add a device certified by the current identity key.

revokeDeviceKey

revokeDeviceKey(revocation: SignedStatementInput!): DeviceKey!

Revoke a device, signed by the identity key or by the device itself. Ends its sessions.

startDeviceLink

startDeviceLink: StartedDeviceLink!

Start linking a new device to the signed-in account. Cancels the account's previous live link. The link lives 10 minutes.

sendDeviceLinkOffer

sendDeviceLinkOffer(linkId: String!, offer: SealedMessageInput!): Boolean!

The new device's sealed offer. No session needed: the link id is the capability.

sendDeviceLinkAnswer

sendDeviceLinkAnswer(linkId: String!, answer: SealedMessageInput!): DeviceLink!

The old device's sealed answer, carrying the new device's certificate. The link then lives another 10 minutes.

completeDeviceLink

completeDeviceLink(linkId: String!): Boolean!

Called by the new device right after its first loginWithKey.

cancelDeviceLink

cancelDeviceLink(linkId: String!): Boolean!

Cancel a link from either device, with or without a session.

Relay 2

ackRelayItems

ackRelayItems(upTo: ID!): Boolean!

Move the session device's cursor up to upTo.

leaveRelay

leaveRelay: Boolean!

Cancel the caller's subscriptions at every host, then delete their queue, requests, contacts and blocks on this relay.

Other 39

login

login(input: LoginInput!): LoginPayload!

No description in the schema.

logout

logout: Boolean!

No description in the schema.

logoutOtherSessions

logoutOtherSessions: Int!

End every session of the signed-in account except this one. Returns how many ended.

toggleReaction

toggleReaction(input: ToggleReactionInput!): [ReactionGroup!]!

No description in the schema.

markAsRead

markAsRead(input: MarkAsReadInput!): Boolean!

No description in the schema.

markAllAsRead

markAllAsRead(input: MarkAllAsReadInput!): Boolean!

No description in the schema.

startTyping

startTyping(serverId: ID!, conversationId: ID!): Boolean!

Announce that the caller is typing in a direct conversation. Typing is announced in direct conversations only: the mutation answers true when it emitted a TypingStarted event and false when it did not, which is in a channel or a group, or on a repeat inside the throttle window.

heartbeat

heartbeat(input: HeartbeatInput!): Boolean!

No description in the schema.

requestPasswordReset

requestPasswordReset(username: String!): Boolean!

FEATURE_DISABLED while the operator has disabled email. Without SMTP the reset mail is logged instead of sent.

resetPassword

resetPassword(token: String!, newPassword: String!): Boolean!

No description in the schema.

updateMyProfile

updateMyProfile(input: UpdateMyProfileInput!): User!

Update fields on the authenticated user's profile.

Returns the full updated User so the client can refresh local cache without an extra me { ... } round-trip.

Errors

  • UNAUTHENTICATED — no session.
  • FORBIDDEN — displayName from a member whose relay is another server; their display name comes from their profile card.
  • VALIDATION — displayName > 64 chars, statusText > 256 chars, bio > 2000 chars, or avatarUrl not under /api/files/.
  • NOT_FOUND — caller's user row missing (should not happen in practice).
  • INTERNAL — repository failure.

Examples

mutation Update($input: UpdateMyProfileInput!) {
updateMyProfile(input: $input) {
id username displayName avatarUrl statusText bio
}
}

setMemberRole

setMemberRole( serverId: ID! userId: ID! role: ServerMemberRoleGql! ): ServerMember!

Change a member's role. Owner: any role but OWNER, never their own. Moderator: MEMBER <-> GUEST only. Audited (admin.set_member_role).

kickMember

kickMember( serverId: ID! userId: ID! reason: String ): Boolean!

Remove a member from the workspace (Owner/Moderator; nobody can kick the owner, and a moderator cannot kick a moderator). They may re-join with a new invite. Audited.

banMember

banMember( serverId: ID! userId: ID! reason: String expiresAt: DateTime ): ServerBan!

Remove a member and block them from re-joining until expiresAt (or until unbanned when omitted). Same targeting rules as kickMember. Audited.

unbanMember

unbanMember(serverId: ID!, userId: ID!): Boolean!

Lift a ban (Owner/Moderator). Returns whether a ban existed. Audited.

timeoutMember

timeoutMember( serverId: ID! userId: ID! until: DateTime! reason: String ): MemberTimeout!

Time a member out until until (at most 30 days ahead): they keep reading but every write fails with TIMED_OUT. Same targeting rules as kickMember. Audited.

clearTimeout

clearTimeout(serverId: ID!, userId: ID!): Boolean!

End a member's timeout early. Returns whether one was in force. Audited.

setSlowMode

setSlowMode( serverId: ID! conversationId: ID! seconds: Int! ): Conversation!

Set a channel's slow mode, in seconds (0 to 21600; 0 turns it off). Owner/Moderator. Audited (chat.set_slow_mode).

setDoNotDisturb

setDoNotDisturb( serverId: ID! paused: Boolean! until: DateTime ): NotificationSettings!

Turn the viewer's manual do-not-disturb pause on (until turned off, or until until) or off. While paused, notifications are still recorded but arrive quiet.

publishProfileCard

publishProfileCard(card: SignedStatementInput!): ProfileCard!

Publish a profile card signed by the current identity key.

submitMlsCommit

submitMlsCommit(input: SubmitMlsCommitInput!): MlsCommit!

A Commit for the group's current epoch, or an incarnation's first Commit (epoch 0). STALE_EPOCH names the current incarnation and epoch when another Commit came first.

ackMlsWelcomes

ackMlsWelcomes(ids: [ID!]!): Int!

Acknowledge Welcomes of the session's device; answers how many were acknowledged now.

requestMlsReadd

requestMlsReadd(input: RequestMlsReaddInput!): Boolean!

Ask the group's other devices to remove and add the session's device again.

addContact

addContact(principalId: String!, relayUrls: [String!]!): Contact!

Add a contact, or replace its relay URLs (1 to 8 of at most 256 bytes each).

removeContact

removeContact(principalId: String!): Boolean!

No description in the schema.

acceptDmRequest

acceptDmRequest(id: ID!): DmRequest!

Release the request's held items, let later ones flow, and add the sender as a contact.

ignoreDmRequest

ignoreDmRequest(id: ID!): DmRequest!

Delete the request's held items and drop later items of the conversation.

blockPrincipal

blockPrincipal(principalId: String!): Boolean!

Ignore a principal's pending requests and refuse its invites and key package claims.

unblockPrincipal

unblockPrincipal(principalId: String!): Boolean!

No description in the schema.

remoteJoinChallenge

remoteJoinChallenge( hostServerId: String! hostOrigin: String! inviteToken: String ): RemoteJoinChallenge!

Pin the host at hostOrigin as hostServerId and fetch a login challenge from it for a join, with the workspace inviteToken names (the invite is not used).

renewDelegations

renewDelegations(delegations: [SignedStatementInput!]!): [RemoteSubscription!]!

Present fresh delegations of the caller's devices to their hosts; one entry per delegation, in order.

applyRemoteRevocation

applyRemoteRevocation(revocation: SignedStatementInput!): SignedStatement!

Apply a device revocation on this host directly, as an app does when a host did not acknowledge it through the relay. Needs no session: it acts only on the revocation's signature, and attempts are limited per IP. Returns the host's signed acknowledgement.

requestAccountDeletion

requestAccountDeletion(input: RequestAccountDeletionInput!): AccountDeletionSchedule!

Schedule the signed-in account for deletion once the grace period ends (14 days unless the operator set RIM_ACCOUNT_DELETION_GRACE_DAYS, 0 to 30). Every other session of the account ends now; this one keeps working, and cancelAccountDeletion keeps the account until the grace period ends. me.deletionScheduledFor shows the pending deletion.

Then the account is purged: its sessions, devices, keys, workspace memberships, plaintext messages, files and personal settings are removed, workspaces where it was the only member are deleted, and its username becomes free. The user row stays as a tombstone (deleted-<id prefix>, "Deleted account", no email, password or key) that cannot sign in and shows in no member list or search; it stays the author of the account's encrypted messages, which are kept so the conversations' history does not shift, and of a deleted message others replied to. The tombstone keeps the account's key identity id, so the same key identity cannot sign up on this server again.

Errors

  • UNAUTHENTICATED: no session.
  • FORBIDDEN: a person from another server, who deletes their account at their relay.
  • VALIDATION: confirmUsername is not the account's username, or the account owns a workspace that has other members: hand it over (transferWorkspaceOwnership) or delete it (deleteWorkspace) first.
  • CONFLICT: a deletion is already pending.

cancelAccountDeletion

cancelAccountDeletion: Boolean!

Cancel the signed-in account's pending deletion during its grace period. Returns whether a deletion was pending.

Errors

  • UNAUTHENTICATED: no session.

instanceBlockPrincipal

instanceBlockPrincipal( principalId: String! reason: String! cascade: Boolean! = false ): [InstancePrincipalBlockOutcome!]!

Block a principal on this server: its pending DM requests are ignored, and the account holding it here has its sessions ended, its invites with uses left revoked and its email refused. Returns one outcome per account blocked, the principal's first. Instance operators only; anyone else gets FORBIDDEN.

ArgumentTypeDescription
principalIdString!

The principal to block (rimp1_…).

reasonString!

Why it is blocked, 1 to 1000 characters.

cascadeBoolean! = false

Also block every account its invites created, recursively.

instanceUnblockPrincipal

instanceUnblockPrincipal(principalId: String!): InstancePrincipalUnblockOutcome!

Lift a principal's block and its account's email block. Ended sessions and revoked invites stay ended. Instance operators only; anyone else gets FORBIDDEN.

ArgumentTypeDescription
principalIdString!

The principal to unblock (rimp1_…).

instanceBlockIp

instanceBlockIp( cidr: String! reason: String! expiresInDays: Int ): InstanceIpBlockOutcome!

Block an address or range, or replace the reason and expiry of its block. A running server applies it within 30 seconds. Instance operators only; anyone else gets FORBIDDEN.

ArgumentTypeDescription
cidrString!

An address or a CIDR range, IPv4 or IPv6.

reasonString!

Why it is blocked, 1 to 1000 characters.

expiresInDaysInt

Days until the block lifts, 1 to 365; null blocks until it is removed.

instanceUnblockIp

instanceUnblockIp(cidr: String!): Boolean!

Lift the block on an address or range, named as it was blocked or in any form naming the same range. Returns whether there was one. A running server applies it within 30 seconds. Instance operators only; anyone else gets FORBIDDEN.

ArgumentTypeDescription
cidrString!

The address or CIDR range to unblock.

setMyDmSettings

setMyDmSettings(outside: DmOutside!): MyDmSettings!

Set who outside the caller's workspaces may start a DM with them: REQUESTS, or NONE. REQUESTS under a floor that refuses such DMs is VALIDATION, naming it.