Skip to content

feat: manage project API tokens - #46

Merged
bjarn merged 2 commits into
mainfrom
feat/project-api-tokens
Oct 30, 2026
Merged

bjarn merged 2 commits into
mainfrom
feat/project-api-tokens

Conversation

@bjarn

@bjarn bjarn commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

What changed

Adds projects.api_tokens, a sub-client for the API tokens of a project, in the same style as projects.report_forwarding and routes (team token), on both Lettermint and AsyncLettermint:

Method Request Returns
list(project_id, query=None, *, timeout=None) GET /projects/{projectId}/api-tokens ({"page": {"size", "cursor"}, "sort": [...]}) ListProjectApiTokensResponse (CursorPage[ProjectApiToken])
iterate(project_id, query=None, *, timeout=None) follows next_cursor Iterator[ProjectApiToken] (AsyncIterator on the async client)
create(project_id, body, *, timeout=None) POST /projects/{projectId}/api-tokens with StoreProjectApiTokenData ProjectApiTokenCreatedResponse (201)
delete(project_id, token_id, *, timeout=None) DELETE /projects/{projectId}/api-tokens/{tokenId} MessageResponse
  • create returns the token value once, in data["token"]. It works for sending through the API, and as the SMTP password when SMTP is enabled for the project; smtp then holds the SMTP host, ports and username, otherwise None. "short_token": True creates a shorter token for devices that limit password length. The docstring and README say to store the value right away.
  • list and iterate return token metadata only. delete stops the token from working immediately.
  • Responses are plain dicts and the SDK does not redact them, so data["token"] is documented as returned once rather than treated specially (same as api_token on projects.create and the new secret of webhooks.regenerate_secret).
  • A 404 raises the existing NotFoundError, a 422 the existing ValidationError. No new exception classes.
  • Empty and .. project and token IDs are rejected before any request, as for the other methods.
  • None of these operations take an Idempotency-Key, so there is no idempotency_key argument.
  • ProjectApiTokens and AsyncProjectApiTokens are exported, like ReportForwarding.
  • The rotate_token docstring now points at api_tokens for managing specific tokens.
  • README: projects.api_tokens is in the Team API table, with a short section and example.

Team API token management is added by the PR stacked on top of this one. Until then, the surface test lists those three 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 /projects/{projectId}/api-tokens (cursor paginated, page[size], page[cursor], sort) ListProjectApiTokensQuery, ListProjectApiTokensQueryPage, ListProjectApiTokensQuerySortItem, ListProjectApiTokensResponse, ProjectApiToken projects.api_tokens.list / iterate (this PR)
New POST /projects/{projectId}/api-tokens (201; also 422) StoreProjectApiTokenData, ProjectApiTokenCreatedResponse, ProjectApiTokenSecret, SmtpCredentials projects.api_tokens.create (this PR)
New DELETE /projects/{projectId}/api-tokens/{tokenId} MessageResponse projects.api_tokens.delete (this PR)
New GET /team/api-tokens (cursor paginated, page[size], page[cursor], sort) ListTeamApiTokensQuery, ListTeamApiTokensQueryPage, ListTeamApiTokensQuerySortItem, ListTeamApiTokensResponse, TeamApiToken team.api_tokens.list / iterate (next PR)
New POST /team/api-tokens (201; also 422) StoreTeamApiTokenData, TeamApiTokenCreatedResponse, TeamApiTokenSecret team.api_tokens.create (next PR)
New DELETE /team/api-tokens/{tokenId} MessageResponse team.api_tokens.delete (next PR)
New ApiTokenSource (Literal["dashboard", "api", "cli", "mcp"] | str) for created_via ProjectApiToken, TeamApiToken and the *Secret types None
The rotate-token endpoint is now described as the legacy endpoint for the original Project API token, and points at the new Project API token endpoints POST /projects/{projectId}/rotate-token (no generated change) Docstring of projects.rotate_token only

No existing type loses or changes a field.

Usage

lettermint = Lettermint(team_token=os.environ["LETTERMINT_TEAM_TOKEN"])

created = lettermint.projects.api_tokens.create("project-id", {"name": "Checkout service"})
print(created["data"]["token"])  # only returned once
print(created["smtp"])  # {"host", "ports", "username"} when SMTP is enabled, otherwise None

for token in lettermint.projects.api_tokens.iterate("project-id"):
    print(token["name"], token["last_used_at"])

lettermint.projects.api_tokens.delete("project-id", created["data"]["id"])

Checks

On this branch:

  • python -m ruff check src tests scripts: passed
  • python -m ruff format --check src tests scripts: passed
  • python -m mypy: no issues in 36 source files
  • python scripts/unasync.py --check: _sync up to date
  • python scripts/generate.py --check: generated files up to date with the pinned spec, headers OK
  • python -m pytest tests/: 320 passed on Python 3.10, 3.11, 3.12, 3.13 and 3.14
  • python -m build and twine check --strict dist/*: passed; the wheel installs in a fresh venv and imports (UPGRADE.md and py.typed included)

Not run locally

Nothing; every CI step was run locally.

Suggested release tag

v3.3.0 (minor), after this PR and the one stacked on it are merged. main already has unreleased changes since v3.2.0 (the inbound.rejected webhook event in the types), so this fits in the same minor release.

bjarn added 2 commits October 29, 2026 17:55
Add `projects.api_tokens` with `list`, `iterate`, `create` and `delete`
for the API tokens of a project (team token), on the sync and async
clients. `create` returns the token value once, with the SMTP settings
when SMTP is enabled for the project.

The surface test lists the team API token operations as pending; the
next PR in this stack adds their methods.
@bjarn
bjarn requested a review from a team as a code owner October 29, 2026 17:00
@bjarn
bjarn added this pull request to stack #48 October 29, 2026 17:00
@bjarn
bjarn merged commit a45e4ae into main Oct 30, 2026
7 checks passed
@bjarn
bjarn deleted the feat/project-api-tokens branch October 30, 2026 08:37
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