From c3f2f4a2e93139c627d3745ea4eb7f5142f3153b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:19:54 +0000 Subject: [PATCH 01/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/workflow_recipient_run.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 86d162e..c2b6258 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-3e8f3a4664d48b3d546339018b451a356f8e20c223a2d21e7c3824fad4cddc7b.yml -openapi_spec_hash: c2b6637451a63e39c1f1042c6a7cc7f7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-4b8499dddbc5ac767491c492be1629f4f10a17442cf84e13e10fe38b7dcb713c.yml +openapi_spec_hash: 98edfca809c07521259de151d3fc5684 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/workflow_recipient_run.py b/src/knockapi/types/workflow_recipient_run.py index 884b684..4217f64 100644 --- a/src/knockapi/types/workflow_recipient_run.py +++ b/src/knockapi/types/workflow_recipient_run.py @@ -7,7 +7,6 @@ from pydantic import Field as FieldInfo from .._models import BaseModel -from .recipient import Recipient from .recipient_reference import RecipientReference __all__ = ["WorkflowRecipientRun", "TriggerSource"] @@ -74,8 +73,11 @@ class WorkflowRecipientRun(BaseModel): single trigger. """ - actor: Optional[Recipient] = None - """A recipient of a notification, which is either a user or an object.""" + actor: Optional[RecipientReference] = None + """ + A reference to a recipient, either a user identifier (string) or an object + reference (ID, collection). + """ error_count: Optional[int] = None """The number of errors encountered during the workflow recipient run.""" From 4d33037881f97e2b3e99892b31af059ae22c4bb8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:01:36 +0000 Subject: [PATCH 02/45] fix: use correct field name format for multipart file arrays --- src/knockapi/_qs.py | 8 ++----- src/knockapi/_types.py | 3 +++ src/knockapi/_utils/_utils.py | 42 ++++++++++++++++++++++++++++------- tests/test_extract_files.py | 28 ++++++++++++++++++----- tests/test_files.py | 2 +- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/knockapi/_qs.py b/src/knockapi/_qs.py index de8c99b..4127c19 100644 --- a/src/knockapi/_qs.py +++ b/src/knockapi/_qs.py @@ -2,17 +2,13 @@ from typing import Any, List, Tuple, Union, Mapping, TypeVar from urllib.parse import parse_qs, urlencode -from typing_extensions import Literal, get_args +from typing_extensions import get_args -from ._types import NotGiven, not_given +from ._types import NotGiven, ArrayFormat, NestedFormat, not_given from ._utils import flatten _T = TypeVar("_T") - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - PrimitiveData = Union[str, int, float, bool, None] # this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] # https://github.com/microsoft/pyright/issues/3555 diff --git a/src/knockapi/_types.py b/src/knockapi/_types.py index 8059ac4..6e24b33 100644 --- a/src/knockapi/_types.py +++ b/src/knockapi/_types.py @@ -47,6 +47,9 @@ ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) _T = TypeVar("_T") +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + # Approximates httpx internal ProxiesTypes and RequestFiles types # while adding support for `PathLike` instances diff --git a/src/knockapi/_utils/_utils.py b/src/knockapi/_utils/_utils.py index 771859f..199cd23 100644 --- a/src/knockapi/_utils/_utils.py +++ b/src/knockapi/_utils/_utils.py @@ -17,11 +17,11 @@ ) from pathlib import Path from datetime import date, datetime -from typing_extensions import TypeGuard +from typing_extensions import TypeGuard, get_args import sniffio -from .._types import Omit, NotGiven, FileTypes, HeadersLike +from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) @@ -40,25 +40,45 @@ def extract_files( query: Mapping[str, object], *, paths: Sequence[Sequence[str]], + array_format: ArrayFormat = "brackets", ) -> list[tuple[str, FileTypes]]: """Recursively extract files from the given dictionary based on specified paths. A path may look like this ['foo', 'files', '', 'data']. + ``array_format`` controls how ```` segments contribute to the emitted + field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and + ``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``). + Note: this mutates the given dictionary. """ files: list[tuple[str, FileTypes]] = [] for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None)) + files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format)) return files +def _array_suffix(array_format: ArrayFormat, array_index: int) -> str: + if array_format == "brackets": + return "[]" + if array_format == "indices": + return f"[{array_index}]" + if array_format == "repeat" or array_format == "comma": + # Both repeat the bare field name for each file part; there is no + # meaningful way to comma-join binary parts. + return "" + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + def _extract_items( obj: object, path: Sequence[str], *, index: int, flattened_key: str | None, + array_format: ArrayFormat, ) -> list[tuple[str, FileTypes]]: try: key = path[index] @@ -75,9 +95,11 @@ def _extract_items( if is_list(obj): files: list[tuple[str, FileTypes]] = [] - for entry in obj: - assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") - files.append((flattened_key + "[]", cast(FileTypes, entry))) + for array_index, entry in enumerate(obj): + suffix = _array_suffix(array_format, array_index) + emitted_key = (flattened_key + suffix) if flattened_key else suffix + assert_is_file_content(entry, key=emitted_key) + files.append((emitted_key, cast(FileTypes, entry))) return files assert_is_file_content(obj, key=flattened_key) @@ -106,6 +128,7 @@ def _extract_items( path, index=index, flattened_key=flattened_key, + array_format=array_format, ) elif is_list(obj): if key != "": @@ -117,9 +140,12 @@ def _extract_items( item, path, index=index, - flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", + flattened_key=( + (flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index) + ), + array_format=array_format, ) - for item in obj + for array_index, item in enumerate(obj) ] ) diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py index dc13e21..eeb7608 100644 --- a/tests/test_extract_files.py +++ b/tests/test_extract_files.py @@ -4,7 +4,7 @@ import pytest -from knockapi._types import FileTypes +from knockapi._types import FileTypes, ArrayFormat from knockapi._utils import extract_files @@ -37,10 +37,7 @@ def test_multiple_files() -> None: def test_top_level_file_array() -> None: query = {"files": [b"file one", b"file two"], "title": "hello"} - assert extract_files(query, paths=[["files", ""]]) == [ - ("files[]", b"file one"), - ("files[]", b"file two"), - ] + assert extract_files(query, paths=[["files", ""]]) == [("files[]", b"file one"), ("files[]", b"file two")] assert query == {"title": "hello"} @@ -71,3 +68,24 @@ def test_ignores_incorrect_paths( expected: list[tuple[str, FileTypes]], ) -> None: assert extract_files(query, paths=paths) == expected + + +@pytest.mark.parametrize( + "array_format,expected_top_level,expected_nested", + [ + ("brackets", [("files[]", b"a"), ("files[]", b"b")], [("items[][file]", b"a"), ("items[][file]", b"b")]), + ("repeat", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("comma", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("indices", [("files[0]", b"a"), ("files[1]", b"b")], [("items[0][file]", b"a"), ("items[1][file]", b"b")]), + ], +) +def test_array_format_controls_file_field_names( + array_format: ArrayFormat, + expected_top_level: list[tuple[str, FileTypes]], + expected_nested: list[tuple[str, FileTypes]], +) -> None: + top_level = {"files": [b"a", b"b"]} + assert extract_files(top_level, paths=[["files", ""]], array_format=array_format) == expected_top_level + + nested = {"items": [{"file": b"a"}, {"file": b"b"}]} + assert extract_files(nested, paths=[["items", "", "file"]], array_format=array_format) == expected_nested diff --git a/tests/test_files.py b/tests/test_files.py index 641bf93..83cca7b 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -131,7 +131,7 @@ def test_extract_files_does_not_mutate_original_nested_array_path(self) -> None: copied = deepcopy_with_paths(original, [["items", "", "file"]]) extracted = extract_files(copied, paths=[["items", "", "file"]]) - assert extracted == [("items[][file]", file1), ("items[][file]", file2)] + assert [entry for _, entry in extracted] == [file1, file2] assert original == { "items": [ {"file": file1, "extra": 1}, From e22462bd64af8c7ddaa8e84c76aca28e411d9734 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:29:49 +0000 Subject: [PATCH 03/45] feat: support setting headers via env --- src/knockapi/_client.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/knockapi/_client.py b/src/knockapi/_client.py index 6f3e90b..4549136 100644 --- a/src/knockapi/_client.py +++ b/src/knockapi/_client.py @@ -19,7 +19,11 @@ RequestOptions, not_given, ) -from ._utils import is_given, get_async_library +from ._utils import ( + is_given, + is_mapping_t, + get_async_library, +) from ._compat import cached_property from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream @@ -113,6 +117,15 @@ def __init__( if base_url is None: base_url = f"https://api.knock.app" + custom_headers_env = os.environ.get("KNOCK_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, @@ -388,6 +401,15 @@ def __init__( if base_url is None: base_url = f"https://api.knock.app" + custom_headers_env = os.environ.get("KNOCK_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, From 95d95f5d1213168128a62e44fd3f990f017b4ec9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:15:52 +0000 Subject: [PATCH 04/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index c2b6258..af6f4c6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-4b8499dddbc5ac767491c492be1629f4f10a17442cf84e13e10fe38b7dcb713c.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-4b8499dddbc5ac767491c492be1629f4f10a17442cf84e13e10fe38b7dcb713c.yml openapi_spec_hash: 98edfca809c07521259de151d3fc5684 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From 0c514bf839ee8134227869b00cf52fb07deeeae6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:36:25 +0000 Subject: [PATCH 05/45] feat(api): api update --- .stats.yml | 4 +- src/knockapi/resources/workflows.py | 40 +++++++++---------- src/knockapi/types/workflow_cancel_params.py | 10 ++--- src/knockapi/types/workflow_trigger_params.py | 10 ++--- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.stats.yml b/.stats.yml index af6f4c6..479881b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-4b8499dddbc5ac767491c492be1629f4f10a17442cf84e13e10fe38b7dcb713c.yml -openapi_spec_hash: 98edfca809c07521259de151d3fc5684 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-0d9b2038188e6e237e90e7d04144af0b48d60f006c49172ffb5e5c0151187d3b.yml +openapi_spec_hash: a37bbcbd9f496e5469be9a756bdaa0e9 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/resources/workflows.py b/src/knockapi/resources/workflows.py index 6080eb8..8706094 100644 --- a/src/knockapi/resources/workflows.py +++ b/src/knockapi/resources/workflows.py @@ -70,11 +70,11 @@ def cancel( pair. Can optionally be provided one or more recipients to scope the request to. Args: - cancellation_key: An optional key that is used to reference a specific workflow trigger request - when issuing a [workflow cancellation](/send-notifications/canceling-workflows) - request. Must be provided while triggering a workflow in order to enable - subsequent cancellation. Should be unique across trigger requests to avoid - unintentional cancellations. + cancellation_key: A key that is used to reference a specific workflow trigger request when issuing + a [workflow cancellation](/send-notifications/canceling-workflows) request. Must + be provided while triggering a workflow in order to enable subsequent + cancellation. Should be unique across trigger requests to avoid unintentional + cancellations. recipients: A list of recipients to cancel the notification for. If omitted, cancels for all recipients associated with the cancellation key. @@ -143,11 +143,11 @@ def trigger( (string), an inline user request (object), or an inline object request, which is determined by the presence of a `collection` property. - cancellation_key: An optional key that is used to reference a specific workflow trigger request - when issuing a [workflow cancellation](/send-notifications/canceling-workflows) - request. Must be provided while triggering a workflow in order to enable - subsequent cancellation. Should be unique across trigger requests to avoid - unintentional cancellations. + cancellation_key: A key that is used to reference a specific workflow trigger request when issuing + a [workflow cancellation](/send-notifications/canceling-workflows) request. Must + be provided while triggering a workflow in order to enable subsequent + cancellation. Should be unique across trigger requests to avoid unintentional + cancellations. data: An optional map of data to pass into the workflow execution. There is a 10MB limit on the size of the full `data` payload. Any individual string value @@ -235,11 +235,11 @@ async def cancel( pair. Can optionally be provided one or more recipients to scope the request to. Args: - cancellation_key: An optional key that is used to reference a specific workflow trigger request - when issuing a [workflow cancellation](/send-notifications/canceling-workflows) - request. Must be provided while triggering a workflow in order to enable - subsequent cancellation. Should be unique across trigger requests to avoid - unintentional cancellations. + cancellation_key: A key that is used to reference a specific workflow trigger request when issuing + a [workflow cancellation](/send-notifications/canceling-workflows) request. Must + be provided while triggering a workflow in order to enable subsequent + cancellation. Should be unique across trigger requests to avoid unintentional + cancellations. recipients: A list of recipients to cancel the notification for. If omitted, cancels for all recipients associated with the cancellation key. @@ -308,11 +308,11 @@ async def trigger( (string), an inline user request (object), or an inline object request, which is determined by the presence of a `collection` property. - cancellation_key: An optional key that is used to reference a specific workflow trigger request - when issuing a [workflow cancellation](/send-notifications/canceling-workflows) - request. Must be provided while triggering a workflow in order to enable - subsequent cancellation. Should be unique across trigger requests to avoid - unintentional cancellations. + cancellation_key: A key that is used to reference a specific workflow trigger request when issuing + a [workflow cancellation](/send-notifications/canceling-workflows) request. Must + be provided while triggering a workflow in order to enable subsequent + cancellation. Should be unique across trigger requests to avoid unintentional + cancellations. data: An optional map of data to pass into the workflow execution. There is a 10MB limit on the size of the full `data` payload. Any individual string value diff --git a/src/knockapi/types/workflow_cancel_params.py b/src/knockapi/types/workflow_cancel_params.py index ad674e6..13a260a 100644 --- a/src/knockapi/types/workflow_cancel_params.py +++ b/src/knockapi/types/workflow_cancel_params.py @@ -14,11 +14,11 @@ class WorkflowCancelParams(TypedDict, total=False): cancellation_key: Required[str] """ - An optional key that is used to reference a specific workflow trigger request - when issuing a [workflow cancellation](/send-notifications/canceling-workflows) - request. Must be provided while triggering a workflow in order to enable - subsequent cancellation. Should be unique across trigger requests to avoid - unintentional cancellations. + A key that is used to reference a specific workflow trigger request when issuing + a [workflow cancellation](/send-notifications/canceling-workflows) request. Must + be provided while triggering a workflow in order to enable subsequent + cancellation. Should be unique across trigger requests to avoid unintentional + cancellations. """ recipients: Optional[SequenceNotStr[RecipientReferenceParam]] diff --git a/src/knockapi/types/workflow_trigger_params.py b/src/knockapi/types/workflow_trigger_params.py index 604f319..24088b4 100644 --- a/src/knockapi/types/workflow_trigger_params.py +++ b/src/knockapi/types/workflow_trigger_params.py @@ -30,11 +30,11 @@ class WorkflowTriggerParams(TypedDict, total=False): cancellation_key: Optional[str] """ - An optional key that is used to reference a specific workflow trigger request - when issuing a [workflow cancellation](/send-notifications/canceling-workflows) - request. Must be provided while triggering a workflow in order to enable - subsequent cancellation. Should be unique across trigger requests to avoid - unintentional cancellations. + A key that is used to reference a specific workflow trigger request when issuing + a [workflow cancellation](/send-notifications/canceling-workflows) request. Must + be provided while triggering a workflow in order to enable subsequent + cancellation. Should be unique across trigger requests to avoid unintentional + cancellations. """ data: Optional[Dict[str, object]] From 456ff0c3bebaf080f76833e9b32f1183dad243ec Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:23:10 +0000 Subject: [PATCH 06/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 479881b..ca0f0b7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-0d9b2038188e6e237e90e7d04144af0b48d60f006c49172ffb5e5c0151187d3b.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-325fab92874fd04ae73a042c429db4cb6c98a934cff5cc4cb130b85b39a6538e.yml openapi_spec_hash: a37bbcbd9f496e5469be9a756bdaa0e9 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From 8e6480650f67a83f923f45485ff2f0d79e719d0b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 20:58:33 +0000 Subject: [PATCH 07/45] chore(internal): reformat pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e23661b..347458d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -168,7 +168,7 @@ show_error_codes = true # # We also exclude our `tests` as mypy doesn't always infer # types correctly and Pyright will still catch any type errors. -exclude = ['src/knockapi/_files.py', '_dev/.*.py', 'tests/.*'] +exclude = ["src/knockapi/_files.py", "_dev/.*.py", "tests/.*"] strict_equality = true implicit_reexport = true From bc1348d82573b0ea6e0e33e99cbd9022bf41da85 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 18:26:21 +0000 Subject: [PATCH 08/45] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ca0f0b7..8996ed0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-325fab92874fd04ae73a042c429db4cb6c98a934cff5cc4cb130b85b39a6538e.yml -openapi_spec_hash: a37bbcbd9f496e5469be9a756bdaa0e9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-b04dec9fb30a417afb8b04537bfb32150e98d3b8071d17802e1ddbcf65253c1f.yml +openapi_spec_hash: cbbb7c70db84e7eb72c39a0400efd6f0 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From 39e6add4ed39335399c26b1c87968bf68709330f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 00:28:41 +0000 Subject: [PATCH 09/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8996ed0..0aafda3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-b04dec9fb30a417afb8b04537bfb32150e98d3b8071d17802e1ddbcf65253c1f.yml -openapi_spec_hash: cbbb7c70db84e7eb72c39a0400efd6f0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-9574f16123ffa4f4b89e9ab4ff2f3276938d1f985c73aebfce8a74f2e07778a9.yml +openapi_spec_hash: b886eafe6bb5a3b78bb1e74b3f1ddda6 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index fe1a72c..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -34,22 +34,22 @@ class MessageEvent(BaseModel): """ type: Literal[ - "message.archived", - "message.bounced", + "message.read", + "message.sent", + "message.seen", "message.created", + "message.queued", "message.delivered", + "message.bounced", + "message.undelivered", + "message.not_sent", "message.delivery_attempted", - "message.interacted", + "message.archived", "message.link_clicked", - "message.not_sent", - "message.queued", - "message.read", - "message.seen", - "message.sent", - "message.unarchived", - "message.undelivered", - "message.unread", + "message.interacted", "message.unseen", + "message.unread", + "message.unarchived", ] """The type of event that occurred.""" From 04b3154865a445887eb791b9c94d2c3586eadf3a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 16:36:20 +0000 Subject: [PATCH 10/45] fix(client): add missing f-string prefix in file type error message --- src/knockapi/_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knockapi/_files.py b/src/knockapi/_files.py index 0fdce17..76da9e0 100644 --- a/src/knockapi/_files.py +++ b/src/knockapi/_files.py @@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles elif is_sequence_t(files): files = [(key, await _async_transform_file(file)) for key, file in files] else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") return files From b128ac31c39b01c758eabda4003373c513f59138 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 17:40:28 +0000 Subject: [PATCH 11/45] feat(internal/types): support eagerly validating pydantic iterators --- src/knockapi/_models.py | 80 +++++++++++++++++++++++++++++++++++++++++ tests/test_models.py | 60 +++++++++++++++++++++++++++++-- 2 files changed, 137 insertions(+), 3 deletions(-) diff --git a/src/knockapi/_models.py b/src/knockapi/_models.py index 29070e0..8c5ab26 100644 --- a/src/knockapi/_models.py +++ b/src/knockapi/_models.py @@ -25,7 +25,9 @@ ClassVar, Protocol, Required, + Annotated, ParamSpec, + TypeAlias, TypedDict, TypeGuard, final, @@ -79,7 +81,15 @@ from ._constants import RAW_RESPONSE_HEADER if TYPE_CHECKING: + from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler + from pydantic_core import CoreSchema, core_schema from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema +else: + try: + from pydantic_core import CoreSchema, core_schema + except ImportError: + CoreSchema = None + core_schema = None __all__ = ["BaseModel", "GenericModel"] @@ -396,6 +406,76 @@ def model_dump_json( ) +class _EagerIterable(list[_T], Generic[_T]): + """ + Accepts any Iterable[T] input (including generators), consumes it + eagerly, and validates all items upfront. + + Validation preserves the original container type where possible + (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON) + always emits a list — round-tripping through model_dump() will not + restore the original container type. + """ + + @classmethod + def __get_pydantic_core_schema__( + cls, + source_type: Any, + handler: GetCoreSchemaHandler, + ) -> CoreSchema: + (item_type,) = get_args(source_type) or (Any,) + item_schema: CoreSchema = handler.generate_schema(item_type) + list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema) + + return core_schema.no_info_wrap_validator_function( + cls._validate, + list_of_items_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + cls._serialize, + info_arg=False, + ), + ) + + @staticmethod + def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any: + original_type: type[Any] = type(v) + + # Normalize to list so list_schema can validate each item + if isinstance(v, list): + items: list[_T] = v + else: + try: + items = list(v) + except TypeError as e: + raise TypeError("Value is not iterable") from e + + # Validate items against the inner schema + validated: list[_T] = handler(items) + + # Reconstruct original container type + if original_type is list: + return validated + # str(list) produces the list's repr, not a string built from items, + # so skip reconstruction for str and its subclasses. + if issubclass(original_type, str): + return validated + try: + return original_type(validated) + except (TypeError, ValueError): + # If the type cannot be reconstructed, just return the validated list + return validated + + @staticmethod + def _serialize(v: Iterable[_T]) -> list[_T]: + """Always serialize as a list so Pydantic's JSON encoder is happy.""" + if isinstance(v, list): + return v + return list(v) + + +EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable] + + def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) diff --git a/tests/test_models.py b/tests/test_models.py index 36593c9..d3ced95 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,7 +1,8 @@ import json -from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, List, Union, Iterable, Optional, cast from datetime import datetime, timezone -from typing_extensions import Literal, Annotated, TypeAliasType +from collections import deque +from typing_extensions import Literal, Annotated, TypedDict, TypeAliasType import pytest import pydantic @@ -9,7 +10,7 @@ from knockapi._utils import PropertyInfo from knockapi._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from knockapi._models import DISCRIMINATOR_CACHE, BaseModel, construct_type +from knockapi._models import DISCRIMINATOR_CACHE, BaseModel, EagerIterable, construct_type class BasicModel(BaseModel): @@ -961,3 +962,56 @@ def __getattr__(self, attr: str) -> Item: ... assert model.a.prop == 1 assert isinstance(model.a, Item) assert model.other == "foo" + + +# NOTE: Workaround for Pydantic Iterable behavior. +# Iterable fields are replaced with a ValidatorIterator and may be consumed +# during serialization, which can cause subsequent dumps to return empty data. +# See: https://github.com/pydantic/pydantic/issues/9541 +@pytest.mark.parametrize( + "data, expected_validated", + [ + ([1, 2, 3], [1, 2, 3]), + ((1, 2, 3), (1, 2, 3)), + (set([1, 2, 3]), set([1, 2, 3])), + (iter([1, 2, 3]), [1, 2, 3]), + ([], []), + ((x for x in [1, 2, 3]), [1, 2, 3]), + (map(lambda x: x, [1, 2, 3]), [1, 2, 3]), + (frozenset([1, 2, 3]), frozenset([1, 2, 3])), + (deque([1, 2, 3]), deque([1, 2, 3])), + ], + ids=["list", "tuple", "set", "iterator", "empty", "generator", "map", "frozenset", "deque"], +) +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction(data: Iterable[int], expected_validated: Iterable[int]) -> None: + class TypeWithIterable(TypedDict): + items: EagerIterable[int] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": data}}) + assert m.data["items"] == expected_validated + + # Verify repeated dumps don't lose data (the original bug) + assert m.model_dump()["data"]["items"] == list(expected_validated) + assert m.model_dump()["data"]["items"] == list(expected_validated) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction_str_falls_back_to_list() -> None: + # str is iterable (over chars), but str(list_of_chars) produces the list's repr + # rather than reconstructing a string from items. We special-case str to fall + # back to list instead of attempting reconstruction. + class TypeWithIterable(TypedDict): + items: EagerIterable[str] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": "hello"}}) + + # falls back to list of chars rather than calling str(["h", "e", "l", "l", "o"]) + assert m.data["items"] == ["h", "e", "l", "l", "o"] + assert m.model_dump()["data"]["items"] == ["h", "e", "l", "l", "o"] From 9147893f95171e4957dfbefb7210f1c990b4abbd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 09:14:48 +0000 Subject: [PATCH 12/45] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0aafda3..5a8198b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-9574f16123ffa4f4b89e9ab4ff2f3276938d1f985c73aebfce8a74f2e07778a9.yml -openapi_spec_hash: b886eafe6bb5a3b78bb1e74b3f1ddda6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-a330b08c7c525cff2693b98bf9418f370b35df8507a2338ea209e5c2cf508a1a.yml +openapi_spec_hash: 83312a96382ac5fc8cba616be474efe6 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From e891c961376ae90ad0ccba7a68b5db5c8e402312 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 19:08:05 +0000 Subject: [PATCH 13/45] ci: pin GitHub Actions to commit SHAs Pin all GitHub Actions referenced in generated workflows (both first-party `actions/*` and third-party) to immutable commit SHAs. Updating pinned actions is now a deliberate codegen-side bump rather than implicit on every workflow run. --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/publish-pypi.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43283d9..80834ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/knock-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 Rye run: | @@ -46,7 +46,7 @@ jobs: id-token: write runs-on: ${{ github.repository == 'stainless-sdks/knock-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | @@ -67,7 +67,7 @@ jobs: github.repository == 'stainless-sdks/knock-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()); @@ -87,7 +87,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/knock-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 Rye run: | diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 02565d3..3b46ace 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 7c384aa..0ae2ffd 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'knocklabs/knock-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: | From 406a78ea83fabc9054d80a9d13b97dde579e37bc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 07:12:19 +0000 Subject: [PATCH 14/45] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5a8198b..a18062d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-a330b08c7c525cff2693b98bf9418f370b35df8507a2338ea209e5c2cf508a1a.yml -openapi_spec_hash: 83312a96382ac5fc8cba616be474efe6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-1081b58ad42a969e5cd51e7c80d7e13fa5bf4973cbf1dfebbef4772caed7be80.yml +openapi_spec_hash: 58773164753990875fff9468a1f16429 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From 4ade4a73e6121f40677e6e497e7979ef3769ab6d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 13:05:33 +0000 Subject: [PATCH 15/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index a18062d..2607c38 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-1081b58ad42a969e5cd51e7c80d7e13fa5bf4973cbf1dfebbef4772caed7be80.yml -openapi_spec_hash: 58773164753990875fff9468a1f16429 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-369efa4602ed92c883669820ff3d099d97b6c7254c0ebc0028d462564144528d.yml +openapi_spec_hash: a8e129bcd0b0235a5b5d867212ccbe86 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" From 6b7bf04ce3367a43fd7190d739ac07ac0e4540db Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 15:22:33 +0000 Subject: [PATCH 16/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2607c38..a18062d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-369efa4602ed92c883669820ff3d099d97b6c7254c0ebc0028d462564144528d.yml -openapi_spec_hash: a8e129bcd0b0235a5b5d867212ccbe86 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-1081b58ad42a969e5cd51e7c80d7e13fa5bf4973cbf1dfebbef4772caed7be80.yml +openapi_spec_hash: 58773164753990875fff9468a1f16429 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From 08f1af8a783072188da2bf1301fa3fad2b599271 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 20:16:18 +0000 Subject: [PATCH 17/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- .../types/providers/ms_team_check_auth_response.py | 3 +++ src/knockapi/types/shared/condition.py | 1 + src/knockapi/types/shared_params/condition.py | 1 + 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index a18062d..960ae3c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-1081b58ad42a969e5cd51e7c80d7e13fa5bf4973cbf1dfebbef4772caed7be80.yml -openapi_spec_hash: 58773164753990875fff9468a1f16429 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-6c3b72254f0f994d27c16100e3555edcc6001a3c986519567adcc51cdfe1261c.yml +openapi_spec_hash: 2e6ed3ff848d34fba88d965b06120fd4 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" diff --git a/src/knockapi/types/providers/ms_team_check_auth_response.py b/src/knockapi/types/providers/ms_team_check_auth_response.py index c1d5e90..14d6a87 100644 --- a/src/knockapi/types/providers/ms_team_check_auth_response.py +++ b/src/knockapi/types/providers/ms_team_check_auth_response.py @@ -13,6 +13,9 @@ class Connection(BaseModel): ok: bool """Whether the Microsoft Teams connection is valid.""" + ms_teams_tenant_id: Optional[str] = None + """The Microsoft Teams tenant ID for the connected tenant.""" + reason: Optional[str] = None """The reason for the Microsoft Teams connection if it is not valid.""" diff --git a/src/knockapi/types/shared/condition.py b/src/knockapi/types/shared/condition.py index 7a3879b..a255255 100644 --- a/src/knockapi/types/shared/condition.py +++ b/src/knockapi/types/shared/condition.py @@ -28,6 +28,7 @@ class Condition(BaseModel): "exists", "not_exists", "contains_all", + "not_contains_all", "is_timestamp", "is_not_timestamp", "is_timestamp_on_or_after", diff --git a/src/knockapi/types/shared_params/condition.py b/src/knockapi/types/shared_params/condition.py index 4da8f40..5adfddf 100644 --- a/src/knockapi/types/shared_params/condition.py +++ b/src/knockapi/types/shared_params/condition.py @@ -29,6 +29,7 @@ class Condition(TypedDict, total=False): "exists", "not_exists", "contains_all", + "not_contains_all", "is_timestamp", "is_not_timestamp", "is_timestamp_on_or_after", From 72ae353d7114cf54164169db4623aeb0964485c1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 17:48:24 +0000 Subject: [PATCH 18/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/shared/condition.py | 1 - src/knockapi/types/shared_params/condition.py | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 960ae3c..5c35c6d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-6c3b72254f0f994d27c16100e3555edcc6001a3c986519567adcc51cdfe1261c.yml -openapi_spec_hash: 2e6ed3ff848d34fba88d965b06120fd4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-49a6bd373e9b091c767273d512ca517d1452c1ab954230454534cab87a9e6a1b.yml +openapi_spec_hash: 7503066f9de54d7b8dbf50543b1b7929 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/shared/condition.py b/src/knockapi/types/shared/condition.py index a255255..7a3879b 100644 --- a/src/knockapi/types/shared/condition.py +++ b/src/knockapi/types/shared/condition.py @@ -28,7 +28,6 @@ class Condition(BaseModel): "exists", "not_exists", "contains_all", - "not_contains_all", "is_timestamp", "is_not_timestamp", "is_timestamp_on_or_after", diff --git a/src/knockapi/types/shared_params/condition.py b/src/knockapi/types/shared_params/condition.py index 5adfddf..4da8f40 100644 --- a/src/knockapi/types/shared_params/condition.py +++ b/src/knockapi/types/shared_params/condition.py @@ -29,7 +29,6 @@ class Condition(TypedDict, total=False): "exists", "not_exists", "contains_all", - "not_contains_all", "is_timestamp", "is_not_timestamp", "is_timestamp_on_or_after", From d58778468a31d3f085c5b75eeca367d3f69c1694 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 15:57:06 +0000 Subject: [PATCH 19/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/shared/condition.py | 1 + src/knockapi/types/shared_params/condition.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5c35c6d..ceddeea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-49a6bd373e9b091c767273d512ca517d1452c1ab954230454534cab87a9e6a1b.yml -openapi_spec_hash: 7503066f9de54d7b8dbf50543b1b7929 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce4e8d1b89387fd949bbe362b3500d56e309e00d5ff2b94668c1d9f4c20776d.yml +openapi_spec_hash: 23febe31df8bbfdc3114ba2ce9b021ed config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/shared/condition.py b/src/knockapi/types/shared/condition.py index 7a3879b..a255255 100644 --- a/src/knockapi/types/shared/condition.py +++ b/src/knockapi/types/shared/condition.py @@ -28,6 +28,7 @@ class Condition(BaseModel): "exists", "not_exists", "contains_all", + "not_contains_all", "is_timestamp", "is_not_timestamp", "is_timestamp_on_or_after", diff --git a/src/knockapi/types/shared_params/condition.py b/src/knockapi/types/shared_params/condition.py index 4da8f40..5adfddf 100644 --- a/src/knockapi/types/shared_params/condition.py +++ b/src/knockapi/types/shared_params/condition.py @@ -29,6 +29,7 @@ class Condition(TypedDict, total=False): "exists", "not_exists", "contains_all", + "not_contains_all", "is_timestamp", "is_not_timestamp", "is_timestamp_on_or_after", From f056999c633a20387c7c3ca0d03e6896398bf354 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:17:19 +0000 Subject: [PATCH 20/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index ceddeea..e840854 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce4e8d1b89387fd949bbe362b3500d56e309e00d5ff2b94668c1d9f4c20776d.yml -openapi_spec_hash: 23febe31df8bbfdc3114ba2ce9b021ed +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-304901d28dd866d97329d1fb246d952d00ba02bf8f509f03853f4b532fff1f5c.yml +openapi_spec_hash: da37e7d9f9375fda003a900acb408da7 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From 45246a08de7846278ecf8c628e983f323135030e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:35:46 +0000 Subject: [PATCH 21/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index e840854..ceddeea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-304901d28dd866d97329d1fb246d952d00ba02bf8f509f03853f4b532fff1f5c.yml -openapi_spec_hash: da37e7d9f9375fda003a900acb408da7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce4e8d1b89387fd949bbe362b3500d56e309e00d5ff2b94668c1d9f4c20776d.yml +openapi_spec_hash: 23febe31df8bbfdc3114ba2ce9b021ed config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" From ff11bb4724ba4cbb1d7da0e962c16dfa6202cdc2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 21:34:08 +0000 Subject: [PATCH 22/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message.py | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index ceddeea..903c534 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce4e8d1b89387fd949bbe362b3500d56e309e00d5ff2b94668c1d9f4c20776d.yml -openapi_spec_hash: 23febe31df8bbfdc3114ba2ce9b021ed +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5510d088175a14cf0d6fe117b42ba6e4dc898cd87ea89c76ccac0c8f1f75077e.yml +openapi_spec_hash: a39cd215c648ae625d0f68b05fcc7cde config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message.py b/src/knockapi/types/message.py index b368ffd..a5fb7bd 100644 --- a/src/knockapi/types/message.py +++ b/src/knockapi/types/message.py @@ -9,7 +9,7 @@ from .._models import BaseModel from .recipient_reference import RecipientReference -__all__ = ["Message", "Source", "Channel"] +__all__ = ["Message", "Source", "Channel", "RecipientSnapshot"] class Source(BaseModel): @@ -71,6 +71,19 @@ class Channel(BaseModel): """The human-readable name of the channel.""" +class RecipientSnapshot(BaseModel): + """Recipient contact information captured at email send time. + + Null for non-email channels. + """ + + email: Optional[str] = None + """The email address the message was delivered to""" + + name: Optional[str] = None + """The recipient name at send time""" + + class Message(BaseModel): """ Represents a single message that was generated by a workflow for a given channel. @@ -144,6 +157,12 @@ class Message(BaseModel): read_at: Optional[datetime] = None """Timestamp when the message was read.""" + recipient_snapshot: Optional[RecipientSnapshot] = None + """Recipient contact information captured at email send time. + + Null for non-email channels. + """ + scheduled_at: Optional[datetime] = None """Timestamp when the message was scheduled to be sent.""" From d01a71b3d70e2d41c7699ebf46c71c805aa04a36 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 10:22:49 +0000 Subject: [PATCH 23/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 903c534..8eaa593 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5510d088175a14cf0d6fe117b42ba6e4dc898cd87ea89c76ccac0c8f1f75077e.yml -openapi_spec_hash: a39cd215c648ae625d0f68b05fcc7cde +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-af9ca6816ceac17bfac3ab8eb9abee761db04252f4195b0b466bc31d3bb4be6c.yml +openapi_spec_hash: 966e424d276460ac50dc3d974a3773d6 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From cc4aff98cc1b0213a1215c7751da5383f17ef533 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:32:01 +0000 Subject: [PATCH 24/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message.py | 21 +-------------------- src/knockapi/types/message_event.py | 8 ++++---- 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8eaa593..ceddeea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-af9ca6816ceac17bfac3ab8eb9abee761db04252f4195b0b466bc31d3bb4be6c.yml -openapi_spec_hash: 966e424d276460ac50dc3d974a3773d6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce4e8d1b89387fd949bbe362b3500d56e309e00d5ff2b94668c1d9f4c20776d.yml +openapi_spec_hash: 23febe31df8bbfdc3114ba2ce9b021ed config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message.py b/src/knockapi/types/message.py index a5fb7bd..b368ffd 100644 --- a/src/knockapi/types/message.py +++ b/src/knockapi/types/message.py @@ -9,7 +9,7 @@ from .._models import BaseModel from .recipient_reference import RecipientReference -__all__ = ["Message", "Source", "Channel", "RecipientSnapshot"] +__all__ = ["Message", "Source", "Channel"] class Source(BaseModel): @@ -71,19 +71,6 @@ class Channel(BaseModel): """The human-readable name of the channel.""" -class RecipientSnapshot(BaseModel): - """Recipient contact information captured at email send time. - - Null for non-email channels. - """ - - email: Optional[str] = None - """The email address the message was delivered to""" - - name: Optional[str] = None - """The recipient name at send time""" - - class Message(BaseModel): """ Represents a single message that was generated by a workflow for a given channel. @@ -157,12 +144,6 @@ class Message(BaseModel): read_at: Optional[datetime] = None """Timestamp when the message was read.""" - recipient_snapshot: Optional[RecipientSnapshot] = None - """Recipient contact information captured at email send time. - - Null for non-email channels. - """ - scheduled_at: Optional[datetime] = None """Timestamp when the message was scheduled to be sent.""" diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" From da1eebdadd17a6e62b69bd0187d8098af18ba02f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:51:03 +0000 Subject: [PATCH 25/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message.py | 21 ++++++++++++++++++++- src/knockapi/types/message_event.py | 8 ++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index ceddeea..8eaa593 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce4e8d1b89387fd949bbe362b3500d56e309e00d5ff2b94668c1d9f4c20776d.yml -openapi_spec_hash: 23febe31df8bbfdc3114ba2ce9b021ed +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-af9ca6816ceac17bfac3ab8eb9abee761db04252f4195b0b466bc31d3bb4be6c.yml +openapi_spec_hash: 966e424d276460ac50dc3d974a3773d6 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message.py b/src/knockapi/types/message.py index b368ffd..a5fb7bd 100644 --- a/src/knockapi/types/message.py +++ b/src/knockapi/types/message.py @@ -9,7 +9,7 @@ from .._models import BaseModel from .recipient_reference import RecipientReference -__all__ = ["Message", "Source", "Channel"] +__all__ = ["Message", "Source", "Channel", "RecipientSnapshot"] class Source(BaseModel): @@ -71,6 +71,19 @@ class Channel(BaseModel): """The human-readable name of the channel.""" +class RecipientSnapshot(BaseModel): + """Recipient contact information captured at email send time. + + Null for non-email channels. + """ + + email: Optional[str] = None + """The email address the message was delivered to""" + + name: Optional[str] = None + """The recipient name at send time""" + + class Message(BaseModel): """ Represents a single message that was generated by a workflow for a given channel. @@ -144,6 +157,12 @@ class Message(BaseModel): read_at: Optional[datetime] = None """Timestamp when the message was read.""" + recipient_snapshot: Optional[RecipientSnapshot] = None + """Recipient contact information captured at email send time. + + Null for non-email channels. + """ + scheduled_at: Optional[datetime] = None """Timestamp when the message was scheduled to be sent.""" diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From f53e71fc4c49e6a45666986f809404870325e453 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 07:53:20 +0000 Subject: [PATCH 26/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- src/knockapi/types/recipients/slack_channel_data.py | 10 +++++++++- .../types/recipients/slack_channel_data_param.py | 10 +++++++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8eaa593..89463ca 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-af9ca6816ceac17bfac3ab8eb9abee761db04252f4195b0b466bc31d3bb4be6c.yml -openapi_spec_hash: 966e424d276460ac50dc3d974a3773d6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5c3e6b29dfb4ee5811c311c6012d38dbf7ce1030ad655aead40c1c6b3576cb15.yml +openapi_spec_hash: 571b56ac280b0f82268155416fb14a78 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" diff --git a/src/knockapi/types/recipients/slack_channel_data.py b/src/knockapi/types/recipients/slack_channel_data.py index 261631d..f241c7a 100644 --- a/src/knockapi/types/recipients/slack_channel_data.py +++ b/src/knockapi/types/recipients/slack_channel_data.py @@ -10,6 +10,7 @@ "Connection", "ConnectionSlackTokenConnection", "ConnectionSlackIncomingWebhookConnection", + "ConnectionSlackIncomingWebhookConnectionIncomingWebhook", "Token", ] @@ -27,13 +28,20 @@ class ConnectionSlackTokenConnection(BaseModel): """A Slack user ID from the Slack provider.""" -class ConnectionSlackIncomingWebhookConnection(BaseModel): +class ConnectionSlackIncomingWebhookConnectionIncomingWebhook(BaseModel): """A Slack connection incoming webhook.""" url: str """The URL of the incoming webhook for a Slack connection.""" +class ConnectionSlackIncomingWebhookConnection(BaseModel): + """A Slack connection incoming webhook.""" + + incoming_webhook: ConnectionSlackIncomingWebhookConnectionIncomingWebhook + """A Slack connection incoming webhook.""" + + Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] diff --git a/src/knockapi/types/recipients/slack_channel_data_param.py b/src/knockapi/types/recipients/slack_channel_data_param.py index 0100c10..c2ef29c 100644 --- a/src/knockapi/types/recipients/slack_channel_data_param.py +++ b/src/knockapi/types/recipients/slack_channel_data_param.py @@ -10,6 +10,7 @@ "Connection", "ConnectionSlackTokenConnection", "ConnectionSlackIncomingWebhookConnection", + "ConnectionSlackIncomingWebhookConnectionIncomingWebhook", "Token", ] @@ -27,13 +28,20 @@ class ConnectionSlackTokenConnection(TypedDict, total=False): """A Slack user ID from the Slack provider.""" -class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): +class ConnectionSlackIncomingWebhookConnectionIncomingWebhook(TypedDict, total=False): """A Slack connection incoming webhook.""" url: Required[str] """The URL of the incoming webhook for a Slack connection.""" +class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): + """A Slack connection incoming webhook.""" + + incoming_webhook: Required[ConnectionSlackIncomingWebhookConnectionIncomingWebhook] + """A Slack connection incoming webhook.""" + + Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] From 0759719e28f705d6d77d25a1cd34463db0e5e43b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:11:11 +0000 Subject: [PATCH 27/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/recipients/slack_channel_data.py | 10 +--------- .../types/recipients/slack_channel_data_param.py | 10 +--------- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/.stats.yml b/.stats.yml index 89463ca..903c534 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5c3e6b29dfb4ee5811c311c6012d38dbf7ce1030ad655aead40c1c6b3576cb15.yml -openapi_spec_hash: 571b56ac280b0f82268155416fb14a78 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5510d088175a14cf0d6fe117b42ba6e4dc898cd87ea89c76ccac0c8f1f75077e.yml +openapi_spec_hash: a39cd215c648ae625d0f68b05fcc7cde config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/recipients/slack_channel_data.py b/src/knockapi/types/recipients/slack_channel_data.py index f241c7a..261631d 100644 --- a/src/knockapi/types/recipients/slack_channel_data.py +++ b/src/knockapi/types/recipients/slack_channel_data.py @@ -10,7 +10,6 @@ "Connection", "ConnectionSlackTokenConnection", "ConnectionSlackIncomingWebhookConnection", - "ConnectionSlackIncomingWebhookConnectionIncomingWebhook", "Token", ] @@ -28,20 +27,13 @@ class ConnectionSlackTokenConnection(BaseModel): """A Slack user ID from the Slack provider.""" -class ConnectionSlackIncomingWebhookConnectionIncomingWebhook(BaseModel): +class ConnectionSlackIncomingWebhookConnection(BaseModel): """A Slack connection incoming webhook.""" url: str """The URL of the incoming webhook for a Slack connection.""" -class ConnectionSlackIncomingWebhookConnection(BaseModel): - """A Slack connection incoming webhook.""" - - incoming_webhook: ConnectionSlackIncomingWebhookConnectionIncomingWebhook - """A Slack connection incoming webhook.""" - - Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] diff --git a/src/knockapi/types/recipients/slack_channel_data_param.py b/src/knockapi/types/recipients/slack_channel_data_param.py index c2ef29c..0100c10 100644 --- a/src/knockapi/types/recipients/slack_channel_data_param.py +++ b/src/knockapi/types/recipients/slack_channel_data_param.py @@ -10,7 +10,6 @@ "Connection", "ConnectionSlackTokenConnection", "ConnectionSlackIncomingWebhookConnection", - "ConnectionSlackIncomingWebhookConnectionIncomingWebhook", "Token", ] @@ -28,20 +27,13 @@ class ConnectionSlackTokenConnection(TypedDict, total=False): """A Slack user ID from the Slack provider.""" -class ConnectionSlackIncomingWebhookConnectionIncomingWebhook(TypedDict, total=False): +class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): """A Slack connection incoming webhook.""" url: Required[str] """The URL of the incoming webhook for a Slack connection.""" -class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): - """A Slack connection incoming webhook.""" - - incoming_webhook: Required[ConnectionSlackIncomingWebhookConnectionIncomingWebhook] - """A Slack connection incoming webhook.""" - - Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] From 385770f1fa876f3214c4d81994c13b7b2ba3c757 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:44:31 +0000 Subject: [PATCH 28/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/recipients/slack_channel_data.py | 10 +++++++++- .../types/recipients/slack_channel_data_param.py | 10 +++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 903c534..89463ca 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5510d088175a14cf0d6fe117b42ba6e4dc898cd87ea89c76ccac0c8f1f75077e.yml -openapi_spec_hash: a39cd215c648ae625d0f68b05fcc7cde +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5c3e6b29dfb4ee5811c311c6012d38dbf7ce1030ad655aead40c1c6b3576cb15.yml +openapi_spec_hash: 571b56ac280b0f82268155416fb14a78 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/recipients/slack_channel_data.py b/src/knockapi/types/recipients/slack_channel_data.py index 261631d..f241c7a 100644 --- a/src/knockapi/types/recipients/slack_channel_data.py +++ b/src/knockapi/types/recipients/slack_channel_data.py @@ -10,6 +10,7 @@ "Connection", "ConnectionSlackTokenConnection", "ConnectionSlackIncomingWebhookConnection", + "ConnectionSlackIncomingWebhookConnectionIncomingWebhook", "Token", ] @@ -27,13 +28,20 @@ class ConnectionSlackTokenConnection(BaseModel): """A Slack user ID from the Slack provider.""" -class ConnectionSlackIncomingWebhookConnection(BaseModel): +class ConnectionSlackIncomingWebhookConnectionIncomingWebhook(BaseModel): """A Slack connection incoming webhook.""" url: str """The URL of the incoming webhook for a Slack connection.""" +class ConnectionSlackIncomingWebhookConnection(BaseModel): + """A Slack connection incoming webhook.""" + + incoming_webhook: ConnectionSlackIncomingWebhookConnectionIncomingWebhook + """A Slack connection incoming webhook.""" + + Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] diff --git a/src/knockapi/types/recipients/slack_channel_data_param.py b/src/knockapi/types/recipients/slack_channel_data_param.py index 0100c10..c2ef29c 100644 --- a/src/knockapi/types/recipients/slack_channel_data_param.py +++ b/src/knockapi/types/recipients/slack_channel_data_param.py @@ -10,6 +10,7 @@ "Connection", "ConnectionSlackTokenConnection", "ConnectionSlackIncomingWebhookConnection", + "ConnectionSlackIncomingWebhookConnectionIncomingWebhook", "Token", ] @@ -27,13 +28,20 @@ class ConnectionSlackTokenConnection(TypedDict, total=False): """A Slack user ID from the Slack provider.""" -class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): +class ConnectionSlackIncomingWebhookConnectionIncomingWebhook(TypedDict, total=False): """A Slack connection incoming webhook.""" url: Required[str] """The URL of the incoming webhook for a Slack connection.""" +class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): + """A Slack connection incoming webhook.""" + + incoming_webhook: Required[ConnectionSlackIncomingWebhookConnectionIncomingWebhook] + """A Slack connection incoming webhook.""" + + Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] From 84f04fa741708c52e808d0a9d16ecef51e8b9278 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 10:04:07 +0000 Subject: [PATCH 29/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 89463ca..99c5181 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-5c3e6b29dfb4ee5811c311c6012d38dbf7ce1030ad655aead40c1c6b3576cb15.yml -openapi_spec_hash: 571b56ac280b0f82268155416fb14a78 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-b42b3885822c03188c2cb418d1aa851762ef1c21cb60df47cfa1a4f8324785ef.yml +openapi_spec_hash: 57558c1ee413f957ee574df59f7b64ce config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From 75bdef9bb327961a6ca2e5f77339b49deaaa0c1d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:40:24 +0000 Subject: [PATCH 30/45] feat(api): api update --- .stats.yml | 4 ++-- README.md | 9 +++++---- src/knockapi/resources/workflows.py | 8 ++++++++ src/knockapi/types/workflow_trigger_params.py | 16 +++++++++++++++- tests/api_resources/test_workflows.py | 2 ++ 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index 99c5181..d999c8d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-b42b3885822c03188c2cb418d1aa851762ef1c21cb60df47cfa1a4f8324785ef.yml -openapi_spec_hash: 57558c1ee413f957ee574df59f7b64ce +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-be7b5bed750e6c98f4e8151a45b4bebafc3a8aa6ab0eae95fc1d9a2ff852be9d.yml +openapi_spec_hash: a1a14a0e8251e55df9d6e6ecb0d0c675 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/README.md b/README.md index 169ec8e..17416fc 100644 --- a/README.md +++ b/README.md @@ -190,11 +190,12 @@ from knockapi import Knock client = Knock() -page = client.users.list_messages( - user_id="user-123", - inserted_at={}, +response = client.workflows.trigger( + key="key", + recipients=["dr_grant", "dr_sattler", "dr_malcolm"], + settings={"sandbox_mode": True}, ) -print(page.items) +print(response.settings) ``` ## Handling errors diff --git a/src/knockapi/resources/workflows.py b/src/knockapi/resources/workflows.py index 8706094..232e6c9 100644 --- a/src/knockapi/resources/workflows.py +++ b/src/knockapi/resources/workflows.py @@ -119,6 +119,7 @@ def trigger( actor: Optional[RecipientRequestParam] | Omit = omit, cancellation_key: Optional[str] | Omit = omit, data: Optional[Dict[str, object]] | Omit = omit, + settings: Optional[workflow_trigger_params.Settings] | Omit = omit, tenant: Optional[InlineTenantRequestParam] | 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. @@ -154,6 +155,8 @@ def trigger( greater than 1024 bytes in length will be [truncated](/developer-tools/api-logs#log-truncation) in your logs. + settings: Optional settings that control how this workflow trigger is executed. + tenant: An request to set a tenant inline. extra_headers: Send extra headers @@ -176,6 +179,7 @@ def trigger( "actor": actor, "cancellation_key": cancellation_key, "data": data, + "settings": settings, "tenant": tenant, }, workflow_trigger_params.WorkflowTriggerParams, @@ -284,6 +288,7 @@ async def trigger( actor: Optional[RecipientRequestParam] | Omit = omit, cancellation_key: Optional[str] | Omit = omit, data: Optional[Dict[str, object]] | Omit = omit, + settings: Optional[workflow_trigger_params.Settings] | Omit = omit, tenant: Optional[InlineTenantRequestParam] | 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. @@ -319,6 +324,8 @@ async def trigger( greater than 1024 bytes in length will be [truncated](/developer-tools/api-logs#log-truncation) in your logs. + settings: Optional settings that control how this workflow trigger is executed. + tenant: An request to set a tenant inline. extra_headers: Send extra headers @@ -341,6 +348,7 @@ async def trigger( "actor": actor, "cancellation_key": cancellation_key, "data": data, + "settings": settings, "tenant": tenant, }, workflow_trigger_params.WorkflowTriggerParams, diff --git a/src/knockapi/types/workflow_trigger_params.py b/src/knockapi/types/workflow_trigger_params.py index 24088b4..50418c5 100644 --- a/src/knockapi/types/workflow_trigger_params.py +++ b/src/knockapi/types/workflow_trigger_params.py @@ -9,7 +9,7 @@ from .recipient_request_param import RecipientRequestParam from .inline_tenant_request_param import InlineTenantRequestParam -__all__ = ["WorkflowTriggerParams"] +__all__ = ["WorkflowTriggerParams", "Settings"] class WorkflowTriggerParams(TypedDict, total=False): @@ -45,5 +45,19 @@ class WorkflowTriggerParams(TypedDict, total=False): [truncated](/developer-tools/api-logs#log-truncation) in your logs. """ + settings: Optional[Settings] + """Optional settings that control how this workflow trigger is executed.""" + tenant: Optional[InlineTenantRequestParam] """An request to set a tenant inline.""" + + +class Settings(TypedDict, total=False): + """Optional settings that control how this workflow trigger is executed.""" + + sandbox_mode: Optional[bool] + """ + When set to true, overrides the sandbox mode for all channels in this workflow + run, messages are not delivered to the underlying providers. If false or not + set, the workflow delivers messages normally. + """ diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 7653239..327fae9 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -93,6 +93,7 @@ def test_method_trigger_with_all_params(self, client: Knock) -> None: "severity": "bar", "system_status": "bar", }, + settings={"sandbox_mode": True}, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) @@ -211,6 +212,7 @@ async def test_method_trigger_with_all_params(self, async_client: AsyncKnock) -> "severity": "bar", "system_status": "bar", }, + settings={"sandbox_mode": True}, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) From 8f3a9d18b69e5c5fd84bec640a634c3f7ac4f823 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 17:29:41 +0000 Subject: [PATCH 31/45] feat(api): api update --- .stats.yml | 4 ++-- README.md | 5 ++++- src/knockapi/types/workflow_trigger_params.py | 7 +++++++ tests/api_resources/test_workflows.py | 10 ++++++++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index d999c8d..a2dee2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-be7b5bed750e6c98f4e8151a45b4bebafc3a8aa6ab0eae95fc1d9a2ff852be9d.yml -openapi_spec_hash: a1a14a0e8251e55df9d6e6ecb0d0c675 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8df4c4cf914f64f1d4926b9b913fa40267a9558b7fc2ab0db2867a6fc29edd57.yml +openapi_spec_hash: a5dff3ff3dac4798b76578cb4c7c8dc1 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/README.md b/README.md index 17416fc..1ab5f9b 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,10 @@ client = Knock() response = client.workflows.trigger( key="key", recipients=["dr_grant", "dr_sattler", "dr_malcolm"], - settings={"sandbox_mode": True}, + settings={ + "sandbox_mode": True, + "skip_delay": True, + }, ) print(response.settings) ``` diff --git a/src/knockapi/types/workflow_trigger_params.py b/src/knockapi/types/workflow_trigger_params.py index 50418c5..373dec0 100644 --- a/src/knockapi/types/workflow_trigger_params.py +++ b/src/knockapi/types/workflow_trigger_params.py @@ -61,3 +61,10 @@ class Settings(TypedDict, total=False): run, messages are not delivered to the underlying providers. If false or not set, the workflow delivers messages normally. """ + + skip_delay: Optional[bool] + """When set to true, skips all delay steps in the workflow for this trigger + request. + + If false or not set, delay steps execute normally. + """ diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 327fae9..7bd00fa 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -93,7 +93,10 @@ def test_method_trigger_with_all_params(self, client: Knock) -> None: "severity": "bar", "system_status": "bar", }, - settings={"sandbox_mode": True}, + settings={ + "sandbox_mode": True, + "skip_delay": True, + }, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) @@ -212,7 +215,10 @@ async def test_method_trigger_with_all_params(self, async_client: AsyncKnock) -> "severity": "bar", "system_status": "bar", }, - settings={"sandbox_mode": True}, + settings={ + "sandbox_mode": True, + "skip_delay": True, + }, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) From edbcb1532aa9d87d505c0ebc5980da3d04fbb0dd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 18:58:35 +0000 Subject: [PATCH 32/45] feat(api): api update --- .stats.yml | 4 ++-- README.md | 5 +---- src/knockapi/types/message_event.py | 8 ++++---- src/knockapi/types/workflow_trigger_params.py | 7 ------- tests/api_resources/test_workflows.py | 10 ++-------- 5 files changed, 9 insertions(+), 25 deletions(-) diff --git a/.stats.yml b/.stats.yml index a2dee2e..b023cd7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8df4c4cf914f64f1d4926b9b913fa40267a9558b7fc2ab0db2867a6fc29edd57.yml -openapi_spec_hash: a5dff3ff3dac4798b76578cb4c7c8dc1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-d859f28a4d971b6fc63b5d0d0c43b09289ca9d64b25b393611e282c221b59204.yml +openapi_spec_hash: cbfd341f327ceeaa11e5d482159639d2 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/README.md b/README.md index 1ab5f9b..17416fc 100644 --- a/README.md +++ b/README.md @@ -193,10 +193,7 @@ client = Knock() response = client.workflows.trigger( key="key", recipients=["dr_grant", "dr_sattler", "dr_malcolm"], - settings={ - "sandbox_mode": True, - "skip_delay": True, - }, + settings={"sandbox_mode": True}, ) print(response.settings) ``` diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" diff --git a/src/knockapi/types/workflow_trigger_params.py b/src/knockapi/types/workflow_trigger_params.py index 373dec0..50418c5 100644 --- a/src/knockapi/types/workflow_trigger_params.py +++ b/src/knockapi/types/workflow_trigger_params.py @@ -61,10 +61,3 @@ class Settings(TypedDict, total=False): run, messages are not delivered to the underlying providers. If false or not set, the workflow delivers messages normally. """ - - skip_delay: Optional[bool] - """When set to true, skips all delay steps in the workflow for this trigger - request. - - If false or not set, delay steps execute normally. - """ diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 7bd00fa..327fae9 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -93,10 +93,7 @@ def test_method_trigger_with_all_params(self, client: Knock) -> None: "severity": "bar", "system_status": "bar", }, - settings={ - "sandbox_mode": True, - "skip_delay": True, - }, + settings={"sandbox_mode": True}, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) @@ -215,10 +212,7 @@ async def test_method_trigger_with_all_params(self, async_client: AsyncKnock) -> "severity": "bar", "system_status": "bar", }, - settings={ - "sandbox_mode": True, - "skip_delay": True, - }, + settings={"sandbox_mode": True}, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) From 43412da962d2521710dd41058bd4c5074d17e3d1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 06:52:31 +0000 Subject: [PATCH 33/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index b023cd7..d999c8d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-d859f28a4d971b6fc63b5d0d0c43b09289ca9d64b25b393611e282c221b59204.yml -openapi_spec_hash: cbfd341f327ceeaa11e5d482159639d2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-be7b5bed750e6c98f4e8151a45b4bebafc3a8aa6ab0eae95fc1d9a2ff852be9d.yml +openapi_spec_hash: a1a14a0e8251e55df9d6e6ecb0d0c675 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From e181bcbd1beb5423c04f5f176b2aa4fb997f3f8c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 19:14:31 +0000 Subject: [PATCH 34/45] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d999c8d..93cb1ab 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-be7b5bed750e6c98f4e8151a45b4bebafc3a8aa6ab0eae95fc1d9a2ff852be9d.yml -openapi_spec_hash: a1a14a0e8251e55df9d6e6ecb0d0c675 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-c74d7e55b4f746714d4be9617164282634e1b9b6c5de7629e093618b5e47b279.yml +openapi_spec_hash: 732830246d0490768a1e36c84f892cb2 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From 52c59f74ebbd0670333af8afd67f6ffa259e58e1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:18:49 +0000 Subject: [PATCH 35/45] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 93cb1ab..d999c8d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-c74d7e55b4f746714d4be9617164282634e1b9b6c5de7629e093618b5e47b279.yml -openapi_spec_hash: 732830246d0490768a1e36c84f892cb2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-be7b5bed750e6c98f4e8151a45b4bebafc3a8aa6ab0eae95fc1d9a2ff852be9d.yml +openapi_spec_hash: a1a14a0e8251e55df9d6e6ecb0d0c675 config_hash: 625db64572b7ee0ee1dd00546e53fc5f From c4e760e67d085de8b0e468a2e98775f4ab93bd66 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:32:31 +0000 Subject: [PATCH 36/45] feat(api): api update --- .stats.yml | 4 ++-- README.md | 5 ++++- src/knockapi/types/workflow_trigger_params.py | 7 +++++++ tests/api_resources/test_workflows.py | 10 ++++++++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index d999c8d..a2dee2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-be7b5bed750e6c98f4e8151a45b4bebafc3a8aa6ab0eae95fc1d9a2ff852be9d.yml -openapi_spec_hash: a1a14a0e8251e55df9d6e6ecb0d0c675 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8df4c4cf914f64f1d4926b9b913fa40267a9558b7fc2ab0db2867a6fc29edd57.yml +openapi_spec_hash: a5dff3ff3dac4798b76578cb4c7c8dc1 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/README.md b/README.md index 17416fc..1ab5f9b 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,10 @@ client = Knock() response = client.workflows.trigger( key="key", recipients=["dr_grant", "dr_sattler", "dr_malcolm"], - settings={"sandbox_mode": True}, + settings={ + "sandbox_mode": True, + "skip_delay": True, + }, ) print(response.settings) ``` diff --git a/src/knockapi/types/workflow_trigger_params.py b/src/knockapi/types/workflow_trigger_params.py index 50418c5..373dec0 100644 --- a/src/knockapi/types/workflow_trigger_params.py +++ b/src/knockapi/types/workflow_trigger_params.py @@ -61,3 +61,10 @@ class Settings(TypedDict, total=False): run, messages are not delivered to the underlying providers. If false or not set, the workflow delivers messages normally. """ + + skip_delay: Optional[bool] + """When set to true, skips all delay steps in the workflow for this trigger + request. + + If false or not set, delay steps execute normally. + """ diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 327fae9..7bd00fa 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -93,7 +93,10 @@ def test_method_trigger_with_all_params(self, client: Knock) -> None: "severity": "bar", "system_status": "bar", }, - settings={"sandbox_mode": True}, + settings={ + "sandbox_mode": True, + "skip_delay": True, + }, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) @@ -212,7 +215,10 @@ async def test_method_trigger_with_all_params(self, async_client: AsyncKnock) -> "severity": "bar", "system_status": "bar", }, - settings={"sandbox_mode": True}, + settings={ + "sandbox_mode": True, + "skip_delay": True, + }, tenant="ingen_isla_nublar", ) assert_matches_type(WorkflowTriggerResponse, workflow, path=["response"]) From ea6a7b20b8b6945407270414c377e0d0cacbe549 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 19:58:43 +0000 Subject: [PATCH 37/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index a2dee2e..a48c06e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8df4c4cf914f64f1d4926b9b913fa40267a9558b7fc2ab0db2867a6fc29edd57.yml -openapi_spec_hash: a5dff3ff3dac4798b76578cb4c7c8dc1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce258ba68dc2bd3ece04f80d57367fd30371b21abe309183aa444a7e3a7562c.yml +openapi_spec_hash: 94a2b63ecf5a86b76ebd9641b5b395ad config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" From 98cab8e55b0c27929c8ed10655aefedb8d56ccca Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 07:57:47 +0000 Subject: [PATCH 38/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index a48c06e..71e0a95 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce258ba68dc2bd3ece04f80d57367fd30371b21abe309183aa444a7e3a7562c.yml -openapi_spec_hash: 94a2b63ecf5a86b76ebd9641b5b395ad +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8bafdf65ee77c3fa7f0b3f0f01701d33a5d5d4af508f6a8ddd2ffe678fd734d7.yml +openapi_spec_hash: 1201b3d5db4b0361a7f5dcf158b29368 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From ac2b316b3b0436305d61e147d438b21189c7603f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:27:58 +0000 Subject: [PATCH 39/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 71e0a95..a48c06e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8bafdf65ee77c3fa7f0b3f0f01701d33a5d5d4af508f6a8ddd2ffe678fd734d7.yml -openapi_spec_hash: 1201b3d5db4b0361a7f5dcf158b29368 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce258ba68dc2bd3ece04f80d57367fd30371b21abe309183aa444a7e3a7562c.yml +openapi_spec_hash: 94a2b63ecf5a86b76ebd9641b5b395ad config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" From ca1f59724d1643bf5f863d7b030c05ddddc0dd8f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 17:20:53 +0000 Subject: [PATCH 40/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index a48c06e..71e0a95 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce258ba68dc2bd3ece04f80d57367fd30371b21abe309183aa444a7e3a7562c.yml -openapi_spec_hash: 94a2b63ecf5a86b76ebd9641b5b395ad +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8bafdf65ee77c3fa7f0b3f0f01701d33a5d5d4af508f6a8ddd2ffe678fd734d7.yml +openapi_spec_hash: 1201b3d5db4b0361a7f5dcf158b29368 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From 63378d10a51e7f7dceeab05d7dd98015f143852f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:27:39 +0000 Subject: [PATCH 41/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 71e0a95..a48c06e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8bafdf65ee77c3fa7f0b3f0f01701d33a5d5d4af508f6a8ddd2ffe678fd734d7.yml -openapi_spec_hash: 1201b3d5db4b0361a7f5dcf158b29368 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce258ba68dc2bd3ece04f80d57367fd30371b21abe309183aa444a7e3a7562c.yml +openapi_spec_hash: 94a2b63ecf5a86b76ebd9641b5b395ad config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 17faa7e..8caa6d5 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.created", + "message.archived", "message.queued", "message.delivered", + "message.not_sent", "message.bounced", "message.undelivered", - "message.not_sent", "message.delivery_attempted", - "message.archived", "message.link_clicked", "message.interacted", + "message.unarchived", "message.unseen", "message.unread", - "message.unarchived", + "message.created", ] """The type of event that occurred.""" From e81b283f0a2ece6369dc5b1ba0bd6e6410cb433d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 07:51:35 +0000 Subject: [PATCH 42/45] feat(api): api update --- .stats.yml | 4 ++-- src/knockapi/types/message_event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index a48c06e..71e0a95 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8ce258ba68dc2bd3ece04f80d57367fd30371b21abe309183aa444a7e3a7562c.yml -openapi_spec_hash: 94a2b63ecf5a86b76ebd9641b5b395ad +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8bafdf65ee77c3fa7f0b3f0f01701d33a5d5d4af508f6a8ddd2ffe678fd734d7.yml +openapi_spec_hash: 1201b3d5db4b0361a7f5dcf158b29368 config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index 8caa6d5..17faa7e 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -37,19 +37,19 @@ class MessageEvent(BaseModel): "message.read", "message.sent", "message.seen", - "message.archived", + "message.created", "message.queued", "message.delivered", - "message.not_sent", "message.bounced", "message.undelivered", + "message.not_sent", "message.delivery_attempted", + "message.archived", "message.link_clicked", "message.interacted", - "message.unarchived", "message.unseen", "message.unread", - "message.created", + "message.unarchived", ] """The type of event that occurred.""" From c4fc2df8327f44f10823ba20f361d42e1c98f5fd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:15:06 +0000 Subject: [PATCH 43/45] feat(api): api update --- .stats.yml | 4 +- src/knockapi/resources/users/bulk.py | 11 +- .../users/bulk_set_preferences_params.py | 107 +++++++++++++++++- tests/api_resources/users/test_bulk.py | 4 +- 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/.stats.yml b/.stats.yml index 71e0a95..2a11252 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 94 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-8bafdf65ee77c3fa7f0b3f0f01701d33a5d5d4af508f6a8ddd2ffe678fd734d7.yml -openapi_spec_hash: 1201b3d5db4b0361a7f5dcf158b29368 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock/knock-b42896ed120111c98cea7e588b382fdce0ff587b92a779e1eff1e585c3f77039.yml +openapi_spec_hash: 7b326a46e026aabfb75a66d7dfd3010b config_hash: 625db64572b7ee0ee1dd00546e53fc5f diff --git a/src/knockapi/resources/users/bulk.py b/src/knockapi/resources/users/bulk.py index 48e4d62..21212ae 100644 --- a/src/knockapi/resources/users/bulk.py +++ b/src/knockapi/resources/users/bulk.py @@ -20,7 +20,6 @@ from ..._base_client import make_request_options from ...types.bulk_operation import BulkOperation from ...types.inline_identify_user_request_param import InlineIdentifyUserRequestParam -from ...types.recipients.preference_set_request_param import PreferenceSetRequestParam __all__ = ["BulkResource", "AsyncBulkResource"] @@ -137,7 +136,7 @@ def identify( def set_preferences( self, *, - preferences: PreferenceSetRequestParam, + preferences: bulk_set_preferences_params.Preferences, user_ids: SequenceNotStr[str], # 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. @@ -156,7 +155,8 @@ def set_preferences( the preferences sent. Args: - preferences: A request to set a preference set for a recipient. + preferences: A preference set to apply in a bulk operation. Always replaces existing + preferences for the specified set. user_ids: A list of user IDs. @@ -302,7 +302,7 @@ async def identify( async def set_preferences( self, *, - preferences: PreferenceSetRequestParam, + preferences: bulk_set_preferences_params.Preferences, user_ids: SequenceNotStr[str], # 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. @@ -321,7 +321,8 @@ async def set_preferences( the preferences sent. Args: - preferences: A request to set a preference set for a recipient. + preferences: A preference set to apply in a bulk operation. Always replaces existing + preferences for the specified set. user_ids: A list of user IDs. diff --git a/src/knockapi/types/users/bulk_set_preferences_params.py b/src/knockapi/types/users/bulk_set_preferences_params.py index a954ede..c583120 100644 --- a/src/knockapi/types/users/bulk_set_preferences_params.py +++ b/src/knockapi/types/users/bulk_set_preferences_params.py @@ -2,17 +2,114 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Required, TypeAlias, TypedDict from ..._types import SequenceNotStr -from ..recipients.preference_set_request_param import PreferenceSetRequestParam +from ..shared_params.condition import Condition +from ..recipients.preference_set_channel_types_param import PreferenceSetChannelTypesParam +from ..recipients.preference_set_channel_setting_param import PreferenceSetChannelSettingParam -__all__ = ["BulkSetPreferencesParams"] +__all__ = [ + "BulkSetPreferencesParams", + "Preferences", + "PreferencesCategories", + "PreferencesCategoriesPreferenceSetWorkflowCategorySettingObject", + "PreferencesCategoriesPreferenceSetWorkflowCategorySettingObjectChannels", + "PreferencesChannels", + "PreferencesWorkflows", + "PreferencesWorkflowsPreferenceSetWorkflowCategorySettingObject", + "PreferencesWorkflowsPreferenceSetWorkflowCategorySettingObjectChannels", +] class BulkSetPreferencesParams(TypedDict, total=False): - preferences: Required[PreferenceSetRequestParam] - """A request to set a preference set for a recipient.""" + preferences: Required[Preferences] + """A preference set to apply in a bulk operation. + + Always replaces existing preferences for the specified set. + """ user_ids: Required[SequenceNotStr[str]] """A list of user IDs.""" + + +PreferencesCategoriesPreferenceSetWorkflowCategorySettingObjectChannels: TypeAlias = Union[ + bool, PreferenceSetChannelSettingParam +] + + +class PreferencesCategoriesPreferenceSetWorkflowCategorySettingObject(TypedDict, total=False): + """ + The settings object for a workflow or category, where you can specify channel types or conditions. + """ + + channel_types: Optional[PreferenceSetChannelTypesParam] + """Channel type preferences.""" + + channels: Optional[Dict[str, PreferencesCategoriesPreferenceSetWorkflowCategorySettingObjectChannels]] + """Channel preferences.""" + + conditions: Optional[Iterable[Condition]] + """A list of conditions to apply to a channel type.""" + + +PreferencesCategories: TypeAlias = Union[bool, PreferencesCategoriesPreferenceSetWorkflowCategorySettingObject] + +PreferencesChannels: TypeAlias = Union[bool, PreferenceSetChannelSettingParam] + +PreferencesWorkflowsPreferenceSetWorkflowCategorySettingObjectChannels: TypeAlias = Union[ + bool, PreferenceSetChannelSettingParam +] + + +class PreferencesWorkflowsPreferenceSetWorkflowCategorySettingObject(TypedDict, total=False): + """ + The settings object for a workflow or category, where you can specify channel types or conditions. + """ + + channel_types: Optional[PreferenceSetChannelTypesParam] + """Channel type preferences.""" + + channels: Optional[Dict[str, PreferencesWorkflowsPreferenceSetWorkflowCategorySettingObjectChannels]] + """Channel preferences.""" + + conditions: Optional[Iterable[Condition]] + """A list of conditions to apply to a channel type.""" + + +PreferencesWorkflows: TypeAlias = Union[bool, PreferencesWorkflowsPreferenceSetWorkflowCategorySettingObject] + + +class Preferences(TypedDict, total=False): + """A preference set to apply in a bulk operation. + + Always replaces existing preferences for the specified set. + """ + + id: str + """Identifier for the preference set to update. Can be `default` or a tenant ID.""" + + categories: Optional[Dict[str, PreferencesCategories]] + """ + An object where the key is the category and the values are the preference + settings for that category. + """ + + channel_types: Optional[PreferenceSetChannelTypesParam] + """Channel type preferences.""" + + channels: Optional[Dict[str, PreferencesChannels]] + """Channel preferences.""" + + commercial_subscribed: Optional[bool] + """Whether the recipient is subscribed to commercial communications. + + When false, the recipient will not receive commercial workflow notifications. + """ + + workflows: Optional[Dict[str, PreferencesWorkflows]] + """ + An object where the key is the workflow key and the values are the preference + settings for that workflow. + """ diff --git a/tests/api_resources/users/test_bulk.py b/tests/api_resources/users/test_bulk.py index 537d6c8..28af4f8 100644 --- a/tests/api_resources/users/test_bulk.py +++ b/tests/api_resources/users/test_bulk.py @@ -91,7 +91,7 @@ def test_method_set_preferences(self, client: Knock) -> None: def test_method_set_preferences_with_all_params(self, client: Knock) -> None: bulk = client.users.bulk.set_preferences( preferences={ - "_persistence_strategy": "merge", + "id": "default", "categories": { "marketing": False, "transactional": { @@ -385,7 +385,7 @@ async def test_method_set_preferences(self, async_client: AsyncKnock) -> None: async def test_method_set_preferences_with_all_params(self, async_client: AsyncKnock) -> None: bulk = await async_client.users.bulk.set_preferences( preferences={ - "_persistence_strategy": "merge", + "id": "default", "categories": { "marketing": False, "transactional": { From 5f69bb911914f0ca3687ce5fe5ebf4a2d0aae2d6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 19:33:09 +0000 Subject: [PATCH 44/45] fix(types): avoid type-checker errors on params with additional properties --- src/knockapi/types/inline_identify_user_request_param.py | 6 +++++- src/knockapi/types/inline_object_request_param.py | 6 +++++- src/knockapi/types/objects/bulk_set_params.py | 6 +++++- src/knockapi/types/tenant_request_param.py | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/knockapi/types/inline_identify_user_request_param.py b/src/knockapi/types/inline_identify_user_request_param.py index 07c5df5..22711bb 100644 --- a/src/knockapi/types/inline_identify_user_request_param.py +++ b/src/knockapi/types/inline_identify_user_request_param.py @@ -13,7 +13,11 @@ __all__ = ["InlineIdentifyUserRequestParam"] -class InlineIdentifyUserRequestParam(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] +class InlineIdentifyUserRequestParam( # type: ignore[call-arg] + TypedDict, + total=False, + extra_items=object, # pyright: ignore[reportGeneralTypeIssues] +): """A set of parameters to inline-identify a user with. Inline identifying the user will ensure that the user is available before the request is executed in Knock. It will perform an upsert for the user you're supplying, replacing any properties specified. diff --git a/src/knockapi/types/inline_object_request_param.py b/src/knockapi/types/inline_object_request_param.py index acedae4..552a6c6 100644 --- a/src/knockapi/types/inline_object_request_param.py +++ b/src/knockapi/types/inline_object_request_param.py @@ -13,7 +13,11 @@ __all__ = ["InlineObjectRequestParam"] -class InlineObjectRequestParam(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] +class InlineObjectRequestParam( # type: ignore[call-arg] + TypedDict, + total=False, + extra_items=object, # pyright: ignore[reportGeneralTypeIssues] +): """A custom [Object](/concepts/objects) entity which belongs to a collection.""" id: Required[str] diff --git a/src/knockapi/types/objects/bulk_set_params.py b/src/knockapi/types/objects/bulk_set_params.py index dda8204..040eaaa 100644 --- a/src/knockapi/types/objects/bulk_set_params.py +++ b/src/knockapi/types/objects/bulk_set_params.py @@ -18,7 +18,11 @@ class BulkSetParams(TypedDict, total=False): """A list of objects.""" -class Object(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] +class Object( # type: ignore[call-arg] + TypedDict, + total=False, + extra_items=object, # pyright: ignore[reportGeneralTypeIssues] +): """A custom [Object](/concepts/objects) entity which belongs to a collection.""" id: Required[str] diff --git a/src/knockapi/types/tenant_request_param.py b/src/knockapi/types/tenant_request_param.py index 58d02b7..3a097b2 100644 --- a/src/knockapi/types/tenant_request_param.py +++ b/src/knockapi/types/tenant_request_param.py @@ -44,7 +44,11 @@ class Settings(TypedDict, total=False): """A request to set a preference set for a recipient.""" -class TenantRequestParam(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] +class TenantRequestParam( # type: ignore[call-arg] + TypedDict, + total=False, + extra_items=object, # pyright: ignore[reportGeneralTypeIssues] +): """A tenant to be set in the system. You can supply any additional properties on the tenant object. From 422f51ef7e3cf6dc62324689bd0ebd1e85f4a281 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 19:33:45 +0000 Subject: [PATCH 45/45] release: 1.26.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 51 +++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/knockapi/_version.py | 2 +- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0c0c0c3..f3dbfd2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.25.0" + ".": "1.26.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ef3d5ea..ffb6804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # Changelog +## 1.26.0 (2026-06-29) + +Full Changelog: [v1.25.0...v1.26.0](https://github.com/knocklabs/knock-python/compare/v1.25.0...v1.26.0) + +### Features + +* **api:** api update ([c4fc2df](https://github.com/knocklabs/knock-python/commit/c4fc2df8327f44f10823ba20f361d42e1c98f5fd)) +* **api:** api update ([e81b283](https://github.com/knocklabs/knock-python/commit/e81b283f0a2ece6369dc5b1ba0bd6e6410cb433d)) +* **api:** api update ([63378d1](https://github.com/knocklabs/knock-python/commit/63378d10a51e7f7dceeab05d7dd98015f143852f)) +* **api:** api update ([ca1f597](https://github.com/knocklabs/knock-python/commit/ca1f59724d1643bf5f863d7b030c05ddddc0dd8f)) +* **api:** api update ([ac2b316](https://github.com/knocklabs/knock-python/commit/ac2b316b3b0436305d61e147d438b21189c7603f)) +* **api:** api update ([98cab8e](https://github.com/knocklabs/knock-python/commit/98cab8e55b0c27929c8ed10655aefedb8d56ccca)) +* **api:** api update ([ea6a7b2](https://github.com/knocklabs/knock-python/commit/ea6a7b20b8b6945407270414c377e0d0cacbe549)) +* **api:** api update ([c4e760e](https://github.com/knocklabs/knock-python/commit/c4e760e67d085de8b0e468a2e98775f4ab93bd66)) +* **api:** api update ([43412da](https://github.com/knocklabs/knock-python/commit/43412da962d2521710dd41058bd4c5074d17e3d1)) +* **api:** api update ([edbcb15](https://github.com/knocklabs/knock-python/commit/edbcb1532aa9d87d505c0ebc5980da3d04fbb0dd)) +* **api:** api update ([8f3a9d1](https://github.com/knocklabs/knock-python/commit/8f3a9d18b69e5c5fd84bec640a634c3f7ac4f823)) +* **api:** api update ([75bdef9](https://github.com/knocklabs/knock-python/commit/75bdef9bb327961a6ca2e5f77339b49deaaa0c1d)) +* **api:** api update ([84f04fa](https://github.com/knocklabs/knock-python/commit/84f04fa741708c52e808d0a9d16ecef51e8b9278)) +* **api:** api update ([385770f](https://github.com/knocklabs/knock-python/commit/385770f1fa876f3214c4d81994c13b7b2ba3c757)) +* **api:** api update ([0759719](https://github.com/knocklabs/knock-python/commit/0759719e28f705d6d77d25a1cd34463db0e5e43b)) +* **api:** api update ([f53e71f](https://github.com/knocklabs/knock-python/commit/f53e71fc4c49e6a45666986f809404870325e453)) +* **api:** api update ([da1eebd](https://github.com/knocklabs/knock-python/commit/da1eebdadd17a6e62b69bd0187d8098af18ba02f)) +* **api:** api update ([cc4aff9](https://github.com/knocklabs/knock-python/commit/cc4aff98cc1b0213a1215c7751da5383f17ef533)) +* **api:** api update ([d01a71b](https://github.com/knocklabs/knock-python/commit/d01a71b3d70e2d41c7699ebf46c71c805aa04a36)) +* **api:** api update ([ff11bb4](https://github.com/knocklabs/knock-python/commit/ff11bb4724ba4cbb1d7da0e962c16dfa6202cdc2)) +* **api:** api update ([45246a0](https://github.com/knocklabs/knock-python/commit/45246a08de7846278ecf8c628e983f323135030e)) +* **api:** api update ([f056999](https://github.com/knocklabs/knock-python/commit/f056999c633a20387c7c3ca0d03e6896398bf354)) +* **api:** api update ([d587784](https://github.com/knocklabs/knock-python/commit/d58778468a31d3f085c5b75eeca367d3f69c1694)) +* **api:** api update ([72ae353](https://github.com/knocklabs/knock-python/commit/72ae353d7114cf54164169db4623aeb0964485c1)) +* **api:** api update ([08f1af8](https://github.com/knocklabs/knock-python/commit/08f1af8a783072188da2bf1301fa3fad2b599271)) +* **api:** api update ([6b7bf04](https://github.com/knocklabs/knock-python/commit/6b7bf04ce3367a43fd7190d739ac07ac0e4540db)) +* **api:** api update ([4ade4a7](https://github.com/knocklabs/knock-python/commit/4ade4a73e6121f40677e6e497e7979ef3769ab6d)) +* **api:** api update ([39e6add](https://github.com/knocklabs/knock-python/commit/39e6add4ed39335399c26b1c87968bf68709330f)) +* **api:** api update ([0c514bf](https://github.com/knocklabs/knock-python/commit/0c514bf839ee8134227869b00cf52fb07deeeae6)) +* **api:** api update ([c3f2f4a](https://github.com/knocklabs/knock-python/commit/c3f2f4a2e93139c627d3745ea4eb7f5142f3153b)) +* **internal/types:** support eagerly validating pydantic iterators ([b128ac3](https://github.com/knocklabs/knock-python/commit/b128ac31c39b01c758eabda4003373c513f59138)) +* support setting headers via env ([e22462b](https://github.com/knocklabs/knock-python/commit/e22462bd64af8c7ddaa8e84c76aca28e411d9734)) + + +### Bug Fixes + +* **client:** add missing f-string prefix in file type error message ([04b3154](https://github.com/knocklabs/knock-python/commit/04b3154865a445887eb791b9c94d2c3586eadf3a)) +* **types:** avoid type-checker errors on params with additional properties ([5f69bb9](https://github.com/knocklabs/knock-python/commit/5f69bb911914f0ca3687ce5fe5ebf4a2d0aae2d6)) +* use correct field name format for multipart file arrays ([4d33037](https://github.com/knocklabs/knock-python/commit/4d33037881f97e2b3e99892b31af059ae22c4bb8)) + + +### Chores + +* **internal:** reformat pyproject.toml ([8e64806](https://github.com/knocklabs/knock-python/commit/8e6480650f67a83f923f45485ff2f0d79e719d0b)) + ## 1.25.0 (2026-04-23) Full Changelog: [v1.24.1...v1.25.0](https://github.com/knocklabs/knock-python/compare/v1.24.1...v1.25.0) diff --git a/pyproject.toml b/pyproject.toml index 347458d..d1819d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "knockapi" -version = "1.25.0" +version = "1.26.0" description = "The official Python library for the knock API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/knockapi/_version.py b/src/knockapi/_version.py index 083c80a..e1ed972 100644 --- a/src/knockapi/_version.py +++ b/src/knockapi/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "knockapi" -__version__ = "1.25.0" # x-release-please-version +__version__ = "1.26.0" # x-release-please-version