Skip to content

feat: add team invites - #43

Merged
bjarn merged 2 commits into
mainfrom
feat/team-invites
Oct 21, 2026
Merged

bjarn merged 2 commits into
mainfrom
feat/team-invites

Conversation

@bjarn

@bjarn bjarn commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

What changed

Adds team.invites, a sub-resource for pending team invitations, next to team.members and in the same style (team token):

Method Request Returns
list(query?, options?) GET /team/invites (page: { size, cursor }) ListTeamInvitesResponse (CursorPage<TeamInviteData>)
iterate(query?, options?) follows next_cursor AsyncGenerator<TeamInviteData>
retrieve(inviteId, options?) GET /team/invites/{inviteId} TeamInviteData
create(body, options?) POST /team/invites with CreateTeamInviteData TeamInviteData (201)
update(inviteId, body, options?) PUT /team/invites/{inviteId} with UpdateTeamInviteData TeamInviteData
revoke(inviteId, options?) DELETE /team/invites/{inviteId} MessageResponse
  • create sends the invitation email. The team needs a free seat, and the Owner role can't be assigned.
  • update replaces the email, role and project access. A new email is sent only when the address changes.
  • A 409 throws the existing ConflictError and a 422 the existing ValidationError (both ApiError). No new error classes.
  • Empty, . and .. invite IDs are rejected before any request, as for the other methods.
  • None of these operations take an Idempotency-Key, so there is no idempotency option.
  • TeamInvites is exported as a type, like TeamMembers.
  • README: team.invites is in the Team API table and the Team API example.

Team role management and member removal are added by the PRs stacked on top of this one. Until then, the coverage test lists those six operations as pending. Every other operation is still checked strictly.

Non-breaking. Suggested bump: minor.

API changes in the regenerated types

Change Where SDK impact
New GET /team/invites (cursor paginated, page[size], page[cursor]) ListTeamInvitesQuery, ListTeamInvitesResponse, TeamInviteData team.invites.list / iterate (this PR)
New GET /team/invites/{inviteId} TeamInviteData team.invites.retrieve (this PR)
New POST /team/invites (201; also 409, 422) CreateTeamInviteData team.invites.create (this PR)
New PUT /team/invites/{inviteId} (also 409, 422) UpdateTeamInviteData team.invites.update (this PR)
New DELETE /team/invites/{inviteId} MessageResponse team.invites.revoke (this PR)
New GET /team/roles/{roleId} TeamRoleData team.retrieveRole (next PR)
New POST /team/roles (201; also 409, 422) CreateTeamRoleData team.createRole (next PR)
New PUT /team/roles/{roleId} (also 409, 422) UpdateTeamRoleData team.updateRole (next PR)
New DELETE /team/roles/{roleId} with optional replacement_role_id (also 409, 422) DeleteTeamRoleQuery team.deleteRole (next PR)
New POST /team/roles/{roleId}/duplicate (201) DuplicateTeamRoleData team.duplicateRole (next PR)
New DELETE /team/members/{userId} (also 409) MessageResponse team.members.remove (last PR)
GET /team/members gains the optional filter[project_id]: only members who can access that project ListTeamMembersQuery Already passes through team.members.list / iterate; tested in the last PR
description?: string | null on roles TeamRoleData (also in team.roles() results) Optional field added to a response type; no code change
TeamRoleData is now listed in OperationTypes (it is a direct response type now) operations.ts None

No existing type loses or changes a field.

Usage

const lettermint = new Lettermint({ teamToken: process.env.LETTERMINT_TEAM_TOKEN });

const invite = await lettermint.team.invites.create({
  email: 'jane@example.com',
  role_id: 'role-id',
  project_access: { scope: 'selected', project_ids: ['project-id'] },
});

await lettermint.team.invites.update(invite.id, {
  email: 'jane@example.org',
  role_id: 'role-id',
  project_access: { scope: 'all' },
});

for await (const pending of lettermint.team.invites.iterate()) {
  console.log(pending.email, pending.role.name);
}

await lettermint.team.invites.revoke(invite.id);

Checks

On this branch:

  • npm run lint: passed
  • npm run type-check: passed
  • npm run generate:check: generated files up to date with the pinned spec; the header-only mode that CI runs also passes
  • npm run test:coverage: 8 suites, 333 tests passed
  • npm run test:coverage on Node 20.18.0, 22.21.0 and 24.18.0: 333 passed each
  • npm run build: passed
  • npm run test:smoke: ESM import, CJS require and type declarations OK

Not run locally

Nothing; every CI step was run locally.

Suggested release tag

v3.2.0 (minor). main already has unreleased features since v3.1.0, so this fits in the same minor release.

🤖 Generated with Claude Code

bjarn and others added 2 commits October 20, 2026 22:37
- Add team invite operations: GET/POST /team/invites and
  GET/PUT/DELETE /team/invites/{inviteId}, with TeamInviteData,
  CreateTeamInviteData, UpdateTeamInviteData, ListTeamInvitesQuery and
  ListTeamInvitesResponse
- Add team role operations: GET/PUT/DELETE /team/roles/{roleId} and
  POST /team/roles, POST /team/roles/{roleId}/duplicate, with
  CreateTeamRoleData, UpdateTeamRoleData, DuplicateTeamRoleData and
  DeleteTeamRoleQuery (optional replacement_role_id)
- Add DELETE /team/members/{userId}
- ListTeamMembersQuery gains the optional filter[project_id]
- TeamRoleData gains the optional, nullable description

Co-Authored-By: Claude <noreply@anthropic.com>
Add `team.invites` with `list`, `iterate`, `retrieve`, `create`, `update`
and `revoke` for pending team invitations (team token).

The coverage test lists the team role and member removal operations as
pending; the next PRs in this stack add their methods.

Co-Authored-By: Claude <noreply@anthropic.com>
@bjarn
bjarn requested a review from a team as a code owner October 20, 2026 20:46
@bjarn
bjarn added this pull request to stack #46 October 20, 2026 20:46
@bjarn
bjarn merged commit d99088a into main Oct 21, 2026
4 checks passed
@bjarn
bjarn deleted the feat/team-invites branch October 21, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants