Skip to content

Invites

Invites let space creators distribute invite tokens without knowing recipients’ DIDs in advance.

Only the space’s creator or an operator with superadmin can create invites.

const response = await fetch("https://happyview.example.com/xrpc/dev.happyview.space.createInvite", {
method: "POST",
headers: {
"X-Client-Key": CLIENT_KEY,
"Authorization": `DPoP ${ACCESS_TOKEN}`,
"DPoP": DPOP_PROOF,
"Content-Type": "application/json",
},
body: JSON.stringify({
space: "at://did:web:happyview.example.com/space/com.example.forum/main",
access: { read: true, write: true },
maxUses: 10,
expiresAt: "2026-06-01T00:00:00Z",
}),
});
interface CreateInviteResponse {
inviteId: string;
token: string;
access: { read: boolean; write: boolean };
maxUses: number | null;
expiresAt: string | null;
}
const data: CreateInviteResponse = await response.json();

Input:

FieldTypeRequiredDefaultDescription
spacestringYesThe space this invite is for
accessobjectNo{ "read": true, "write": false }Access granted on acceptance: read and write booleans, both required when access is given
maxUsesintegerNounlimitedMaximum number of times the invite can be redeemed
expiresAtstring (datetime)NoneverWhen the invite expires, in UTC (ending in Z or +00:00)

Response (201):

{
"inviteId": "uuid",
"token": "a1b2c3d4e5f6...",
"access": { "read": true, "write": true },
"maxUses": 10,
"expiresAt": "2026-06-01T00:00:00Z"
}

Any authenticated user can accept an invite token to join the space.

const response = await fetch("https://happyview.example.com/xrpc/dev.happyview.space.acceptInvite", {
method: "POST",
headers: {
"X-Client-Key": CLIENT_KEY,
"Authorization": `DPoP ${ACCESS_TOKEN}`,
"DPoP": DPOP_PROOF,
"Content-Type": "application/json",
},
body: JSON.stringify({
token: "a1b2c3d4e5f6...",
}),
});
interface AcceptInviteResponse {
uri: string;
access: { read: boolean; write: boolean };
}
const data: AcceptInviteResponse = await response.json();

Response (201):

{
"uri": "at://did:web:happyview.example.com/space/com.example.forum/main",
"access": { "read": true, "write": true }
}

Acceptance fails if:

  • The token is invalid (no matching hash found): 404
  • The invite has been revoked: 400
  • The invite has reached its maxUses: 400
  • The invite has expired: 400
  • The user is already a member of the space: 409
const response = await fetch("https://happyview.example.com/xrpc/dev.happyview.space.revokeInvite", {
method: "POST",
headers: {
"X-Client-Key": CLIENT_KEY,
"Authorization": `DPoP ${ACCESS_TOKEN}`,
"DPoP": DPOP_PROOF,
"Content-Type": "application/json",
},
body: JSON.stringify({
space: "at://did:web:happyview.example.com/space/com.example.forum/main",
inviteId: "uuid",
}),
});

Only the space’s creator or an operator with superadmin can revoke an invite. Revoking prevents future redemptions but does not remove members who already redeemed it. A revoke answers {"success": true}, and an inviteId that is not one of the space’s invites fails with 404.

Only the space’s creator or an operator with superadmin can list invites.

const response = await fetch(
"https://happyview.example.com/xrpc/dev.happyview.space.listInvites?space=at://did:web:happyview.example.com/space/com.example.forum/main",
{
headers: {
"X-Client-Key": CLIENT_KEY,
"Authorization": `DPoP ${ACCESS_TOKEN}`,
"DPoP": DPOP_PROOF,
},
},
);
interface Invite {
id: string;
access: { read: boolean; write: boolean };
maxUses: number | null;
uses: number;
expiresAt: string | null;
revoked: boolean;
createdBy: string;
createdAt: string;
}
const data: { invites: Invite[] } = await response.json();

Parameters:

FieldTypeRequiredDescription
spacestringYesThe space to list invites for

Response:

{
"invites": [
{
"id": "uuid",
"access": { "read": true, "write": true },
"maxUses": 10,
"uses": 3,
"expiresAt": "2026-06-01T00:00:00Z",
"revoked": false,
"createdBy": "did:plc:abc123",
"createdAt": "2026-05-09T12:00:00Z"
}
]
}

List responses carry the invite metadata and never the token.