rtClient.invites
SDK methods for creating and managing invitations.
Methods
rtClient.invites.list(params?)
List the authenticated user's invites. Returns ApiResponse<InviteListResponse> - { items: Invite[], summary }.
const res = await rtClient.invites.list();
const invites = res.data.items;
// Invites assigned to you to send, rather than ones you minted
const held = await rtClient.invites.list({ scope: "held", status: "DRAFT" });InviteListParams is { status?, scope?, limit?, creatorId? }. scope is "created" (default: invites you minted) or "held" (invites assigned to you, which you may send; always self-scoped). status takes one InviteStatus or an array. creatorId is an admin-only override.
rtClient.invites.get(id) / update(id, patch)
Fetch one invite by id (the creator or an admin), or patch a DRAFT invite (the creator only). InvitePatchInput takes the same optional fields as create, except holderUserId - assign a holder with assign.
rtClient.invites.create(input)
Create a new invite in DRAFT status. All fields on InviteCreateInput are optional - the default is a bearer invite claimable by anyone who opens the link.
const { data: invite } = await rtClient.invites.create({
claimBinding: "EMAIL", // optional - lock to a verified identity
bindingValue: "alice@example.com", // the binding's target (email / X handle / c32 address)
holderUserId: 42, // optional, admin only - hand it straight to a holder who may send it
roleId: 2, // optional - the numeric Role id granted on claim
grantAppIds: [5, 10], // optional - apps granted access to on claim
fundingStxMicro: 10_000_000, // optional - starter STX (microSTX)
message: "Come build with us", // optional
});
console.log(invite.code); // "A1B2C3D4E5F6"The role granted on claim is set by roleId (a numeric Role id), not a role name. claimBinding (BEARER | EMAIL | X_HANDLE | STX_ADDRESS | USER) with bindingValue locks the invite to a verified identity - see Invites. Other optional fields: recipientUserId (the USER binding's target), appId (attribution only), expiresAt (defaults to +30 days server-side).
rtClient.invites.assign(id, holderUserId)
Hand a DRAFT invite to a holder, who may then send it. Admin only, and only while the invite is still DRAFT; re-assignment is allowed until it is sent. Assignment is not a status: an assigned invite stays DRAFT until someone sends it. Creator (who is accountable), holder (who may send) and recipient (who may claim) are three different questions - see Invites.
await rtClient.invites.assign(inviteId, holderUserId);rtClient.invites.getMintAuthority()
Read the caller's own invite-mint authority. Mint permission is derived from the creator's role tier, not an entitlement, so gate a mint UI on this rather than showing a form that only 403s on submit.
const { data } = await rtClient.invites.getMintAuthority();
// { canMint, dailyQuota, mintedToday, remaining } (-1 = unlimited, for Admin)rtClient.invites.send(id, binding?)
Move an invite from DRAFT to SENT, making it claimable via its code. A holder who did not mint it must pass a binding ({ kind: "EMAIL" | "X_HANDLE", value }) so the invite is locked to a person; the creator may send it as minted.
await rtClient.invites.send(inviteId);
await rtClient.invites.send(inviteId, { kind: "EMAIL", value: "marcus@example.com" });Refused with INVALID_ADDRESSING (400) when the invite is WAITLIST_ONLY - a renewal or a drip - whoever sends it. Those go through sendToWaitlist.
rtClient.invites.sendToWaitlist(id, signupId)
Spend a held, unaddressed DRAFT invite on someone from the waitlist pool (rtClient.waitlist.pool). The body is the pick handle and nothing about the person: the server reads the row, binds the invite to the contact it holds, sets a 90-day expiry and sends - so the sender never learns how to reach them.
const res = await rtClient.invites.sendToWaitlist(inviteId, signupId);
// res.data: { signupId, invite: { id, code, claimUrl, expiresAt }, notifiedAt }notifiedAt is when the applicant was emailed, or null - an X row, or no mail provider - in which case their own status page is how they learn of it. TAKEN (409) means somebody else brought them in first; the invite is untouched and still yours.
rtClient.invites.revoke(id)
Cancel a SENT invite (SENT -> REVOKED). To discard a DRAFT invite, hard-delete it with rtClient.invites.remove(id) instead.
await rtClient.invites.revoke(inviteId);rtClient.invites.preview(code)
Preview an invite code without claiming it. Requires an app key, no user token.
const { data: preview } = await rtClient.invites.preview("A1B2C3D4E5F6");
// { valid: true, invitedBy: { id, displayName, thumbnailUri }, role: { id, name } | null,
// app?, grantApps?, boundTo?, message? }
// or
// { valid: false }The preview endpoint returns only a generic { valid: false } shape on failure (not found, revoked, expired, claimed) to prevent code enumeration. boundTo carries the binding type (never the target value) so a claim screen can prompt the right sign-in.
rtClient.invites.precheckClaim(code)
Read-only claim eligibility for the signed-in caller. Runs the same status and binding checks as claim but consumes nothing, so a client can catch a binding mismatch right after sign-in - before asking a new user to set up a profile. Works before a protocol account exists.
const { data } = await rtClient.invites.precheckClaim("A1B2C3D4E5F6");
// { eligible: boolean, boundTo: InviteClaimBinding | null }rtClient.invites.claim(code) (authenticated)
Claim an invite code. Grants any attached role and app access, and funds the wallet, atomically on success.
await rtClient.invites.claim("A1B2C3D4E5F6");