Repository navigation
feat: add team invites - #51
Merged
Merged
Conversation
- Team invites: list (cursor paginated), retrieve, create, update and
revoke (`/team/invites`, `/team/invites/{inviteId}`), with
`TeamInviteData` and `ListTeamInvitesResponse`.
- Team roles: retrieve, create, update, delete (optional
`replacement_role_id` query) and duplicate (`/team/roles/{roleId}`,
`/team/roles`, `/team/roles/{roleId}/duplicate`).
- Team members: remove (`DELETE /team/members/{userId}`), and the member
list takes an optional `filter[project_id]`.
- `TeamRoleData` gains an optional, nullable `description`.
Co-Authored-By: Claude <noreply@anthropic.com>
Add `$lettermint->team->invites` with `list`, `iterate`, `retrieve`, `create`, `update` and `revoke` for pending team invitations. The operation coverage test lists the role management and member removal operations as pending; the next PRs in this stack add them. Co-Authored-By: Claude <noreply@anthropic.com>
bjarn
added this pull request to stack #54
October 20, 2026 20:49
bjornftw
approved these changes
Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Adds
$lettermint->team->invites, a sub-client for pending team invitations. It sits next toteam->members, works the same way and uses the team token:list(array $query = [])GET /team/invites(['page' => ['size' => …, 'cursor' => …]])ListTeamInvitesResponse(CursorPage<TeamInviteData>)iterate(array $query = [])next_cursorGenerator<int, TeamInviteData>retrieve(string $inviteId)GET /team/invites/{inviteId}TeamInviteDatacreate(array $body)POST /team/inviteswithCreateTeamInviteDataTeamInviteData(201)update(string $inviteId, array $body)PUT /team/invites/{inviteId}withUpdateTeamInviteDataTeamInviteDatarevoke(string $inviteId)DELETE /team/invites/{inviteId}MessageResponsecreatesends the invitation email. The team needs a free seat, and the Owner role can't be assigned.updatereplaces the email, role and project access. A new email is sent only when the address changes.@phpstan-import-type), likemembers->updateAssignment.ConflictException, with the conflict code inerrorCode. A 422 throwsValidationException, with the field errors inerrors. No new exception classes..and..invite IDs are rejected with aLettermintConfigExceptionbefore any request, as in the other methods.Idempotency-Key, so they have no$idempotencyKeyargument.Internal\Transport: with 71 operations, PHPStan stops tracking the literal type of the generatedOperations::ALLtable and flagged theauthvalue. The transport now narrows that value with a smallmatch. Runtime behaviour is unchanged.team->invitesis in the Team API table, with a short example.tests/phpstan/assertions.phpcovers the new return types.The PRs stacked on top of this one add team role management and member removal. Until then, the coverage test in
tests/TeamApiTest.phplists those six operations as pending. It still checks every other operation strictly, and it now expects 71 operations instead of 60.Non-breaking. Suggested bump: minor.
API changes in the regenerated types
GET /team/invites(cursor paginated:page[size],page[cursor])ListTeamInvitesQuery,ListTeamInvitesResponse,TeamInviteData,TeamInviteDataRoleteam->invites->list/iterate(this PR)GET /team/invites/{inviteId}TeamInviteDatateam->invites->retrieve(this PR)POST /team/invites(201; also 404, 409, 422)CreateTeamInviteData,CreateTeamInviteDataProjectAccessteam->invites->create(this PR)PUT /team/invites/{inviteId}(also 409, 422)UpdateTeamInviteData,UpdateTeamInviteDataProjectAccessteam->invites->update(this PR)DELETE /team/invites/{inviteId}MessageResponseteam->invites->revoke(this PR)GET /team/roles/{roleId}TeamRoleDatateam->retrieveRole(next PR)POST /team/roles(201; also 409, 422)CreateTeamRoleDatateam->createRole(next PR)PUT /team/roles/{roleId}(also 409, 422)UpdateTeamRoleDatateam->updateRole(next PR)DELETE /team/roles/{roleId}with optionalreplacement_role_id(also 409, 422)DeleteTeamRoleQuery,MessageResponseteam->deleteRole(next PR)POST /team/roles/{roleId}/duplicate(201; also 409, 422)DuplicateTeamRoleDatateam->duplicateRole(next PR)DELETE /team/members/{userId}(also 409)MessageResponseteam->members->remove(last PR)GET /team/memberstakes the optionalfilter[project_id]and returns only the members who can access that projectListTeamMembersQuerygainsfilter?: array{project_id?: string}team->members->list/iterate; tested in the last PRTeamRoleDatagainsdescription(string|null, optional)TeamRoleData(also inteam->roles()results)Operations::ALL(60 → 71)No existing type loses or changes a field. No compatibility tool flags apply to PHP: the new
TeamRoleDataproperty is a@property-readon a magic object, so callers' code is unaffected.Usage
Checks
On this branch (PHP 8.5, Composer 2.10):
vendor/bin/pest --ci: 328 passed (3662 assertions)vendor/bin/phpstan: no errors (level 10, includingtests/phpstan/assertions.php)vendor/bin/pint --test: passedcomposer generate:check(full regeneration check): 170 generated files up to datecomposer generate:checkin the header-only mode that CI runs: headers of 170 generated files OKThe full matrix ran on the top of the stack (see the last PR).
Not run locally
Suggested release tag
3.2.0(minor).mainalready has unreleased features since3.1.0, so this fits in the same minor release.🤖 Generated with Claude Code