Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/keycard-api-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand All @@ -43,10 +43,10 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/keycard-api-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand All @@ -61,7 +61,7 @@ jobs:
github.repository == 'stainless-sdks/keycard-api-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setOutput('github_token', await core.getIDToken());

Expand All @@ -81,10 +81,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/keycard-api-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.9.13'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
if: github.repository == 'keycardai/keycard-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Check release environment
run: |
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.10.0"
".": "0.11.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 106
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/keycard/keycard-api-d976147b1bc79d44e82107b943099bc750c9b7d101e91bf1ea53b91a6b74e8a6.yml
openapi_spec_hash: d2953fdcb3490866c4bef3ec7a8300bb
config_hash: 62b00ad8d94230c7c9b8ed142c7dcfc8
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/keycard/keycard-api-98bb06a2aca1b7ea066960a14eb4879aa4967bc4ed9686b66e60438824ce8415.yml
openapi_spec_hash: b7bdac3288a2e626465c0baf6df49c17
config_hash: b0ee2dc67cc490e45f8fe0acabd76206
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## 0.11.0 (2026-05-15)

Full Changelog: [v0.10.0...v0.11.0](https://github.com/keycardai/keycard-python/compare/v0.10.0...v0.11.0)

### Features

* **ACC-277:** list policy versions pinned by a policy-set draft ([1098f3d](https://github.com/keycardai/keycard-python/commit/1098f3dc1da65c5ecc00c7e132bd8c7b8e8bc4fc))
* accept ID Zone platform principals in management API ([1e3311e](https://github.com/keycardai/keycard-python/commit/1e3311ed7a826618f9fe8a34c438e9cea81d5636))
* add jwt_lifetime_seconds to resources ([090a5cd](https://github.com/keycardai/keycard-python/commit/090a5cd8c0f02bc29b29a74b525924fff94320a7))


### Bug Fixes

* housekeeping ([744a2af](https://github.com/keycardai/keycard-python/commit/744a2afd2465cc5c67ee665636f89675d0913192))

## 0.10.0 (2026-05-11)

Full Changelog: [v0.9.1...v0.10.0](https://github.com/keycardai/keycard-python/compare/v0.9.1...v0.10.0)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "keycardai_api"
version = "0.10.0"
version = "0.11.0"
description = "The official Python library for the keycard-api API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/keycardai_api/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "keycardai_api"
__version__ = "0.10.0" # x-release-please-version
__version__ = "0.11.0" # x-release-please-version
20 changes: 20 additions & 0 deletions src/keycardai_api/resources/zones/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def create(
name: str,
application_id: str | Omit = omit,
application_type: Literal["native", "web"] | Omit = omit,
credential_lifetime_seconds: int | Omit = omit,
credential_provider_id: str | Omit = omit,
description: Optional[str] | Omit = omit,
metadata: MetadataParam | Omit = omit,
Expand Down Expand Up @@ -88,6 +89,9 @@ def create(
localhost URLs for redirect_uris or URIs with custom schemes. Web clients must
use https URLs and must not use localhost as the hostname.

credential_lifetime_seconds: Credential lifetime override in seconds. When set, overrides the default
credential lifetime for this resource.

credential_provider_id: ID of the credential provider to associate with the resource

description: Human-readable description. Must not contain HTML tags (e.g. `<script>`,
Expand Down Expand Up @@ -119,6 +123,7 @@ def create(
"name": name,
"application_id": application_id,
"application_type": application_type,
"credential_lifetime_seconds": credential_lifetime_seconds,
"credential_provider_id": credential_provider_id,
"description": description,
"metadata": metadata,
Expand Down Expand Up @@ -176,6 +181,7 @@ def update(
zone_id: str,
application_id: Optional[str] | Omit = omit,
application_type: Literal["native", "web"] | Omit = omit,
credential_lifetime_seconds: Optional[int] | Omit = omit,
credential_provider_id: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
identifier: str | Omit = omit,
Expand All @@ -200,6 +206,9 @@ def update(
localhost URLs for redirect_uris or URIs with custom schemes. Web clients must
use https URLs and must not use localhost as the hostname.

credential_lifetime_seconds: Credential lifetime override in seconds. Set to null to clear the override and
use the default.

credential_provider_id: ID of the credential provider to associate with the resource (set to null to
unset)

Expand Down Expand Up @@ -237,6 +246,7 @@ def update(
{
"application_id": application_id,
"application_type": application_type,
"credential_lifetime_seconds": credential_lifetime_seconds,
"credential_provider_id": credential_provider_id,
"description": description,
"identifier": identifier,
Expand Down Expand Up @@ -384,6 +394,7 @@ async def create(
name: str,
application_id: str | Omit = omit,
application_type: Literal["native", "web"] | Omit = omit,
credential_lifetime_seconds: int | Omit = omit,
credential_provider_id: str | Omit = omit,
description: Optional[str] | Omit = omit,
metadata: MetadataParam | Omit = omit,
Expand Down Expand Up @@ -413,6 +424,9 @@ async def create(
localhost URLs for redirect_uris or URIs with custom schemes. Web clients must
use https URLs and must not use localhost as the hostname.

credential_lifetime_seconds: Credential lifetime override in seconds. When set, overrides the default
credential lifetime for this resource.

credential_provider_id: ID of the credential provider to associate with the resource

description: Human-readable description. Must not contain HTML tags (e.g. `<script>`,
Expand Down Expand Up @@ -444,6 +458,7 @@ async def create(
"name": name,
"application_id": application_id,
"application_type": application_type,
"credential_lifetime_seconds": credential_lifetime_seconds,
"credential_provider_id": credential_provider_id,
"description": description,
"metadata": metadata,
Expand Down Expand Up @@ -501,6 +516,7 @@ async def update(
zone_id: str,
application_id: Optional[str] | Omit = omit,
application_type: Literal["native", "web"] | Omit = omit,
credential_lifetime_seconds: Optional[int] | Omit = omit,
credential_provider_id: Optional[str] | Omit = omit,
description: Optional[str] | Omit = omit,
identifier: str | Omit = omit,
Expand All @@ -525,6 +541,9 @@ async def update(
localhost URLs for redirect_uris or URIs with custom schemes. Web clients must
use https URLs and must not use localhost as the hostname.

credential_lifetime_seconds: Credential lifetime override in seconds. Set to null to clear the override and
use the default.

credential_provider_id: ID of the credential provider to associate with the resource (set to null to
unset)

Expand Down Expand Up @@ -562,6 +581,7 @@ async def update(
{
"application_id": application_id,
"application_type": application_type,
"credential_lifetime_seconds": credential_lifetime_seconds,
"credential_provider_id": credential_provider_id,
"description": description,
"identifier": identifier,
Expand Down
102 changes: 95 additions & 7 deletions src/keycardai_api/resources/zones/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import httpx

from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
Expand Down Expand Up @@ -88,25 +88,63 @@ def list(
after: str | Omit = omit,
before: str | Omit = omit,
expand: Union[Literal["total_count"], List[Literal["total_count"]]] | Omit = omit,
filter_email: Union[str, SequenceNotStr[str]] | Omit = omit,
filter_id: Union[str, SequenceNotStr[str]] | Omit = omit,
limit: int | Omit = omit,
query: Union[str, SequenceNotStr[str]] | Omit = omit,
query_email: Union[str, SequenceNotStr[str]] | Omit = omit,
query_subject: Union[str, SequenceNotStr[str]] | Omit = omit,
sort: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> UserListResponse:
"""Returns a list of users in the specified zone.

Can be filtered by email address.
"""
Returns a list of users in the specified zone.

**Rollout note:** the paginated/searchable/sortable behavior described below is
gated behind the `user-pagination` feature flag and is currently disabled for
most zones. While the flag is off, the response returns every user in the zone
(capped at 100) in `items` and a fixed pagination envelope where `after_cursor`
and `before_cursor` are `null` and `total_count` is `0`. The query parameters
below are accepted but ignored. The flag is rolled out per-zone in Datadog and
will become the default once Console adopts the paginated contract.

Use cursor pagination via `after`/`before`. Sort: comma-separated field list;
prefix with `-` for descending. Use `expand[]=total_count` to include the
matching row count. Filter by exact email via `filter[email]`; search via
`query[email]` / `query[subject]` / `query[]` (substring match, OR'd across
repeated values). `query[]` matches against email and federation credential
subject. Pass `filter[id]` (repeatable, max 100) to restrict results to a known
set of users — mutually exclusive with `after`/`before` (returns 400 if
combined). When `filter[id]` is set, `limit` is ignored and the response
contains every requested user that exists in the zone, in a single page. IDs not
in the zone are silently omitted.

Args:
after: Cursor for forward pagination

before: Cursor for backward pagination

filter_email: Filter by exact email address

filter_id: Restrict results to users with this publicId. Repeatable, max 100. Mutually
exclusive with after/before.

limit: Maximum number of items to return

query: Search across email and credential subject (substring match)

query_email: Search by email (substring match)

query_subject: Search by federated credential subject (substring match)

sort: Comma-separated sort fields. Prefix with - for descending. Allowed: created_at,
email, authenticated_at

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request
Expand All @@ -129,7 +167,13 @@ def list(
"after": after,
"before": before,
"expand": expand,
"filter_email": filter_email,
"filter_id": filter_id,
"limit": limit,
"query": query,
"query_email": query_email,
"query_subject": query_subject,
"sort": sort,
},
user_list_params.UserListParams,
),
Expand Down Expand Up @@ -201,25 +245,63 @@ async def list(
after: str | Omit = omit,
before: str | Omit = omit,
expand: Union[Literal["total_count"], List[Literal["total_count"]]] | Omit = omit,
filter_email: Union[str, SequenceNotStr[str]] | Omit = omit,
filter_id: Union[str, SequenceNotStr[str]] | Omit = omit,
limit: int | Omit = omit,
query: Union[str, SequenceNotStr[str]] | Omit = omit,
query_email: Union[str, SequenceNotStr[str]] | Omit = omit,
query_subject: Union[str, SequenceNotStr[str]] | Omit = omit,
sort: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> UserListResponse:
"""Returns a list of users in the specified zone.

Can be filtered by email address.
"""
Returns a list of users in the specified zone.

**Rollout note:** the paginated/searchable/sortable behavior described below is
gated behind the `user-pagination` feature flag and is currently disabled for
most zones. While the flag is off, the response returns every user in the zone
(capped at 100) in `items` and a fixed pagination envelope where `after_cursor`
and `before_cursor` are `null` and `total_count` is `0`. The query parameters
below are accepted but ignored. The flag is rolled out per-zone in Datadog and
will become the default once Console adopts the paginated contract.

Use cursor pagination via `after`/`before`. Sort: comma-separated field list;
prefix with `-` for descending. Use `expand[]=total_count` to include the
matching row count. Filter by exact email via `filter[email]`; search via
`query[email]` / `query[subject]` / `query[]` (substring match, OR'd across
repeated values). `query[]` matches against email and federation credential
subject. Pass `filter[id]` (repeatable, max 100) to restrict results to a known
set of users — mutually exclusive with `after`/`before` (returns 400 if
combined). When `filter[id]` is set, `limit` is ignored and the response
contains every requested user that exists in the zone, in a single page. IDs not
in the zone are silently omitted.

Args:
after: Cursor for forward pagination

before: Cursor for backward pagination

filter_email: Filter by exact email address

filter_id: Restrict results to users with this publicId. Repeatable, max 100. Mutually
exclusive with after/before.

limit: Maximum number of items to return

query: Search across email and credential subject (substring match)

query_email: Search by email (substring match)

query_subject: Search by federated credential subject (substring match)

sort: Comma-separated sort fields. Prefix with - for descending. Allowed: created_at,
email, authenticated_at

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request
Expand All @@ -242,7 +324,13 @@ async def list(
"after": after,
"before": before,
"expand": expand,
"filter_email": filter_email,
"filter_id": filter_id,
"limit": limit,
"query": query,
"query_email": query_email,
"query_subject": query_subject,
"sort": sort,
},
user_list_params.UserListParams,
),
Expand Down
Loading
Loading