From 842699a68811d63aca9ef8d8865266623ff3e42c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 23:47:02 +0000 Subject: [PATCH 1/6] docs(openapi): describe user topic-preference fields explicitly (#172) Add field descriptions to UsersTopicPreference and UsersTopicPreferenceUpdate so the generated API reference documents them fully (topic_id, status, default_status, has_custom_routing, custom_routing, topic_name), including the REQUIRED-is-a-topic-default semantics and the custom_routing channel set. Wrap the PreferenceStatus $ref fields in allOf so the description renders under OpenAPI 3.0. Co-authored-by: Claude Opus 4.8 (1M context) --- .stats.yml | 4 ++-- ...reference_update_or_create_topic_params.py | 14 +++++++++++- src/courier/types/users/topic_preference.py | 22 ++++++++++++++++++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index e2794c72..e5f81212 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 134 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b053468fefe6d757f86f3233ebbc52d80329ed2a6e7a6740fee01e4028a4c3b9.yml -openapi_spec_hash: 416835e693de0fe19945be90a787d3f3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-0630b37ff5ba795185e1e189b0f24d233ecd51681b6ebb7748cad8f0e8c4fcc0.yml +openapi_spec_hash: b9a8c66633e914c9a2f7b3bf275c7349 config_hash: 8d28dbeabe9d4dcc7d5b8c021a4cbbd7 diff --git a/src/courier/types/users/preference_update_or_create_topic_params.py b/src/courier/types/users/preference_update_or_create_topic_params.py index 434de14b..6eb74fdd 100644 --- a/src/courier/types/users/preference_update_or_create_topic_params.py +++ b/src/courier/types/users/preference_update_or_create_topic_params.py @@ -22,8 +22,20 @@ class PreferenceUpdateOrCreateTopicParams(TypedDict, total=False): class Topic(TypedDict, total=False): status: Required[PreferenceStatus] + """The subscription status to set: OPTED_IN or OPTED_OUT. + + REQUIRED is a topic-level default, not a user choice; the API rejects opting a + user out of a REQUIRED topic. + """ custom_routing: Optional[List[ChannelClassification]] - """The Channels a user has chosen to receive notifications through for this topic""" + """The channels to deliver this topic on when has_custom_routing is true. + + One or more of: direct_message, email, push, sms, webhook, inbox. + """ has_custom_routing: Optional[bool] + """ + Set to true to route this topic to the channels in custom_routing instead of the + topic's default routing. + """ diff --git a/src/courier/types/users/topic_preference.py b/src/courier/types/users/topic_preference.py index 55e74c03..b719e0e8 100644 --- a/src/courier/types/users/topic_preference.py +++ b/src/courier/types/users/topic_preference.py @@ -11,14 +11,34 @@ class TopicPreference(BaseModel): default_status: PreferenceStatus + """The topic's default status, returned on reads. + + It applies whenever the user has no override of their own (status equals this + value). + """ status: PreferenceStatus + """The user's subscription status for this topic. + + OPTED_IN or OPTED_OUT reflect the user's own choice; REQUIRED is a topic-level + default set in the preferences editor, not a user choice. + """ topic_id: str + """The unique identifier of the subscription topic this preference applies to.""" topic_name: str + """The display name of the subscription topic, returned on reads.""" custom_routing: Optional[List[ChannelClassification]] = None - """The Channels a user has chosen to receive notifications through for this topic""" + """ + The channels the user has chosen to receive this topic on, present only when + has_custom_routing is true. One or more of: direct_message, email, push, sms, + webhook, inbox. + """ has_custom_routing: Optional[bool] = None + """ + Whether the user has chosen specific delivery channels for this topic (listed in + custom_routing) rather than the topic's default routing. + """ From c90b5d325da4e542a46a089084205ce145d65ef1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 00:05:33 +0000 Subject: [PATCH 2/6] docs(openapi): rewrite operation descriptions for agents and SEO (#174) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrites the `description` on 116 of 134 operations and fills in 14 that had none (GET /tenants, PUT /tenants/{id}, and other tenant/token/message operations). The 18 already-good descriptions are untouched. Why: these descriptions feed the API reference, the generated llms.txt, and the SDK docstrings across all seven languages. Many were either too terse to be useful to a coding agent (e.g. "Returns the specified audience by id") or long enough that Mintlify truncated them mid-sentence in llms.txt (10 sat at 300-301 chars). A prior SEO pass in mintlify-docs (#563) was silently reverted by spec syncs because it edited the generated mirror instead of this source file — this lands the work where it survives. House style, applied uniformly: - Sentence one states what the operation does using concrete nouns — actual response fields, enum values, and id formats, not vague paraphrase. - Sentence two, when present, gives the reason to reach for it or the behavior that surprises people. No status codes, validation rules, em-dashes, or marketing adjectives (those live in the reference body). - 95-160 characters, so they read fully in Google results and don't truncate in llms.txt. Each description was written against the operation's schema (required params, response properties, enums), not from assumption. This caught real errors: the message status enum has 12 values and does not include UNDELIVERABLE; POST /auth/issue-token requires both scope and expires_in (it is not "short-lived"); message content lives at /messages/{id}/output. Please give a domain check to three where behavior was inferred from HTTP semantics rather than stated in the schema: - PUT /users/{user_id}/tenants (users_tenants_addMultiple) — worded to only claim it adds; does it also remove tenants not listed in the body? - PUT /notifications/{id}/{submissionId}/checks (replaceSubmissionChecks) — worded as "the complete set supplied"; are omitted checks dropped? - GET /translations/{domain}/{locale} — says "notification content"; confirm the term. Mechanical: only operation-level `description` lines changed (verified: 0 operationId lines touched, 0 non-description lines added). Multi-line block scalars were collapsed to single quoted lines, which accounts for the deletion count. openapi.yml still parses and all 134 operations are intact. Co-authored-by: Claude --- .stats.yml | 4 +- src/courier/resources/audiences.py | 42 +++-- src/courier/resources/audit_events.py | 18 ++- src/courier/resources/auth.py | 12 +- .../resources/automations/automations.py | 16 +- src/courier/resources/automations/invoke.py | 24 ++- src/courier/resources/brands.py | 48 +++--- src/courier/resources/digests/schedules.py | 16 +- src/courier/resources/inbound.py | 18 ++- src/courier/resources/journeys/journeys.py | 148 +++++++----------- src/courier/resources/journeys/templates.py | 84 +++++----- src/courier/resources/lists/lists.py | 48 ++++-- src/courier/resources/lists/subscriptions.py | 26 +-- src/courier/resources/messages.py | 64 ++++---- src/courier/resources/notifications/checks.py | 24 ++- .../resources/notifications/notifications.py | 124 +++++++-------- src/courier/resources/profiles/lists.py | 38 +++-- src/courier/resources/profiles/profiles.py | 52 +++--- src/courier/resources/providers/catalog.py | 12 +- src/courier/resources/providers/providers.py | 68 ++++---- src/courier/resources/requests.py | 12 +- src/courier/resources/routing_strategies.py | 26 ++- src/courier/resources/send.py | 12 +- .../resources/tenants/preferences/items.py | 12 +- .../resources/tenants/templates/templates.py | 60 +++---- .../resources/tenants/templates/versions.py | 18 +-- src/courier/resources/tenants/tenants.py | 42 +++-- src/courier/resources/translations.py | 18 ++- src/courier/resources/users/preferences.py | 112 ++++--------- src/courier/resources/users/tenants.py | 64 ++++---- src/courier/resources/users/tokens.py | 36 +++-- .../resources/workspace_preferences/topics.py | 50 +++--- .../workspace_preferences.py | 50 +++--- 33 files changed, 670 insertions(+), 728 deletions(-) diff --git a/.stats.yml b/.stats.yml index e5f81212..48e48092 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 134 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-0630b37ff5ba795185e1e189b0f24d233ecd51681b6ebb7748cad8f0e8c4fcc0.yml -openapi_spec_hash: b9a8c66633e914c9a2f7b3bf275c7349 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-5c878919b3df530781ebcd4ab1cda83606304da75c53fe0817d4c725d5bbbe73.yml +openapi_spec_hash: dd37022222543ff064200e65e4b82f59 config_hash: 8d28dbeabe9d4dcc7d5b8c021a4cbbd7 diff --git a/src/courier/resources/audiences.py b/src/courier/resources/audiences.py index 4c930bdb..89bc7835 100644 --- a/src/courier/resources/audiences.py +++ b/src/courier/resources/audiences.py @@ -60,7 +60,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Audience: """ - Returns the specified audience by id. + Returns one audience with its name, description, and the filter and AND or OR + operator that decide which users belong to it. Args: extra_headers: Send extra headers @@ -97,7 +98,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AudienceUpdateResponse: """ - Creates or updates audience. + Creates or replaces an audience from a filter and an AND or OR operator. + Membership recalculates automatically as profiles change. Args: description: A description of the audience @@ -148,8 +150,10 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AudienceListResponse: - """ - Get the audiences associated with the authorization token. + """Returns the audiences in the workspace with paging. + + Audiences are filter-based + groups that recalculate as user profiles change. Args: cursor: A unique identifier that allows for fetching the next set of audiences @@ -186,7 +190,8 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Deletes the specified audience. + Deletes an audience permanently, so update any caller sending to it by audience + id first. Those sends fail once the audience is gone. Args: extra_headers: Send extra headers @@ -220,8 +225,10 @@ def list_members( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AudienceListMembersResponse: - """ - Get list of members of an audience. + """Returns the users currently matching an audience filter, with paging. + + Membership + is recalculated, so results shift as profiles change. Args: cursor: A unique identifier that allows for fetching the next set of members @@ -281,7 +288,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Audience: """ - Returns the specified audience by id. + Returns one audience with its name, description, and the filter and AND or OR + operator that decide which users belong to it. Args: extra_headers: Send extra headers @@ -318,7 +326,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AudienceUpdateResponse: """ - Creates or updates audience. + Creates or replaces an audience from a filter and an AND or OR operator. + Membership recalculates automatically as profiles change. Args: description: A description of the audience @@ -369,8 +378,10 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AudienceListResponse: - """ - Get the audiences associated with the authorization token. + """Returns the audiences in the workspace with paging. + + Audiences are filter-based + groups that recalculate as user profiles change. Args: cursor: A unique identifier that allows for fetching the next set of audiences @@ -407,7 +418,8 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Deletes the specified audience. + Deletes an audience permanently, so update any caller sending to it by audience + id first. Those sends fail once the audience is gone. Args: extra_headers: Send extra headers @@ -441,8 +453,10 @@ async def list_members( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AudienceListMembersResponse: - """ - Get list of members of an audience. + """Returns the users currently matching an audience filter, with paging. + + Membership + is recalculated, so results shift as profiles change. Args: cursor: A unique identifier that allows for fetching the next set of members diff --git a/src/courier/resources/audit_events.py b/src/courier/resources/audit_events.py index 0323e1fc..289597ab 100644 --- a/src/courier/resources/audit_events.py +++ b/src/courier/resources/audit_events.py @@ -56,7 +56,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuditEvent: """ - Fetch a specific audit event by ID. + Returns one audit event by id, including the actor who performed it, the target + they changed, the source, the event type, and a timestamp. Args: extra_headers: Send extra headers @@ -88,8 +89,10 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuditEventListResponse: - """ - Fetch the list of audit events + """Returns the workspace's audit event log with cursor paging. + + Each event records + the actor, target, source, type, and timestamp of a change. Args: cursor: A unique identifier that allows for fetching the next set of audit events. @@ -147,7 +150,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuditEvent: """ - Fetch a specific audit event by ID. + Returns one audit event by id, including the actor who performed it, the target + they changed, the source, the event type, and a timestamp. Args: extra_headers: Send extra headers @@ -179,8 +183,10 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuditEventListResponse: - """ - Fetch the list of audit events + """Returns the workspace's audit event log with cursor paging. + + Each event records + the actor, target, source, type, and timestamp of a change. Args: cursor: A unique identifier that allows for fetching the next set of audit events. diff --git a/src/courier/resources/auth.py b/src/courier/resources/auth.py index b7b00ad1..4ba679c9 100644 --- a/src/courier/resources/auth.py +++ b/src/courier/resources/auth.py @@ -53,8 +53,10 @@ def issue_token( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuthIssueTokenResponse: - """ - Returns a new access token. + """Returns a JWT for authenticating client-side SDKs such as the Inbox. + + You supply + the scope and an expires_in duration, both required. Args: expires_in: @@ -143,8 +145,10 @@ async def issue_token( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuthIssueTokenResponse: - """ - Returns a new access token. + """Returns a JWT for authenticating client-side SDKs such as the Inbox. + + You supply + the scope and an expires_in duration, both required. Args: expires_in: diff --git a/src/courier/resources/automations/automations.py b/src/courier/resources/automations/automations.py index fd29b8a3..00635564 100644 --- a/src/courier/resources/automations/automations.py +++ b/src/courier/resources/automations/automations.py @@ -67,12 +67,12 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AutomationTemplateListResponse: - """Get the list of automations. + """ + Lists the workspace's saved automation templates, each with its id and a cursor + for paging to the next page of results. Args: - cursor: A cursor token for pagination. - - Use the cursor from the previous response to + cursor: A cursor token for pagination. Use the cursor from the previous response to fetch the next page of results. version: The version of templates to retrieve. Accepted values are published (for @@ -141,12 +141,12 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AutomationTemplateListResponse: - """Get the list of automations. + """ + Lists the workspace's saved automation templates, each with its id and a cursor + for paging to the next page of results. Args: - cursor: A cursor token for pagination. - - Use the cursor from the previous response to + cursor: A cursor token for pagination. Use the cursor from the previous response to fetch the next page of results. version: The version of templates to retrieve. Accepted values are published (for diff --git a/src/courier/resources/automations/invoke.py b/src/courier/resources/automations/invoke.py index 7ec143ec..1ecaf91b 100644 --- a/src/courier/resources/automations/invoke.py +++ b/src/courier/resources/automations/invoke.py @@ -59,12 +59,9 @@ def invoke_ad_hoc( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AutomationInvokeResponse: - """Invoke an ad hoc automation run. - - This endpoint accepts a JSON payload with a - series of automation steps. For information about what steps are available, - checkout the ad hoc automation guide - [here](https://www.courier.com/docs/automations/steps/). + """ + Runs a series of automation steps supplied inline, without a saved template, and + returns a runId. Args: extra_headers: Send extra headers @@ -111,7 +108,8 @@ def invoke_by_template( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AutomationInvokeResponse: """ - Invoke an automation run from an automation template. + Starts an automation run from a saved template for one recipient, with optional + data and profile, and returns a runId. Args: extra_headers: Send extra headers @@ -179,12 +177,9 @@ async def invoke_ad_hoc( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AutomationInvokeResponse: - """Invoke an ad hoc automation run. - - This endpoint accepts a JSON payload with a - series of automation steps. For information about what steps are available, - checkout the ad hoc automation guide - [here](https://www.courier.com/docs/automations/steps/). + """ + Runs a series of automation steps supplied inline, without a saved template, and + returns a runId. Args: extra_headers: Send extra headers @@ -231,7 +226,8 @@ async def invoke_by_template( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AutomationInvokeResponse: """ - Invoke an automation run from an automation template. + Starts an automation run from a saved template for one recipient, with optional + data and profile, and returns a runId. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/brands.py b/src/courier/resources/brands.py index 93754218..1f942d76 100644 --- a/src/courier/resources/brands.py +++ b/src/courier/resources/brands.py @@ -60,10 +60,10 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Brand: - """Create a new brand. + """Creates a brand from a name and settings, including primary and secondary + colors. - Requires `name` and `settings` (with at least - `colors.primary` and `colors.secondary`). + Brands supply the logo, colors, and styling that templates render with. Args: extra_headers: Send extra headers @@ -103,7 +103,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Brand: """ - Fetch a specific brand by brand ID. + Returns one brand by id, including its colors, logo and styling settings, + Handlebars snippets, and published version. Args: extra_headers: Send extra headers @@ -139,7 +140,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Brand: """ - Replace an existing brand with the supplied values. + Replaces a brand with the values you supply, so send the complete settings and + snippets rather than only the fields you want changed. Args: name: The name of the brand. @@ -181,8 +183,10 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BrandListResponse: - """ - Get the list of brands. + """Lists the workspace's brands. + + Every entry carries its name, styling settings, + snippets, and published version. Args: cursor: A unique identifier that allows for fetching the next set of brands. @@ -218,8 +222,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a brand by brand ID. + """Deletes a brand by id. + + Reassign any template or tenant that references it before + deleting to keep their styling intact. Args: extra_headers: Send extra headers @@ -276,10 +282,10 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Brand: - """Create a new brand. + """Creates a brand from a name and settings, including primary and secondary + colors. - Requires `name` and `settings` (with at least - `colors.primary` and `colors.secondary`). + Brands supply the logo, colors, and styling that templates render with. Args: extra_headers: Send extra headers @@ -319,7 +325,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Brand: """ - Fetch a specific brand by brand ID. + Returns one brand by id, including its colors, logo and styling settings, + Handlebars snippets, and published version. Args: extra_headers: Send extra headers @@ -355,7 +362,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Brand: """ - Replace an existing brand with the supplied values. + Replaces a brand with the values you supply, so send the complete settings and + snippets rather than only the fields you want changed. Args: name: The name of the brand. @@ -397,8 +405,10 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BrandListResponse: - """ - Get the list of brands. + """Lists the workspace's brands. + + Every entry carries its name, styling settings, + snippets, and published version. Args: cursor: A unique identifier that allows for fetching the next set of brands. @@ -434,8 +444,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a brand by brand ID. + """Deletes a brand by id. + + Reassign any template or tenant that references it before + deleting to keep their styling intact. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/digests/schedules.py b/src/courier/resources/digests/schedules.py index d92f7653..4c488392 100644 --- a/src/courier/resources/digests/schedules.py +++ b/src/courier/resources/digests/schedules.py @@ -54,11 +54,9 @@ def list_instances( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DigestInstanceListResponse: - """List the digest instances for a schedule. - - Each instance represents the events - accumulated for a single user against the schedule, and can be used to monitor - digest accumulation before the digest is released. + """ + Returns the digest instances for a schedule, one per user, with cursor paging. + Use it to see what has accumulated before a digest releases. Args: cursor: A cursor token from a previous response, used to fetch the next page of results. @@ -163,11 +161,9 @@ async def list_instances( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DigestInstanceListResponse: - """List the digest instances for a schedule. - - Each instance represents the events - accumulated for a single user against the schedule, and can be used to monitor - digest accumulation before the digest is released. + """ + Returns the digest instances for a schedule, one per user, with cursor paging. + Use it to see what has accumulated before a digest releases. Args: cursor: A cursor token from a previous response, used to fetch the next page of results. diff --git a/src/courier/resources/inbound.py b/src/courier/resources/inbound.py index 4c1a58c9..9474c374 100644 --- a/src/courier/resources/inbound.py +++ b/src/courier/resources/inbound.py @@ -59,12 +59,13 @@ def track_event( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InboundTrackEventResponse: - """Courier Track Event + """Records an inbound event that can trigger a journey. - Args: - event: A descriptive name of the event. + Requires an event name, a + messageId you generate, a type, and a properties object. - This name will appear as a trigger in the + Args: + event: A descriptive name of the event. This name will appear as a trigger in the Courier Automation Trigger node. message_id: A required unique identifier that will be used to de-duplicate requests. If not @@ -134,12 +135,13 @@ async def track_event( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InboundTrackEventResponse: - """Courier Track Event + """Records an inbound event that can trigger a journey. - Args: - event: A descriptive name of the event. + Requires an event name, a + messageId you generate, a type, and a properties object. - This name will appear as a trigger in the + Args: + event: A descriptive name of the event. This name will appear as a trigger in the Courier Automation Trigger node. message_id: A required unique identifier that will be used to de-duplicate requests. If not diff --git a/src/courier/resources/journeys/journeys.py b/src/courier/resources/journeys/journeys.py index c71614e6..d85cf354 100644 --- a/src/courier/resources/journeys/journeys.py +++ b/src/courier/resources/journeys/journeys.py @@ -85,14 +85,9 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyResponse: - """Create a journey. - - Defaults to `DRAFT` state; pass `state: "PUBLISHED"` to - publish on create. Send nodes are not allowed on `POST`. The standard flow is: - create the journey shell here, add notification templates with - `POST /journeys/{templateId}/templates`, then wire them into the journey with - `PUT /journeys/{templateId}`. Call `POST /journeys/{templateId}/publish` to - publish a draft after the fact. + """ + Creates a journey from a set of nodes, in draft state unless you pass a + published state. Send nodes cannot be included until their templates exist. Args: state: Lifecycle state of a journey. @@ -176,12 +171,12 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneysListResponse: - """Get the list of journeys. + """ + Lists the workspace's journeys, each carrying a name, state, and enabled flag. + Paged by cursor. Args: - cursor: A cursor token for pagination. - - Use the cursor from the previous response to + cursor: A cursor token for pagination. Use the cursor from the previous response to fetch the next page of results. version: The version of journeys to retrieve. Accepted values are published (for @@ -224,10 +219,10 @@ def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Archive a journey. + """Archives a journey so it can no longer be invoked. - Archived journeys cannot be invoked. Existing journey runs - continue to completion. + Runs already in flight + continue to completion, so archiving never strands a user mid-sequence. Args: extra_headers: Send extra headers @@ -261,14 +256,9 @@ def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CancelJourneyResponse: - """Cancel journey runs. - - The request body must include EXACTLY ONE of - `cancelation_token` (cancels every run associated with the token) or `run_id` - (cancels a single tenant-scoped run). Supplying both or neither returns a `400`. - A `run_id` that does not match a run for the tenant returns `404`. Cancelation - is idempotent: a run that has already finished (`PROCESSED`/`ERROR`) or was - already `CANCELED` is left unchanged and its current status is returned. + """ + Cancels in-flight journey runs, either every run sharing a cancelation token or + one run by id. Use it to stop a sequence when the event resolves. Args: extra_headers: Send extra headers @@ -293,14 +283,9 @@ def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CancelJourneyResponse: - """Cancel journey runs. - - The request body must include EXACTLY ONE of - `cancelation_token` (cancels every run associated with the token) or `run_id` - (cancels a single tenant-scoped run). Supplying both or neither returns a `400`. - A `run_id` that does not match a run for the tenant returns `404`. Cancelation - is idempotent: a run that has already finished (`PROCESSED`/`ERROR`) or was - already `CANCELED` is left unchanged and its current status is returned. + """ + Cancels in-flight journey runs, either every run sharing a cancelation token or + one run by id. Use it to stop a sequence when the event resolves. Args: extra_headers: Send extra headers @@ -360,10 +345,10 @@ def invoke( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneysInvokeResponse: - """Invoke a journey by id or alias to start a new run. + """Starts a journey run for one user and returns a runId. - The response includes a - `runId` identifying the run. + Runs execute + asynchronously, so the response arrives before any message is sent. Args: data: Data payload passed to the journey. The expected shape can be predefined using @@ -419,7 +404,8 @@ def list_versions( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyVersionsListResponse: """ - List published versions of a journey, ordered most recent first. + Lists a journey's published versions, most recent first, so you have a version + id to roll back to. Paged by cursor. Args: extra_headers: Send extra headers @@ -452,11 +438,9 @@ def publish( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyResponse: - """Publish the current draft as a new version. - - Body is optional; pass - `{ "version": "vN" }` to roll back to a prior version instead. Returns 404 if - the journey has no draft to publish. + """ + Publishes a journey's current draft as a new version, making it live for new + runs. Pass a version instead to roll back to an earlier one. Args: extra_headers: Send extra headers @@ -493,13 +477,9 @@ def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyResponse: - """Replace the journey draft. - - Updates the working draft only; call - `POST /journeys/{templateId}/publish` to make it live, or pass - `state: "PUBLISHED"` in this request to publish immediately. Send-node - `template` ids must already exist and be scoped to this journey, and node ids - must not be claimed by another journey. + """ + Replaces a journey's working draft, leaving the published version live until you + publish. Reach for this when editing a journey already running. Args: state: Lifecycle state of a journey. @@ -570,14 +550,9 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyResponse: - """Create a journey. - - Defaults to `DRAFT` state; pass `state: "PUBLISHED"` to - publish on create. Send nodes are not allowed on `POST`. The standard flow is: - create the journey shell here, add notification templates with - `POST /journeys/{templateId}/templates`, then wire them into the journey with - `PUT /journeys/{templateId}`. Call `POST /journeys/{templateId}/publish` to - publish a draft after the fact. + """ + Creates a journey from a set of nodes, in draft state unless you pass a + published state. Send nodes cannot be included until their templates exist. Args: state: Lifecycle state of a journey. @@ -661,12 +636,12 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneysListResponse: - """Get the list of journeys. + """ + Lists the workspace's journeys, each carrying a name, state, and enabled flag. + Paged by cursor. Args: - cursor: A cursor token for pagination. - - Use the cursor from the previous response to + cursor: A cursor token for pagination. Use the cursor from the previous response to fetch the next page of results. version: The version of journeys to retrieve. Accepted values are published (for @@ -709,10 +684,10 @@ async def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Archive a journey. + """Archives a journey so it can no longer be invoked. - Archived journeys cannot be invoked. Existing journey runs - continue to completion. + Runs already in flight + continue to completion, so archiving never strands a user mid-sequence. Args: extra_headers: Send extra headers @@ -746,14 +721,9 @@ async def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CancelJourneyResponse: - """Cancel journey runs. - - The request body must include EXACTLY ONE of - `cancelation_token` (cancels every run associated with the token) or `run_id` - (cancels a single tenant-scoped run). Supplying both or neither returns a `400`. - A `run_id` that does not match a run for the tenant returns `404`. Cancelation - is idempotent: a run that has already finished (`PROCESSED`/`ERROR`) or was - already `CANCELED` is left unchanged and its current status is returned. + """ + Cancels in-flight journey runs, either every run sharing a cancelation token or + one run by id. Use it to stop a sequence when the event resolves. Args: extra_headers: Send extra headers @@ -778,14 +748,9 @@ async def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CancelJourneyResponse: - """Cancel journey runs. - - The request body must include EXACTLY ONE of - `cancelation_token` (cancels every run associated with the token) or `run_id` - (cancels a single tenant-scoped run). Supplying both or neither returns a `400`. - A `run_id` that does not match a run for the tenant returns `404`. Cancelation - is idempotent: a run that has already finished (`PROCESSED`/`ERROR`) or was - already `CANCELED` is left unchanged and its current status is returned. + """ + Cancels in-flight journey runs, either every run sharing a cancelation token or + one run by id. Use it to stop a sequence when the event resolves. Args: extra_headers: Send extra headers @@ -845,10 +810,10 @@ async def invoke( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneysInvokeResponse: - """Invoke a journey by id or alias to start a new run. + """Starts a journey run for one user and returns a runId. - The response includes a - `runId` identifying the run. + Runs execute + asynchronously, so the response arrives before any message is sent. Args: data: Data payload passed to the journey. The expected shape can be predefined using @@ -904,7 +869,8 @@ async def list_versions( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyVersionsListResponse: """ - List published versions of a journey, ordered most recent first. + Lists a journey's published versions, most recent first, so you have a version + id to roll back to. Paged by cursor. Args: extra_headers: Send extra headers @@ -937,11 +903,9 @@ async def publish( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyResponse: - """Publish the current draft as a new version. - - Body is optional; pass - `{ "version": "vN" }` to roll back to a prior version instead. Returns 404 if - the journey has no draft to publish. + """ + Publishes a journey's current draft as a new version, making it live for new + runs. Pass a version instead to roll back to an earlier one. Args: extra_headers: Send extra headers @@ -978,13 +942,9 @@ async def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyResponse: - """Replace the journey draft. - - Updates the working draft only; call - `POST /journeys/{templateId}/publish` to make it live, or pass - `state: "PUBLISHED"` in this request to publish immediately. Send-node - `template` ids must already exist and be scoped to this journey, and node ids - must not be claimed by another journey. + """ + Replaces a journey's working draft, leaving the published version live until you + publish. Reach for this when editing a journey already running. Args: state: Lifecycle state of a journey. diff --git a/src/courier/resources/journeys/templates.py b/src/courier/resources/journeys/templates.py index cb716dca..bb5ea256 100644 --- a/src/courier/resources/journeys/templates.py +++ b/src/courier/resources/journeys/templates.py @@ -117,11 +117,9 @@ def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyTemplateGetResponse: - """Fetch a journey-scoped notification template by id. - - Pass `?version=draft` - (default `published`) to retrieve the working draft, or `?version=vN` for a - historical version. + """ + Returns a journey's own notification template with its name, brand, subscription + topic, and content. Defaults to the published version. Args: extra_headers: Send extra headers @@ -211,10 +209,10 @@ def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Archive the journey-scoped notification template. + """Archives one journey's notification template, preventing further sends. - Archived templates cannot be - sent. + Detach + any send node referencing it beforehand. Args: extra_headers: Send extra headers @@ -255,8 +253,8 @@ def list_versions( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateVersionListResponse: """ - List published versions of the journey-scoped notification template, ordered - most recent first. + Lists the published versions of a template that belongs to a journey, most + recent first. Paged by cursor. Args: extra_headers: Send extra headers @@ -296,10 +294,10 @@ def publish( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Publish the current draft of the journey-scoped notification template as a new - version. Optionally roll back to a prior version by passing - `{ "version": "vN" }`. + """Publishes a journey-scoped template's draft as a new version. + + Pass a version + instead to roll back the template to an earlier publish. Args: extra_headers: Send extra headers @@ -455,8 +453,10 @@ def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyTemplateGetResponse: - """ - Replace the journey-scoped notification template draft. + """Replaces the draft content of one journey's notification template. + + Publish it + before send nodes referencing it render the change. Args: extra_headers: Send extra headers @@ -503,13 +503,9 @@ def retrieve_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentGetResponse: - """Retrieve the elemental content of a journey-scoped notification template. - - The - response contains the versioned elements along with their content checksums, - which can be used to detect changes between versions. Pass `?version=draft` - (default `published`) to retrieve the working draft, or `?version=vN` for a - historical version. + """ + Returns the Elemental elements and version of a journey-scoped template's + content. Compare versions to see what changed between publishes. Args: version: Accepts `draft`, `published`, or a version string (e.g., `v001`). Defaults to @@ -626,11 +622,9 @@ async def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyTemplateGetResponse: - """Fetch a journey-scoped notification template by id. - - Pass `?version=draft` - (default `published`) to retrieve the working draft, or `?version=vN` for a - historical version. + """ + Returns a journey's own notification template with its name, brand, subscription + topic, and content. Defaults to the published version. Args: extra_headers: Send extra headers @@ -720,10 +714,10 @@ async def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Archive the journey-scoped notification template. + """Archives one journey's notification template, preventing further sends. - Archived templates cannot be - sent. + Detach + any send node referencing it beforehand. Args: extra_headers: Send extra headers @@ -764,8 +758,8 @@ async def list_versions( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateVersionListResponse: """ - List published versions of the journey-scoped notification template, ordered - most recent first. + Lists the published versions of a template that belongs to a journey, most + recent first. Paged by cursor. Args: extra_headers: Send extra headers @@ -805,10 +799,10 @@ async def publish( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Publish the current draft of the journey-scoped notification template as a new - version. Optionally roll back to a prior version by passing - `{ "version": "vN" }`. + """Publishes a journey-scoped template's draft as a new version. + + Pass a version + instead to roll back the template to an earlier publish. Args: extra_headers: Send extra headers @@ -964,8 +958,10 @@ async def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JourneyTemplateGetResponse: - """ - Replace the journey-scoped notification template draft. + """Replaces the draft content of one journey's notification template. + + Publish it + before send nodes referencing it render the change. Args: extra_headers: Send extra headers @@ -1012,13 +1008,9 @@ async def retrieve_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentGetResponse: - """Retrieve the elemental content of a journey-scoped notification template. - - The - response contains the versioned elements along with their content checksums, - which can be used to detect changes between versions. Pass `?version=draft` - (default `published`) to retrieve the working draft, or `?version=vN` for a - historical version. + """ + Returns the Elemental elements and version of a journey-scoped template's + content. Compare versions to see what changed between publishes. Args: version: Accepts `draft`, `published`, or a version string (e.g., `v001`). Defaults to diff --git a/src/courier/resources/lists/lists.py b/src/courier/resources/lists/lists.py index ae71b29b..37063764 100644 --- a/src/courier/resources/lists/lists.py +++ b/src/courier/resources/lists/lists.py @@ -68,8 +68,10 @@ def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionList: - """ - Returns a list based on the list ID provided. + """Returns one list by id with its name and created and updated timestamps. + + Fetch + its subscribers separately with the subscriptions endpoint. Args: extra_headers: Send extra headers @@ -103,8 +105,10 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Create or replace an existing list with the supplied values. + """Creates or replaces a list from a name and preferences. + + Subscribers are managed + through the separate subscriptions endpoints. Args: extra_headers: Send extra headers @@ -146,7 +150,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListListResponse: """ - Returns all of the lists, with the ability to filter based on a pattern. + Returns the workspace's lists, filterable by a pattern to fetch a subset such as + every regional list. Paged by cursor. Args: cursor: A unique identifier that allows for fetching the next page of lists. @@ -194,8 +199,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a list by list ID. + """Deletes a list, halting sends that target it. + + A previously deleted list can be + brought back with the companion restore endpoint. Args: extra_headers: Send extra headers @@ -229,7 +236,8 @@ def restore( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Restore a previously deleted list. + Restores a previously deleted list along with its subscribers, so a list removed + by mistake can be brought back rather than rebuilt. Args: extra_headers: Send extra headers @@ -287,8 +295,10 @@ async def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionList: - """ - Returns a list based on the list ID provided. + """Returns one list by id with its name and created and updated timestamps. + + Fetch + its subscribers separately with the subscriptions endpoint. Args: extra_headers: Send extra headers @@ -322,8 +332,10 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Create or replace an existing list with the supplied values. + """Creates or replaces a list from a name and preferences. + + Subscribers are managed + through the separate subscriptions endpoints. Args: extra_headers: Send extra headers @@ -365,7 +377,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListListResponse: """ - Returns all of the lists, with the ability to filter based on a pattern. + Returns the workspace's lists, filterable by a pattern to fetch a subset such as + every regional list. Paged by cursor. Args: cursor: A unique identifier that allows for fetching the next page of lists. @@ -413,8 +426,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a list by list ID. + """Deletes a list, halting sends that target it. + + A previously deleted list can be + brought back with the companion restore endpoint. Args: extra_headers: Send extra headers @@ -448,7 +463,8 @@ async def restore( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Restore a previously deleted list. + Restores a previously deleted list along with its subscribers, so a list removed + by mistake can be brought back rather than rebuilt. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/lists/subscriptions.py b/src/courier/resources/lists/subscriptions.py index 74034f4b..9d3cd1f0 100644 --- a/src/courier/resources/lists/subscriptions.py +++ b/src/courier/resources/lists/subscriptions.py @@ -63,7 +63,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionListResponse: """ - Get the list's subscriptions. + Returns the users subscribed to a list with paging, each with the preferences + recorded for that subscription. Args: cursor: A unique identifier that allows for fetching the next set of list subscriptions @@ -179,8 +180,8 @@ def subscribe_user( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Subscribe a user to an existing list (note: if the List does not exist, it will - be automatically created). + Subscribes one user to a list, creating the list if it does not yet exist. + Optional preferences apply to this subscription only. Args: extra_headers: Send extra headers @@ -219,8 +220,10 @@ def unsubscribe_user( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a subscription to a list by list ID and user ID. + """Removes one user's subscription to a list, addressed by list id and user id. + + The + user's profile and other subscriptions are separate resources. Args: extra_headers: Send extra headers @@ -278,7 +281,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionListResponse: """ - Get the list's subscriptions. + Returns the users subscribed to a list with paging, each with the preferences + recorded for that subscription. Args: cursor: A unique identifier that allows for fetching the next set of list subscriptions @@ -396,8 +400,8 @@ async def subscribe_user( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Subscribe a user to an existing list (note: if the List does not exist, it will - be automatically created). + Subscribes one user to a list, creating the list if it does not yet exist. + Optional preferences apply to this subscription only. Args: extra_headers: Send extra headers @@ -436,8 +440,10 @@ async def unsubscribe_user( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a subscription to a list by list ID and user ID. + """Removes one user's subscription to a list, addressed by list id and user id. + + The + user's profile and other subscriptions are separate resources. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/messages.py b/src/courier/resources/messages.py index c8c87ce9..10dbf259 100644 --- a/src/courier/resources/messages.py +++ b/src/courier/resources/messages.py @@ -60,7 +60,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageRetrieveResponse: """ - Fetch the status of a message you've previously sent. + Returns a sent message's status, recipient, event, and per-provider delivery + detail, with timestamps for enqueued, sent, delivered, opened, and clicked. Args: extra_headers: Send extra headers @@ -106,7 +107,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageListResponse: """ - Fetch the statuses of messages you've previously sent. + Returns previously sent messages, most recent first, each carrying its status, + recipient, channel, and provider. Paged by cursor. Args: archived: A boolean value that indicates whether archived messages should be included in @@ -195,13 +197,9 @@ def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageDetails: - """Cancel a message that is currently in the process of being delivered. - - A - well-formatted API call to the cancel message API will return either `200` - status code for a successful cancellation or `409` status code for an - unsuccessful cancellation. Both cases will include the actual message record in - the response body (see details below). + """ + Cancels a message that is still in the delivery pipeline and returns the message + record with its resulting canceled or failed status. Args: extra_headers: Send extra headers @@ -234,7 +232,8 @@ def content( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageContentResponse: """ - Get message content + Returns the rendered content Courier delivered for a message, broken out per + channel, to confirm what the recipient received. Args: extra_headers: Send extra headers @@ -268,7 +267,8 @@ def history( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageHistoryResponse: """ - Fetch the array of events of a message you've previously sent. + Returns the ordered event history for a sent message, one entry per status + transition with its timestamp. Args: type: A supported Message History type that will filter the events returned. @@ -306,13 +306,9 @@ def resend( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageResendResponse: - """Resend a previously sent message. - - The original send request is loaded from - storage and a brand-new send is enqueued for the same recipient and content, - producing a **new** `messageId` — the original message is not modified. - Throttled by a per-message rate limit; a repeat inside the limit window returns - `429 Too Many Requests`. + """ + Resends a previously sent message to the same recipient and content, returning a + new messageId. The original send request is not modified. Args: extra_headers: Send extra headers @@ -366,7 +362,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageRetrieveResponse: """ - Fetch the status of a message you've previously sent. + Returns a sent message's status, recipient, event, and per-provider delivery + detail, with timestamps for enqueued, sent, delivered, opened, and clicked. Args: extra_headers: Send extra headers @@ -412,7 +409,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageListResponse: """ - Fetch the statuses of messages you've previously sent. + Returns previously sent messages, most recent first, each carrying its status, + recipient, channel, and provider. Paged by cursor. Args: archived: A boolean value that indicates whether archived messages should be included in @@ -501,13 +499,9 @@ async def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageDetails: - """Cancel a message that is currently in the process of being delivered. - - A - well-formatted API call to the cancel message API will return either `200` - status code for a successful cancellation or `409` status code for an - unsuccessful cancellation. Both cases will include the actual message record in - the response body (see details below). + """ + Cancels a message that is still in the delivery pipeline and returns the message + record with its resulting canceled or failed status. Args: extra_headers: Send extra headers @@ -540,7 +534,8 @@ async def content( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageContentResponse: """ - Get message content + Returns the rendered content Courier delivered for a message, broken out per + channel, to confirm what the recipient received. Args: extra_headers: Send extra headers @@ -574,7 +569,8 @@ async def history( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageHistoryResponse: """ - Fetch the array of events of a message you've previously sent. + Returns the ordered event history for a sent message, one entry per status + transition with its timestamp. Args: type: A supported Message History type that will filter the events returned. @@ -612,13 +608,9 @@ async def resend( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageResendResponse: - """Resend a previously sent message. - - The original send request is loaded from - storage and a brand-new send is enqueued for the same recipient and content, - producing a **new** `messageId` — the original message is not modified. - Throttled by a per-message rate limit; a repeat inside the limit window returns - `429 Too Many Requests`. + """ + Resends a previously sent message to the same recipient and content, returning a + new messageId. The original send request is not modified. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/notifications/checks.py b/src/courier/resources/notifications/checks.py index b619de48..4da0afe6 100644 --- a/src/courier/resources/notifications/checks.py +++ b/src/courier/resources/notifications/checks.py @@ -59,7 +59,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CheckUpdateResponse: """ - Replace the submission checks for a notification template. + Replaces the approval checks on a template submission with the complete set + supplied in the request body. Args: extra_headers: Send extra headers @@ -96,7 +97,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CheckListResponse: """ - Retrieve the submission checks for a notification template. + Returns the approval checks recorded for a template submission, each with its + pass or fail result. Args: extra_headers: Send extra headers @@ -131,8 +133,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Cancel a submission for a notification template. + """Cancels a pending template submission, withdrawing it from the approval + workflow. + + The template stays in draft and can be resubmitted later. Args: extra_headers: Send extra headers @@ -191,7 +195,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CheckUpdateResponse: """ - Replace the submission checks for a notification template. + Replaces the approval checks on a template submission with the complete set + supplied in the request body. Args: extra_headers: Send extra headers @@ -228,7 +233,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CheckListResponse: """ - Retrieve the submission checks for a notification template. + Returns the approval checks recorded for a template submission, each with its + pass or fail result. Args: extra_headers: Send extra headers @@ -263,8 +269,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Cancel a submission for a notification template. + """Cancels a pending template submission, withdrawing it from the approval + workflow. + + The template stays in draft and can be resubmitted later. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/notifications/notifications.py b/src/courier/resources/notifications/notifications.py index a479a76d..c6a6c1d5 100644 --- a/src/courier/resources/notifications/notifications.py +++ b/src/courier/resources/notifications/notifications.py @@ -177,8 +177,10 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationListResponse: - """ - List notification templates in your workspace. + """Lists the workspace's notification templates. + + Each carries a name, tags, brand, + routing, and its draft or published state. Args: cursor: Opaque pagination cursor from a previous response. Omit for the first page. @@ -225,8 +227,10 @@ def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Archive a notification template. + """Archives a notification template, preventing new sends from referencing it. + + The + template stays retrievable for its version history. Args: extra_headers: Send extra headers @@ -259,14 +263,10 @@ def duplicate( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateResponse: - """Duplicate a notification template. - - Creates a standalone copy within the same - workspace and environment, with " COPY" appended to the title. The copy clones - the source draft's tags, brand, subscription topic, routing strategy, channels, - and content, and is always created as a standalone template (it is not linked to - any journey or broadcast, even if the source was). Templates that are scoped to - a journey or a broadcast cannot be duplicated through this endpoint. + """ + Copies a notification template within the same workspace and environment, + appending " COPY" to the title. The copy is standalone and independently + editable. Args: extra_headers: Send extra headers @@ -301,7 +301,8 @@ def list_versions( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateVersionListResponse: """ - List versions of a notification template. + Returns a notification template's published versions, most recent first, for + comparison or rollback. Paged. Args: cursor: Opaque pagination cursor from a previous response. Omit for the first page. @@ -389,11 +390,10 @@ def put_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentMutationResponse: - """Replace the elemental content of a notification template. + """Replaces all Elemental content in a template, overwriting every existing + element. - Overwrites all - elements in the template with the provided content. Only supported for V2 - (elemental) templates. + Supported for V2 templates only, not V1 blocks and channels. Args: content: Elemental content payload. The server defaults `version` when omitted. @@ -444,10 +444,9 @@ def put_element( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentMutationResponse: - """Update a single element within a notification template. - - Only supported for V2 - (elemental) templates. + """ + Replaces one Elemental element in a template, addressed by its element id. + Supported for V2 templates only, not V1 blocks and channels. Args: type: Element type (text, meta, action, image, etc.). @@ -500,11 +499,10 @@ def put_locale( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentMutationResponse: - """Set locale-specific content overrides for a notification template. + """Sets locale-specific content overrides for a template. - Each element - override must reference an existing element by ID. Only supported for V2 - (elemental) templates. + Each override must + reference an element that already exists in the default content. Args: elements: Elements with locale-specific content overrides. @@ -551,9 +549,9 @@ def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateResponse: - """Replace a notification template. - - All fields are required. + """ + Replaces a notification template in full, so send every field rather than only + the ones you want changed. Publish separately to make it live. Args: notification: Core template fields used in POST and PUT request bodies (nested under a @@ -599,12 +597,10 @@ def retrieve_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationRetrieveContentResponse: - """Retrieve the content of a notification template. + """Returns a template's content and checksum. - The response shape depends on - whether the template uses V1 (blocks/channels) or V2 (elemental) content. Use - the `version` query parameter to select draft, published, or a specific - historical version. + V2 templates return Elemental + elements, while V1 templates return blocks and channels instead. Args: version: Accepts `draft`, `published`, or a version string (e.g., `v001`). Defaults to @@ -769,8 +765,10 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationListResponse: - """ - List notification templates in your workspace. + """Lists the workspace's notification templates. + + Each carries a name, tags, brand, + routing, and its draft or published state. Args: cursor: Opaque pagination cursor from a previous response. Omit for the first page. @@ -817,8 +815,10 @@ async def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Archive a notification template. + """Archives a notification template, preventing new sends from referencing it. + + The + template stays retrievable for its version history. Args: extra_headers: Send extra headers @@ -851,14 +851,10 @@ async def duplicate( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateResponse: - """Duplicate a notification template. - - Creates a standalone copy within the same - workspace and environment, with " COPY" appended to the title. The copy clones - the source draft's tags, brand, subscription topic, routing strategy, channels, - and content, and is always created as a standalone template (it is not linked to - any journey or broadcast, even if the source was). Templates that are scoped to - a journey or a broadcast cannot be duplicated through this endpoint. + """ + Copies a notification template within the same workspace and environment, + appending " COPY" to the title. The copy is standalone and independently + editable. Args: extra_headers: Send extra headers @@ -893,7 +889,8 @@ async def list_versions( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateVersionListResponse: """ - List versions of a notification template. + Returns a notification template's published versions, most recent first, for + comparison or rollback. Paged. Args: cursor: Opaque pagination cursor from a previous response. Omit for the first page. @@ -983,11 +980,10 @@ async def put_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentMutationResponse: - """Replace the elemental content of a notification template. + """Replaces all Elemental content in a template, overwriting every existing + element. - Overwrites all - elements in the template with the provided content. Only supported for V2 - (elemental) templates. + Supported for V2 templates only, not V1 blocks and channels. Args: content: Elemental content payload. The server defaults `version` when omitted. @@ -1038,10 +1034,9 @@ async def put_element( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentMutationResponse: - """Update a single element within a notification template. - - Only supported for V2 - (elemental) templates. + """ + Replaces one Elemental element in a template, addressed by its element id. + Supported for V2 templates only, not V1 blocks and channels. Args: type: Element type (text, meta, action, image, etc.). @@ -1094,11 +1089,10 @@ async def put_locale( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationContentMutationResponse: - """Set locale-specific content overrides for a notification template. + """Sets locale-specific content overrides for a template. - Each element - override must reference an existing element by ID. Only supported for V2 - (elemental) templates. + Each override must + reference an element that already exists in the default content. Args: elements: Elements with locale-specific content overrides. @@ -1145,9 +1139,9 @@ async def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationTemplateResponse: - """Replace a notification template. - - All fields are required. + """ + Replaces a notification template in full, so send every field rather than only + the ones you want changed. Publish separately to make it live. Args: notification: Core template fields used in POST and PUT request bodies (nested under a @@ -1193,12 +1187,10 @@ async def retrieve_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NotificationRetrieveContentResponse: - """Retrieve the content of a notification template. + """Returns a template's content and checksum. - The response shape depends on - whether the template uses V1 (blocks/channels) or V2 (elemental) content. Use - the `version` query parameter to select draft, published, or a specific - historical version. + V2 templates return Elemental + elements, while V1 templates return blocks and channels instead. Args: version: Accepts `draft`, `published`, or a version string (e.g., `v001`). Defaults to diff --git a/src/courier/resources/profiles/lists.py b/src/courier/resources/profiles/lists.py index 4f41eb9d..8cab7b03 100644 --- a/src/courier/resources/profiles/lists.py +++ b/src/courier/resources/profiles/lists.py @@ -58,8 +58,10 @@ def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListRetrieveResponse: - """ - Returns the subscribed lists for a specified user. + """Returns the lists a user is subscribed to, with paging. + + Use it to check what a + recipient will receive before sending to a list. Args: cursor: A unique identifier that allows for fetching the next set of message statuses. @@ -97,8 +99,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListDeleteResponse: - """ - Removes all list subscriptions for given user. + """Removes every list subscription for a user at once. + + Their profile and + preferences are untouched, so this only affects list-targeted sends. Args: extra_headers: Send extra headers @@ -131,10 +135,9 @@ def subscribe( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListSubscribeResponse: - """Subscribes the given user to one or more lists. - - If the list does not exist, it - will be created. + """ + Subscribes a user to one or more lists, creating any list that does not yet + exist. Optional preferences apply to each subscription. Args: extra_headers: Send extra headers @@ -189,8 +192,10 @@ async def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListRetrieveResponse: - """ - Returns the subscribed lists for a specified user. + """Returns the lists a user is subscribed to, with paging. + + Use it to check what a + recipient will receive before sending to a list. Args: cursor: A unique identifier that allows for fetching the next set of message statuses. @@ -228,8 +233,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListDeleteResponse: - """ - Removes all list subscriptions for given user. + """Removes every list subscription for a user at once. + + Their profile and + preferences are untouched, so this only affects list-targeted sends. Args: extra_headers: Send extra headers @@ -262,10 +269,9 @@ async def subscribe( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ListSubscribeResponse: - """Subscribes the given user to one or more lists. - - If the list does not exist, it - will be created. + """ + Subscribes a user to one or more lists, creating any list that does not yet + exist. Optional preferences apply to each subscription. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/profiles/profiles.py b/src/courier/resources/profiles/profiles.py index d359fbc1..51fea6c3 100644 --- a/src/courier/resources/profiles/profiles.py +++ b/src/courier/resources/profiles/profiles.py @@ -70,8 +70,8 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProfileCreateResponse: """ - Merge the supplied values with an existing profile or create a new profile if - one doesn't already exist. + Merges the supplied values into a user's profile, creating it if absent and + leaving any key you omit untouched. Prefer this for everyday writes. Args: extra_headers: Send extra headers @@ -105,7 +105,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProfileRetrieveResponse: """ - Returns the specified user profile. + Returns a user's stored profile and preferences, including the email address, + phone number, and push tokens Courier can reach them on. Args: extra_headers: Send extra headers @@ -139,7 +140,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Update a profile + Applies a JSON Patch to a user profile, adding, removing, or replacing + individual fields without sending the whole object. Args: patch: List of patch operations to apply to the profile. @@ -175,8 +177,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Deletes the specified user profile. + """Deletes a user's profile and stored contact details. + + List subscriptions and + preferences are separate resources, so remove those too if required. Args: extra_headers: Send extra headers @@ -210,12 +214,10 @@ def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProfileReplaceResponse: - """ - When using `PUT`, be sure to include all the key-value pairs required by the - recipient's profile. Any key-value pairs that exist in the profile but fail to - be included in the `PUT` request will be removed from the profile. Remember, a - `PUT` update is a full replacement of the data. For partial updates, use the - [Patch](https://www.courier.com/docs/reference/profiles/patch/) request. + """Overwrites a user profile in full, removing any key absent from the request + body. + + Use the patch endpoint when changing a single field. Args: extra_headers: Send extra headers @@ -275,8 +277,8 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProfileCreateResponse: """ - Merge the supplied values with an existing profile or create a new profile if - one doesn't already exist. + Merges the supplied values into a user's profile, creating it if absent and + leaving any key you omit untouched. Prefer this for everyday writes. Args: extra_headers: Send extra headers @@ -310,7 +312,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProfileRetrieveResponse: """ - Returns the specified user profile. + Returns a user's stored profile and preferences, including the email address, + phone number, and push tokens Courier can reach them on. Args: extra_headers: Send extra headers @@ -344,7 +347,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Update a profile + Applies a JSON Patch to a user profile, adding, removing, or replacing + individual fields without sending the whole object. Args: patch: List of patch operations to apply to the profile. @@ -380,8 +384,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Deletes the specified user profile. + """Deletes a user's profile and stored contact details. + + List subscriptions and + preferences are separate resources, so remove those too if required. Args: extra_headers: Send extra headers @@ -415,12 +421,10 @@ async def replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProfileReplaceResponse: - """ - When using `PUT`, be sure to include all the key-value pairs required by the - recipient's profile. Any key-value pairs that exist in the profile but fail to - be included in the `PUT` request will be removed from the profile. Remember, a - `PUT` update is a full replacement of the data. For partial updates, use the - [Patch](https://www.courier.com/docs/reference/profiles/patch/) request. + """Overwrites a user profile in full, removing any key absent from the request + body. + + Use the patch endpoint when changing a single field. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/providers/catalog.py b/src/courier/resources/providers/catalog.py index d89a86c0..3587b36c 100644 --- a/src/courier/resources/providers/catalog.py +++ b/src/courier/resources/providers/catalog.py @@ -55,10 +55,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CatalogListResponse: """ - Returns the catalog of available provider types with their display names, - descriptions, and configuration schema fields (snake_case, with `type` and - `required`). Providers with no configurable schema return only `provider`, - `name`, and `description`. + Returns the provider types Courier supports, each with a display name, + description, and the configuration fields it requires. Args: channel: Exact match (case-insensitive) against the provider channel taxonomy (e.g. @@ -130,10 +128,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CatalogListResponse: """ - Returns the catalog of available provider types with their display names, - descriptions, and configuration schema fields (snake_case, with `type` and - `required`). Providers with no configurable schema return only `provider`, - `name`, and `description`. + Returns the provider types Courier supports, each with a display name, + description, and the configuration fields it requires. Args: channel: Exact match (case-insensitive) against the provider channel taxonomy (e.g. diff --git a/src/courier/resources/providers/providers.py b/src/courier/resources/providers/providers.py index 57bc9da5..b2b6a481 100644 --- a/src/courier/resources/providers/providers.py +++ b/src/courier/resources/providers/providers.py @@ -70,10 +70,9 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Provider: - """Create a new provider configuration. - - The `provider` field must be a known - Courier provider key (see catalog). + """ + Configures a provider integration from a Courier provider key and its settings. + Check the catalog endpoint for the schema each provider expects. Args: provider: The provider key identifying the type (e.g. "sendgrid", "twilio"). Must be a @@ -124,7 +123,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Provider: """ - Fetch a single provider configuration by ID. + Returns one configured provider by id, including its channel, provider key, + alias, title, and current settings. Args: extra_headers: Send extra headers @@ -160,13 +160,9 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Provider: - """Replace an existing provider configuration. - - The `provider` key is required and - determines which provider-specific settings schema is applied. All other fields - are optional — omitted fields are cleared from the stored configuration (this is - a full replacement, not a partial merge). Changing the provider type for an - existing configuration is not supported. + """ + Replaces a provider's configuration in full, clearing any field you omit rather + than merging it. Send the complete settings object. Args: provider: The provider key identifying the type. Required on every request because it @@ -218,10 +214,9 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProviderListResponse: - """List configured provider integrations for the current workspace. - - Supports - cursor-based pagination. + """ + Lists the provider integrations configured in the workspace, one entry per + channel and provider key with its alias and settings. Args: cursor: Opaque cursor for fetching the next page. @@ -257,10 +252,9 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Delete a provider configuration. - - Returns 409 if the provider is still referenced - by routing or notifications. + """ + Deletes a provider configuration, which fails while routing strategies or + templates still reference it. Update those references first. Args: extra_headers: Send extra headers @@ -321,10 +315,9 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Provider: - """Create a new provider configuration. - - The `provider` field must be a known - Courier provider key (see catalog). + """ + Configures a provider integration from a Courier provider key and its settings. + Check the catalog endpoint for the schema each provider expects. Args: provider: The provider key identifying the type (e.g. "sendgrid", "twilio"). Must be a @@ -375,7 +368,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Provider: """ - Fetch a single provider configuration by ID. + Returns one configured provider by id, including its channel, provider key, + alias, title, and current settings. Args: extra_headers: Send extra headers @@ -411,13 +405,9 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Provider: - """Replace an existing provider configuration. - - The `provider` key is required and - determines which provider-specific settings schema is applied. All other fields - are optional — omitted fields are cleared from the stored configuration (this is - a full replacement, not a partial merge). Changing the provider type for an - existing configuration is not supported. + """ + Replaces a provider's configuration in full, clearing any field you omit rather + than merging it. Send the complete settings object. Args: provider: The provider key identifying the type. Required on every request because it @@ -469,10 +459,9 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProviderListResponse: - """List configured provider integrations for the current workspace. - - Supports - cursor-based pagination. + """ + Lists the provider integrations configured in the workspace, one entry per + channel and provider key with its alias and settings. Args: cursor: Opaque cursor for fetching the next page. @@ -508,10 +497,9 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Delete a provider configuration. - - Returns 409 if the provider is still referenced - by routing or notifications. + """ + Deletes a provider configuration, which fails while routing strategies or + templates still reference it. Update those references first. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/requests.py b/src/courier/resources/requests.py index c2ddf98b..4b94972b 100644 --- a/src/courier/resources/requests.py +++ b/src/courier/resources/requests.py @@ -50,8 +50,10 @@ def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Archive message + """Archives a send request by its request id. + + Use it to remove test sends or + superseded requests from the message list without deleting them. Args: extra_headers: Send extra headers @@ -105,8 +107,10 @@ async def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Archive message + """Archives a send request by its request id. + + Use it to remove test sends or + superseded requests from the message list without deleting them. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/routing_strategies.py b/src/courier/resources/routing_strategies.py index 99910979..bdcfbf01 100644 --- a/src/courier/resources/routing_strategies.py +++ b/src/courier/resources/routing_strategies.py @@ -125,10 +125,9 @@ def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RoutingStrategyGetResponse: - """Retrieve a routing strategy by ID. - - Returns the full entity including routing - content and metadata. + """ + Returns one routing strategy by id with its name, tags, channels, and the + routing rules that decide provider order and fallback. Args: extra_headers: Send extra headers @@ -247,10 +246,10 @@ def list_notifications( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AssociatedNotificationListResponse: - """List notification templates associated with a routing strategy. + """Returns the notification templates using a routing strategy, with paging. - Includes - template metadata only, not full content. + Check + this before changing a strategy that templates depend on. Args: cursor: Opaque pagination cursor from a previous response. Omit for the first page. @@ -442,10 +441,9 @@ async def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RoutingStrategyGetResponse: - """Retrieve a routing strategy by ID. - - Returns the full entity including routing - content and metadata. + """ + Returns one routing strategy by id with its name, tags, channels, and the + routing rules that decide provider order and fallback. Args: extra_headers: Send extra headers @@ -564,10 +562,10 @@ async def list_notifications( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AssociatedNotificationListResponse: - """List notification templates associated with a routing strategy. + """Returns the notification templates using a routing strategy, with paging. - Includes - template metadata only, not full content. + Check + this before changing a strategy that templates depend on. Args: cursor: Opaque pagination cursor from a previous response. Omit for the first page. diff --git a/src/courier/resources/send.py b/src/courier/resources/send.py index 21c8cbe8..212a1dc8 100644 --- a/src/courier/resources/send.py +++ b/src/courier/resources/send.py @@ -52,8 +52,10 @@ def message( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SendMessageResponse: - """ - Send a message to one or more recipients. + """Sends a message to one or more recipients and returns a requestId. + + Courier + routes it to email, SMS, push, chat, or in-app based on your rules. Args: message: The message property has the following primary top-level properties. They define @@ -108,8 +110,10 @@ async def message( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SendMessageResponse: - """ - Send a message to one or more recipients. + """Sends a message to one or more recipients and returns a requestId. + + Courier + routes it to email, SMS, push, chat, or in-app based on your rules. Args: message: The message property has the following primary top-level properties. They define diff --git a/src/courier/resources/tenants/preferences/items.py b/src/courier/resources/tenants/preferences/items.py index 91d35dc4..4e0f397d 100644 --- a/src/courier/resources/tenants/preferences/items.py +++ b/src/courier/resources/tenants/preferences/items.py @@ -60,7 +60,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Create or Replace Default Preferences For Topic + Sets a tenant's default opt-in status for one subscription topic, which applies + to every member unless a user sets their own override. Args: custom_routing: The default channels to send to this tenant when has_custom_routing is enabled @@ -113,7 +114,8 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Remove Default Preferences For Topic + Removes a tenant's default preference for one subscription topic, addressed by + tenant id and topic id. Args: extra_headers: Send extra headers @@ -176,7 +178,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Create or Replace Default Preferences For Topic + Sets a tenant's default opt-in status for one subscription topic, which applies + to every member unless a user sets their own override. Args: custom_routing: The default channels to send to this tenant when has_custom_routing is enabled @@ -229,7 +232,8 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Remove Default Preferences For Topic + Removes a tenant's default preference for one subscription topic, addressed by + tenant id and topic id. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/tenants/templates/templates.py b/src/courier/resources/tenants/templates/templates.py index accb1275..e617ec2b 100644 --- a/src/courier/resources/tenants/templates/templates.py +++ b/src/courier/resources/tenants/templates/templates.py @@ -72,7 +72,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BaseTemplateTenantAssociation: """ - Get a Template in Tenant + Returns a tenant's notification template with its content, version, and created, + updated, and published timestamps. Args: extra_headers: Send extra headers @@ -109,7 +110,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TemplateListResponse: """ - List Templates in Tenant + Lists a tenant's notification templates, each carrying its version and published + timestamp. Paged. Args: cursor: Continue the pagination with the next cursor @@ -156,13 +158,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Deletes the tenant's notification template with the given `template_id`. - - Returns **204 No Content** with an empty body on success. + """Deletes a tenant's notification template by id. - Returns **404** if there is no template with this ID for the tenant, including a - second `DELETE` after a successful removal. + Sends for that tenant then use + the workspace template registered under the same id. Args: extra_headers: Send extra headers @@ -200,10 +199,8 @@ def publish( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PostTenantTemplatePublishResponse: """ - Publishes a specific version of a notification template for a tenant. - - The template must already exist in the tenant's notification map. If no version - is specified, defaults to publishing the "latest" version. + Publishes a version of a tenant's notification template, making it the content + that tenant's sends render from until you publish another. Args: version: The version of the template to publish (e.g., "v1", "v2", "latest"). If not @@ -247,13 +244,8 @@ def replace( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PutTenantTemplateResponse: """ - Creates or updates a notification template for a tenant. - - If the template already exists for the tenant, it will be updated (200). - Otherwise, a new template is created (201). - - Optionally publishes the template immediately if the `published` flag is set to - true. + Creates or updates a notification template scoped to one tenant, letting a + tenant override the content the workspace template would send. Args: template: Template configuration for creating or updating a tenant notification template @@ -327,7 +319,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BaseTemplateTenantAssociation: """ - Get a Template in Tenant + Returns a tenant's notification template with its content, version, and created, + updated, and published timestamps. Args: extra_headers: Send extra headers @@ -364,7 +357,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TemplateListResponse: """ - List Templates in Tenant + Lists a tenant's notification templates, each carrying its version and published + timestamp. Paged. Args: cursor: Continue the pagination with the next cursor @@ -411,13 +405,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Deletes the tenant's notification template with the given `template_id`. - - Returns **204 No Content** with an empty body on success. + """Deletes a tenant's notification template by id. - Returns **404** if there is no template with this ID for the tenant, including a - second `DELETE` after a successful removal. + Sends for that tenant then use + the workspace template registered under the same id. Args: extra_headers: Send extra headers @@ -455,10 +446,8 @@ async def publish( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PostTenantTemplatePublishResponse: """ - Publishes a specific version of a notification template for a tenant. - - The template must already exist in the tenant's notification map. If no version - is specified, defaults to publishing the "latest" version. + Publishes a version of a tenant's notification template, making it the content + that tenant's sends render from until you publish another. Args: version: The version of the template to publish (e.g., "v1", "v2", "latest"). If not @@ -502,13 +491,8 @@ async def replace( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PutTenantTemplateResponse: """ - Creates or updates a notification template for a tenant. - - If the template already exists for the tenant, it will be updated (200). - Otherwise, a new template is created (201). - - Optionally publishes the template immediately if the `published` flag is set to - true. + Creates or updates a notification template scoped to one tenant, letting a + tenant override the content the workspace template would send. Args: template: Template configuration for creating or updating a tenant notification template diff --git a/src/courier/resources/tenants/templates/versions.py b/src/courier/resources/tenants/templates/versions.py index 8b941609..8b33fe1e 100644 --- a/src/courier/resources/tenants/templates/versions.py +++ b/src/courier/resources/tenants/templates/versions.py @@ -54,13 +54,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BaseTemplateTenantAssociation: """ - Fetches a specific version of a tenant template. - - Supports the following version formats: - - - `latest` - The most recent version of the template - - `published` - The currently published version - - `v{version}` - A specific version (e.g., "v1", "v2", "v1.0.0") + Returns one version of a tenant template, addressed by version number or by + latest, with its content and publish timestamp. Args: extra_headers: Send extra headers @@ -125,13 +120,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BaseTemplateTenantAssociation: """ - Fetches a specific version of a tenant template. - - Supports the following version formats: - - - `latest` - The most recent version of the template - - `published` - The currently published version - - `v{version}` - A specific version (e.g., "v1", "v2", "v1.0.0") + Returns one version of a tenant template, addressed by version number or by + latest, with its content and publish timestamp. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/tenants/tenants.py b/src/courier/resources/tenants/tenants.py index 1c0d55b9..5d60c53d 100644 --- a/src/courier/resources/tenants/tenants.py +++ b/src/courier/resources/tenants/tenants.py @@ -82,7 +82,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Tenant: """ - Get a Tenant + Returns one tenant with its name, parent tenant id, default preferences, + properties, and the user profile applied to its members. Args: extra_headers: Send extra headers @@ -121,7 +122,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Tenant: """ - Create or Replace a Tenant + Creates or replaces a tenant from a name, parent, brand, properties, and default + preferences supplied in the request body. Args: name: Name of the tenant. @@ -180,7 +182,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TenantListResponse: """ - Get a List of Tenants + Lists the workspace's tenants, each carrying a name, parent tenant, properties, + and default preferences. Paged. Args: cursor: Continue the pagination with the next cursor @@ -227,8 +230,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a Tenant + """Deletes a tenant. + + Its members' workspace-level profiles and preferences live + outside the tenant and are managed separately. Args: extra_headers: Send extra headers @@ -263,8 +268,10 @@ def list_users( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TenantListUsersResponse: - """ - Get Users in Tenant + """Returns the users belonging to a tenant with cursor paging. + + Use it to see who a + tenant-scoped send will reach. Args: cursor: Continue the pagination with the next cursor @@ -340,7 +347,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Tenant: """ - Get a Tenant + Returns one tenant with its name, parent tenant id, default preferences, + properties, and the user profile applied to its members. Args: extra_headers: Send extra headers @@ -379,7 +387,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Tenant: """ - Create or Replace a Tenant + Creates or replaces a tenant from a name, parent, brand, properties, and default + preferences supplied in the request body. Args: name: Name of the tenant. @@ -438,7 +447,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TenantListResponse: """ - Get a List of Tenants + Lists the workspace's tenants, each carrying a name, parent tenant, properties, + and default preferences. Paged. Args: cursor: Continue the pagination with the next cursor @@ -485,8 +495,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Delete a Tenant + """Deletes a tenant. + + Its members' workspace-level profiles and preferences live + outside the tenant and are managed separately. Args: extra_headers: Send extra headers @@ -521,8 +533,10 @@ async def list_users( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TenantListUsersResponse: - """ - Get Users in Tenant + """Returns the users belonging to a tenant with cursor paging. + + Use it to see who a + tenant-scoped send will reach. Args: cursor: Continue the pagination with the next cursor diff --git a/src/courier/resources/translations.py b/src/courier/resources/translations.py index f4b1cfd9..da61bc77 100644 --- a/src/courier/resources/translations.py +++ b/src/courier/resources/translations.py @@ -53,7 +53,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: """ - Get translations by locale + Returns the translation strings stored for one domain and locale, for use in + localized notification content. Args: extra_headers: Send extra headers @@ -89,8 +90,10 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Update a translation + """Uploads the translation strings for one domain and locale. + + Courier uses them to + render localized content for recipients in that locale. Args: extra_headers: Send extra headers @@ -149,7 +152,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: """ - Get translations by locale + Returns the translation strings stored for one domain and locale, for use in + localized notification content. Args: extra_headers: Send extra headers @@ -185,8 +189,10 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Update a translation + """Uploads the translation strings for one domain and locale. + + Courier uses them to + render localized content for recipients in that locale. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/users/preferences.py b/src/courier/resources/users/preferences.py index 27e74a1d..be363dcc 100644 --- a/src/courier/resources/users/preferences.py +++ b/src/courier/resources/users/preferences.py @@ -67,7 +67,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceRetrieveResponse: """ - Fetch all user preferences. + Returns a user's preference overrides with paging, one entry per subscription + topic they have set a choice for. Args: tenant_id: Query the preferences of a user for this specific tenant context. @@ -107,25 +108,10 @@ def bulk_replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceBulkReplaceResponse: - """Replace a user's complete set of preference overrides in a single request. - - The - topics in the request body become the recipient's entire set of overrides: - listed topics are created or updated, and every existing override that is not - included in the body is reset to its topic default. Submitting an empty `topics` - array is a valid clear-all that resets every existing override. - - This operation is validation-atomic (all-or-nothing): structural validation - fails fast with a single `400`, and if any topic is semantically invalid (an - unknown topic, a `REQUIRED` topic that cannot be opted out, or a custom routing - request that is not available on the workspace's plan) the request returns a - single `400` aggregating every failure in `errors` and writes nothing. On - success it returns `200` with `items` (the complete resulting override set) and - `deleted` (the ids of the overrides that were reset to default). - - Every `topic_id` in the response — in `items`, `deleted`, and any `errors` — is - returned in Courier's canonical topic id form, regardless of the form supplied - in the request. + """Replaces a user's entire set of preference overrides. + + Any topic you leave out is + reset to its default, so send the full set rather than a subset. Args: topics: The complete set of topic overrides for the user. Up to 50 topics may be @@ -173,23 +159,8 @@ def bulk_update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceBulkUpdateResponse: """ - Additively create or update a user's preferences for one or more subscription - topics in a single request. Only the topics included in the request body are - created or updated; any existing overrides for topics not listed are left - untouched. - - Structural validation of the request body fails fast with a single `400`. Beyond - that, each topic is processed independently (partial-success, not - all-or-nothing): valid topics are written and returned in `items`, while topics - that cannot be applied are collected in `errors` with a per-topic `reason` (for - example an unknown topic, a `REQUIRED` topic that cannot be opted out, a custom - routing request that is not available on the workspace's plan, or a write - failure). The request therefore returns `200` with both lists whenever the body - is structurally valid. - - Every `topic_id` in the response — in both `items` and `errors` — is returned in - Courier's canonical topic id form, regardless of the form supplied in the - request. + Adds or updates a user's preferences for several subscription topics at once. + Topics you leave out keep whatever they were set to before. Args: topics: The topics to create or update. Between 1 and 50 topics may be provided in a @@ -236,9 +207,8 @@ def delete_topic( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Remove a user's preferences for a specific subscription topic, resetting the - topic to its effective default. This operation is idempotent: deleting a - preference that does not exist succeeds with no error. + Removes a user's override for one subscription topic, resetting it to the + effective default from the tenant or workspace. Args: tenant_id: Delete the preferences of a user for this specific tenant context. @@ -284,7 +254,8 @@ def retrieve_topic( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceRetrieveTopicResponse: """ - Fetch user preferences for a specific subscription topic. + Returns a user's opt-in status and channel choices for one subscription topic, + or the effective default if they have set no override. Args: tenant_id: Query the preferences of a user for this specific tenant context. @@ -330,7 +301,8 @@ def update_or_create_topic( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceUpdateOrCreateTopicResponse: """ - Update or Create user preferences for a specific subscription topic. + Sets a user's opt-in status and channel choices for one subscription topic, + overriding the tenant default for that topic only. Args: tenant_id: Update the preferences of a user for this specific tenant context. @@ -399,7 +371,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceRetrieveResponse: """ - Fetch all user preferences. + Returns a user's preference overrides with paging, one entry per subscription + topic they have set a choice for. Args: tenant_id: Query the preferences of a user for this specific tenant context. @@ -441,25 +414,10 @@ async def bulk_replace( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceBulkReplaceResponse: - """Replace a user's complete set of preference overrides in a single request. - - The - topics in the request body become the recipient's entire set of overrides: - listed topics are created or updated, and every existing override that is not - included in the body is reset to its topic default. Submitting an empty `topics` - array is a valid clear-all that resets every existing override. - - This operation is validation-atomic (all-or-nothing): structural validation - fails fast with a single `400`, and if any topic is semantically invalid (an - unknown topic, a `REQUIRED` topic that cannot be opted out, or a custom routing - request that is not available on the workspace's plan) the request returns a - single `400` aggregating every failure in `errors` and writes nothing. On - success it returns `200` with `items` (the complete resulting override set) and - `deleted` (the ids of the overrides that were reset to default). - - Every `topic_id` in the response — in `items`, `deleted`, and any `errors` — is - returned in Courier's canonical topic id form, regardless of the form supplied - in the request. + """Replaces a user's entire set of preference overrides. + + Any topic you leave out is + reset to its default, so send the full set rather than a subset. Args: topics: The complete set of topic overrides for the user. Up to 50 topics may be @@ -509,23 +467,8 @@ async def bulk_update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceBulkUpdateResponse: """ - Additively create or update a user's preferences for one or more subscription - topics in a single request. Only the topics included in the request body are - created or updated; any existing overrides for topics not listed are left - untouched. - - Structural validation of the request body fails fast with a single `400`. Beyond - that, each topic is processed independently (partial-success, not - all-or-nothing): valid topics are written and returned in `items`, while topics - that cannot be applied are collected in `errors` with a per-topic `reason` (for - example an unknown topic, a `REQUIRED` topic that cannot be opted out, a custom - routing request that is not available on the workspace's plan, or a write - failure). The request therefore returns `200` with both lists whenever the body - is structurally valid. - - Every `topic_id` in the response — in both `items` and `errors` — is returned in - Courier's canonical topic id form, regardless of the form supplied in the - request. + Adds or updates a user's preferences for several subscription topics at once. + Topics you leave out keep whatever they were set to before. Args: topics: The topics to create or update. Between 1 and 50 topics may be provided in a @@ -574,9 +517,8 @@ async def delete_topic( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Remove a user's preferences for a specific subscription topic, resetting the - topic to its effective default. This operation is idempotent: deleting a - preference that does not exist succeeds with no error. + Removes a user's override for one subscription topic, resetting it to the + effective default from the tenant or workspace. Args: tenant_id: Delete the preferences of a user for this specific tenant context. @@ -622,7 +564,8 @@ async def retrieve_topic( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceRetrieveTopicResponse: """ - Fetch user preferences for a specific subscription topic. + Returns a user's opt-in status and channel choices for one subscription topic, + or the effective default if they have set no override. Args: tenant_id: Query the preferences of a user for this specific tenant context. @@ -668,7 +611,8 @@ async def update_or_create_topic( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreferenceUpdateOrCreateTopicResponse: """ - Update or Create user preferences for a specific subscription topic. + Sets a user's opt-in status and channel choices for one subscription topic, + overriding the tenant default for that topic only. Args: tenant_id: Update the preferences of a user for this specific tenant context. diff --git a/src/courier/resources/users/tenants.py b/src/courier/resources/users/tenants.py index 64b9fb56..1b958f7d 100644 --- a/src/courier/resources/users/tenants.py +++ b/src/courier/resources/users/tenants.py @@ -57,8 +57,10 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TenantListResponse: - """ - Returns a paginated list of user tenant associations. + """Returns the tenants a user belongs to, with cursor paging. + + A user can belong to + many tenants, each with its own profile and preferences. Args: cursor: Continue the pagination with the next cursor @@ -105,11 +107,9 @@ def add_multiple( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """This endpoint is used to add a user to multiple tenants in one call. - - A custom - profile can also be supplied for each tenant. This profile will be merged with - the user's main profile when sending to the user with that tenant. + """ + Adds a user to several tenants in one call, each optionally with a per-tenant + profile that overrides their workspace profile. Args: extra_headers: Send extra headers @@ -146,10 +146,8 @@ def add_single( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - This endpoint is used to add a single tenant. - - A custom profile can also be supplied with the tenant. This profile will be - merged with the user's main profile when sending to the user with that tenant. + Adds a user to one tenant, optionally with a tenant-specific profile that + overrides their workspace profile for sends in that tenant. Args: extra_headers: Send extra headers @@ -185,8 +183,10 @@ def remove_all( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Removes a user from any tenants they may have been associated with. + """Removes a user from every tenant they belong to in one call. + + Their + workspace-level profile is a separate resource. Args: extra_headers: Send extra headers @@ -220,8 +220,10 @@ def remove_single( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Removes a user from the supplied tenant. + """Removes a user from one tenant. + + Their other tenant memberships and workspace + profile are managed through separate endpoints. Args: extra_headers: Send extra headers @@ -279,8 +281,10 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TenantListResponse: - """ - Returns a paginated list of user tenant associations. + """Returns the tenants a user belongs to, with cursor paging. + + A user can belong to + many tenants, each with its own profile and preferences. Args: cursor: Continue the pagination with the next cursor @@ -327,11 +331,9 @@ async def add_multiple( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """This endpoint is used to add a user to multiple tenants in one call. - - A custom - profile can also be supplied for each tenant. This profile will be merged with - the user's main profile when sending to the user with that tenant. + """ + Adds a user to several tenants in one call, each optionally with a per-tenant + profile that overrides their workspace profile. Args: extra_headers: Send extra headers @@ -368,10 +370,8 @@ async def add_single( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - This endpoint is used to add a single tenant. - - A custom profile can also be supplied with the tenant. This profile will be - merged with the user's main profile when sending to the user with that tenant. + Adds a user to one tenant, optionally with a tenant-specific profile that + overrides their workspace profile for sends in that tenant. Args: extra_headers: Send extra headers @@ -407,8 +407,10 @@ async def remove_all( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Removes a user from any tenants they may have been associated with. + """Removes a user from every tenant they belong to in one call. + + Their + workspace-level profile is a separate resource. Args: extra_headers: Send extra headers @@ -442,8 +444,10 @@ async def remove_single( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """ - Removes a user from the supplied tenant. + """Removes a user from one tenant. + + Their other tenant memberships and workspace + profile are managed through separate endpoints. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/users/tokens.py b/src/courier/resources/users/tokens.py index 964065af..ef065605 100644 --- a/src/courier/resources/users/tokens.py +++ b/src/courier/resources/users/tokens.py @@ -58,7 +58,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TokenRetrieveResponse: """ - Get single token available for a `:token` + Returns one device token with its provider key, status and status reason, expiry + date, and any properties stored alongside it. Args: extra_headers: Send extra headers @@ -95,7 +96,8 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Apply a JSON Patch (RFC 6902) to the specified token. + Applies a JSON Patch to a device token, changing its status, expiry, or + properties without re-registering it. Args: extra_headers: Send extra headers @@ -132,7 +134,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TokenListResponse: """ - Gets all tokens available for a :user_id + Returns every device token registered for a user, each with its provider key, + status, and expiry date. Args: extra_headers: Send extra headers @@ -166,7 +169,8 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Delete User Token + Deletes one device token for a user, addressed by the token value, so push sends + no longer target that device. Args: extra_headers: Send extra headers @@ -202,7 +206,8 @@ def add_multiple( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Adds multiple tokens to a user and overwrites matching existing tokens. + Registers several device tokens for a user in one call, overwriting any stored + token with a matching value. Args: extra_headers: Send extra headers @@ -242,7 +247,8 @@ def add_single( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Adds a single token to a user and overwrites a matching existing token. + Registers one device token for a user against a provider key, overwriting the + token if it already exists. Push sends resolve tokens per user. Args: device: Information about the device the token came from. @@ -319,7 +325,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TokenRetrieveResponse: """ - Get single token available for a `:token` + Returns one device token with its provider key, status and status reason, expiry + date, and any properties stored alongside it. Args: extra_headers: Send extra headers @@ -356,7 +363,8 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Apply a JSON Patch (RFC 6902) to the specified token. + Applies a JSON Patch to a device token, changing its status, expiry, or + properties without re-registering it. Args: extra_headers: Send extra headers @@ -393,7 +401,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TokenListResponse: """ - Gets all tokens available for a :user_id + Returns every device token registered for a user, each with its provider key, + status, and expiry date. Args: extra_headers: Send extra headers @@ -427,7 +436,8 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Delete User Token + Deletes one device token for a user, addressed by the token value, so push sends + no longer target that device. Args: extra_headers: Send extra headers @@ -463,7 +473,8 @@ async def add_multiple( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Adds multiple tokens to a user and overwrites matching existing tokens. + Registers several device tokens for a user in one call, overwriting any stored + token with a matching value. Args: extra_headers: Send extra headers @@ -503,7 +514,8 @@ async def add_single( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Adds a single token to a user and overwrites a matching existing token. + Registers one device token for a user against a provider key, overwriting the + token if it already exists. Push sends resolve tokens per user. Args: device: Information about the device the token came from. diff --git a/src/courier/resources/workspace_preferences/topics.py b/src/courier/resources/workspace_preferences/topics.py index 7c2ca936..9ae430b2 100644 --- a/src/courier/resources/workspace_preferences/topics.py +++ b/src/courier/resources/workspace_preferences/topics.py @@ -64,11 +64,10 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceTopicGetResponse: - """Create a subscription preference topic inside a workspace preference. + """Creates a subscription topic inside a workspace preference. - Fails with - 404 if the workspace preference does not exist. The topic id is generated and - returned. + The default status + sets whether users start opted in, opted out, or required. Args: default_status: The default subscription status applied when a recipient has not set their own. @@ -128,11 +127,9 @@ def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceTopicGetResponse: - """Retrieve a topic within a workspace preference. - - Returns 404 if the workspace - preference does not exist, the topic does not exist, or the topic belongs to a - different workspace preference. + """ + Returns one subscription topic with its default status, routing options, allowed + preferences, and unsubscribe header setting. Args: extra_headers: Send extra headers @@ -169,7 +166,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceTopicListResponse: """ - List the topics in a workspace preference. + Returns the subscription topics inside a workspace preference, each with its + default status and routing options. Args: extra_headers: Send extra headers @@ -202,10 +200,9 @@ def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Archive a topic and remove it from its workspace preference. - - Same 404 rules as - GET. + """ + Archives a subscription topic and removes it from its workspace preference, + addressed by section id and topic id. Args: extra_headers: Send extra headers @@ -344,11 +341,10 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceTopicGetResponse: - """Create a subscription preference topic inside a workspace preference. + """Creates a subscription topic inside a workspace preference. - Fails with - 404 if the workspace preference does not exist. The topic id is generated and - returned. + The default status + sets whether users start opted in, opted out, or required. Args: default_status: The default subscription status applied when a recipient has not set their own. @@ -408,11 +404,9 @@ async def retrieve( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceTopicGetResponse: - """Retrieve a topic within a workspace preference. - - Returns 404 if the workspace - preference does not exist, the topic does not exist, or the topic belongs to a - different workspace preference. + """ + Returns one subscription topic with its default status, routing options, allowed + preferences, and unsubscribe header setting. Args: extra_headers: Send extra headers @@ -449,7 +443,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceTopicListResponse: """ - List the topics in a workspace preference. + Returns the subscription topics inside a workspace preference, each with its + default status and routing options. Args: extra_headers: Send extra headers @@ -482,10 +477,9 @@ async def archive( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Archive a topic and remove it from its workspace preference. - - Same 404 rules as - GET. + """ + Archives a subscription topic and removes it from its workspace preference, + addressed by section id and topic id. Args: extra_headers: Send extra headers diff --git a/src/courier/resources/workspace_preferences/workspace_preferences.py b/src/courier/resources/workspace_preferences/workspace_preferences.py index 361f9551..38339b8f 100644 --- a/src/courier/resources/workspace_preferences/workspace_preferences.py +++ b/src/courier/resources/workspace_preferences/workspace_preferences.py @@ -76,11 +76,10 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceGetResponse: - """Create a workspace preference. + """Creates a workspace preference and returns its generated id. - The workspace preference id is generated and - returned. Topics are created inside a workspace preference via POST - /preferences/sections/{section_id}/topics. + Add subscription + topics to it afterwards with the topics endpoint. Args: name: Human-readable name for the workspace preference. @@ -128,7 +127,8 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceGetResponse: """ - Retrieve a workspace preference by id, including its topics. + Returns one workspace preference by id, including its subscription topics, + routing options, and custom routing flag. Args: extra_headers: Send extra headers @@ -159,10 +159,9 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceListResponse: - """List the workspace's preferences. - - Each workspace preference embeds its topics. - Scoped to the workspace of the API key. + """ + Returns the workspace's preferences, each embedding its subscription topics, + routing options, and whether custom routing is allowed. """ return self._get( "/preferences/sections", @@ -221,11 +220,9 @@ def publish( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PublishPreferencesResponse: - """Publish the workspace's preferences page. - - Takes a snapshot of every workspace - preference with its topics under a new published version, making the current - state visible on the hosted preferences page (non-draft). + """ + Publishes the workspace preference page, snapshotting every preference and + topic, and returns the page id and a preview URL. Args: brand_id: Brand for the hosted page - "default" (workspace default brand), "none" (no @@ -355,11 +352,10 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceGetResponse: - """Create a workspace preference. + """Creates a workspace preference and returns its generated id. - The workspace preference id is generated and - returned. Topics are created inside a workspace preference via POST - /preferences/sections/{section_id}/topics. + Add subscription + topics to it afterwards with the topics endpoint. Args: name: Human-readable name for the workspace preference. @@ -407,7 +403,8 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceGetResponse: """ - Retrieve a workspace preference by id, including its topics. + Returns one workspace preference by id, including its subscription topics, + routing options, and custom routing flag. Args: extra_headers: Send extra headers @@ -438,10 +435,9 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkspacePreferenceListResponse: - """List the workspace's preferences. - - Each workspace preference embeds its topics. - Scoped to the workspace of the API key. + """ + Returns the workspace's preferences, each embedding its subscription topics, + routing options, and whether custom routing is allowed. """ return await self._get( "/preferences/sections", @@ -500,11 +496,9 @@ async def publish( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PublishPreferencesResponse: - """Publish the workspace's preferences page. - - Takes a snapshot of every workspace - preference with its topics under a new published version, making the current - state visible on the hosted preferences page (non-draft). + """ + Publishes the workspace preference page, snapshotting every preference and + topic, and returns the page id and a preview URL. Args: brand_id: Brand for the hosted page - "default" (workspace default brand), "none" (no From 92093156c03c0c8a56e7a43fe41b4d4490fcc7b2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:26:42 +0000 Subject: [PATCH 3/6] docs(openapi): document Idempotency-Key header on idempotent POST endpoints (#176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Idempotency is honored at runtime (handleIdempotentApi dedups POSTs by tenant + Idempotency-Key + path, ~25h default TTL) but was undocumented in the spec — openapi.yml defined zero header parameters, so it never appeared in the API reference or as a typed SDK parameter. Adds reusable components.parameters entries (Idempotency-Key and x-idempotency-expiration) and references them from the 21 POST operations whose backend handlers are actually wrapped in handleIdempotentApi: send, profiles create + subscribeToList, lists addSubscribers, notifications create + publish, users preferences, automations invoke (both), all 6 journeys POSTs, brands, routing-strategies, providers, and workspace preferences (publish/sections/topics). Deliberately NOT added to POSTs whose handlers use plain handleApi (no dedup): messages cancel/resend, auth issue-token, digests trigger, inbound/courier, tenants publishTemplate. notifications/{id}/duplicate is not routed through the public REST gateway at all. Co-authored-by: Claude Opus 4.8 --- .stats.yml | 4 +- src/courier/resources/automations/invoke.py | 46 ++++++++- src/courier/resources/brands.py | 24 ++++- src/courier/resources/journeys/journeys.py | 98 ++++++++++++++++++- src/courier/resources/journeys/templates.py | 46 ++++++++- src/courier/resources/lists/subscriptions.py | 24 ++++- .../resources/notifications/notifications.py | 46 ++++++++- src/courier/resources/profiles/lists.py | 24 ++++- src/courier/resources/profiles/profiles.py | 26 ++++- src/courier/resources/providers/providers.py | 24 ++++- src/courier/resources/routing_strategies.py | 24 ++++- src/courier/resources/send.py | 26 ++++- src/courier/resources/users/preferences.py | 24 ++++- .../resources/workspace_preferences/topics.py | 24 ++++- .../workspace_preferences.py | 46 ++++++++- .../invoke_invoke_ad_hoc_params.py | 8 +- .../invoke_invoke_by_template_params.py | 8 +- src/courier/types/brand_create_params.py | 7 +- src/courier/types/journey_cancel_params.py | 12 ++- src/courier/types/journey_create_params.py | 7 +- src/courier/types/journey_invoke_params.py | 8 +- src/courier/types/journey_publish_params.py | 8 +- .../types/journeys/template_create_params.py | 4 + .../types/journeys/template_publish_params.py | 4 + .../types/lists/subscription_add_params.py | 7 +- .../types/notification_create_params.py | 7 +- .../types/notification_publish_params.py | 8 +- src/courier/types/profile_create_params.py | 8 +- .../types/profiles/list_subscribe_params.py | 7 +- src/courier/types/provider_create_params.py | 8 +- .../types/routing_strategy_create_params.py | 7 +- src/courier/types/send_message_params.py | 7 +- .../users/preference_bulk_update_params.py | 7 +- .../workspace_preference_create_params.py | 7 +- .../workspace_preference_publish_params.py | 8 +- .../topic_create_params.py | 7 +- .../api_resources/automations/test_invoke.py | 8 ++ .../api_resources/journeys/test_templates.py | 8 ++ .../api_resources/lists/test_subscriptions.py | 82 ++++++++++++++++ tests/api_resources/profiles/test_lists.py | 82 ++++++++++++++++ tests/api_resources/test_brands.py | 4 + tests/api_resources/test_journeys.py | 52 ++++++++++ tests/api_resources/test_notifications.py | 8 ++ tests/api_resources/test_profiles.py | 22 +++++ tests/api_resources/test_providers.py | 4 + .../api_resources/test_routing_strategies.py | 4 + tests/api_resources/test_send.py | 4 + .../test_workspace_preferences.py | 8 ++ tests/api_resources/users/test_preferences.py | 4 + .../workspace_preferences/test_topics.py | 4 + 50 files changed, 917 insertions(+), 37 deletions(-) diff --git a/.stats.yml b/.stats.yml index 48e48092..a6b7b828 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 134 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-5c878919b3df530781ebcd4ab1cda83606304da75c53fe0817d4c725d5bbbe73.yml -openapi_spec_hash: dd37022222543ff064200e65e4b82f59 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-0319162d68adb4d442698563aee11cce71cc310b70cbbe908b16287934ffc548.yml +openapi_spec_hash: 729cfea83369faf0261496c24692dce8 config_hash: 8d28dbeabe9d4dcc7d5b8c021a4cbbd7 diff --git a/src/courier/resources/automations/invoke.py b/src/courier/resources/automations/invoke.py index 1ecaf91b..a50a22c1 100644 --- a/src/courier/resources/automations/invoke.py +++ b/src/courier/resources/automations/invoke.py @@ -7,7 +7,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -52,6 +52,8 @@ def invoke_ad_hoc( profile: Optional[Dict[str, object]] | Omit = omit, recipient: Optional[str] | Omit = omit, template: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -72,6 +74,15 @@ def invoke_ad_hoc( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/automations/invoke", body=maybe_transform( @@ -100,6 +111,8 @@ def invoke_by_template( data: Optional[Dict[str, object]] | Omit = omit, profile: Optional[Dict[str, object]] | Omit = omit, template: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -122,6 +135,15 @@ def invoke_by_template( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/automations/{template_id}/invoke", template_id=template_id), body=maybe_transform( @@ -170,6 +192,8 @@ async def invoke_ad_hoc( profile: Optional[Dict[str, object]] | Omit = omit, recipient: Optional[str] | Omit = omit, template: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -190,6 +214,15 @@ async def invoke_ad_hoc( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/automations/invoke", body=await async_maybe_transform( @@ -218,6 +251,8 @@ async def invoke_by_template( data: Optional[Dict[str, object]] | Omit = omit, profile: Optional[Dict[str, object]] | Omit = omit, template: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -240,6 +275,15 @@ async def invoke_by_template( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/automations/{template_id}/invoke", template_id=template_id), body=await async_maybe_transform( diff --git a/src/courier/resources/brands.py b/src/courier/resources/brands.py index 1f942d76..00a9f6d2 100644 --- a/src/courier/resources/brands.py +++ b/src/courier/resources/brands.py @@ -8,7 +8,7 @@ from ..types import brand_list_params, brand_create_params, brand_update_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from .._utils import path_template, maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -53,6 +53,8 @@ def create( settings: BrandSettingsParam, id: Optional[str] | Omit = omit, snippets: Optional[BrandSnippetsParam] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -74,6 +76,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/brands", body=maybe_transform( @@ -275,6 +286,8 @@ async def create( settings: BrandSettingsParam, id: Optional[str] | Omit = omit, snippets: Optional[BrandSnippetsParam] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -296,6 +309,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/brands", body=await async_maybe_transform( diff --git a/src/courier/resources/journeys/journeys.py b/src/courier/resources/journeys/journeys.py index d85cf354..e228e7d8 100644 --- a/src/courier/resources/journeys/journeys.py +++ b/src/courier/resources/journeys/journeys.py @@ -18,7 +18,7 @@ journey_retrieve_params, ) from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, required_args, maybe_transform, async_maybe_transform +from ..._utils import path_template, required_args, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from .templates import ( TemplatesResource, @@ -78,6 +78,8 @@ def create( nodes: Iterable[JourneyNodeParam], enabled: bool | Omit = omit, state: JourneyState | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -100,6 +102,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/journeys", body=maybe_transform( @@ -249,6 +260,8 @@ def cancel( self, *, cancelation_token: str, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -276,6 +289,8 @@ def cancel( self, *, run_id: str, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -303,6 +318,8 @@ def cancel( self, *, cancelation_token: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, run_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -311,6 +328,15 @@ def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CancelJourneyResponse: + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return cast( CancelJourneyResponse, self._post( @@ -338,6 +364,8 @@ def invoke( data: Dict[str, object] | Omit = omit, profile: Dict[str, object] | Omit = omit, user_id: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -376,6 +404,15 @@ def invoke( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/journeys/{template_id}/invoke", template_id=template_id), body=maybe_transform( @@ -431,6 +468,8 @@ def publish( template_id: str, *, version: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -453,6 +492,15 @@ def publish( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/journeys/{template_id}/publish", template_id=template_id), body=maybe_transform({"version": version}, journey_publish_params.JourneyPublishParams), @@ -543,6 +591,8 @@ async def create( nodes: Iterable[JourneyNodeParam], enabled: bool | Omit = omit, state: JourneyState | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -565,6 +615,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/journeys", body=await async_maybe_transform( @@ -714,6 +773,8 @@ async def cancel( self, *, cancelation_token: str, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -741,6 +802,8 @@ async def cancel( self, *, run_id: str, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -768,6 +831,8 @@ async def cancel( self, *, cancelation_token: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, run_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -776,6 +841,15 @@ async def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CancelJourneyResponse: + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return cast( CancelJourneyResponse, await self._post( @@ -803,6 +877,8 @@ async def invoke( data: Dict[str, object] | Omit = omit, profile: Dict[str, object] | Omit = omit, user_id: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -841,6 +917,15 @@ async def invoke( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/journeys/{template_id}/invoke", template_id=template_id), body=await async_maybe_transform( @@ -896,6 +981,8 @@ async def publish( template_id: str, *, version: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -918,6 +1005,15 @@ async def publish( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/journeys/{template_id}/publish", template_id=template_id), body=await async_maybe_transform({"version": version}, journey_publish_params.JourneyPublishParams), diff --git a/src/courier/resources/journeys/templates.py b/src/courier/resources/journeys/templates.py index bb5ea256..68e2b8c5 100644 --- a/src/courier/resources/journeys/templates.py +++ b/src/courier/resources/journeys/templates.py @@ -8,7 +8,7 @@ from ...types import NotificationTemplateState from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -65,6 +65,8 @@ def create( notification: template_create_params.Notification, provider_key: str | Omit = omit, state: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -88,6 +90,15 @@ def create( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/journeys/{template_id}/templates", template_id=template_id), body=maybe_transform( @@ -287,6 +298,8 @@ def publish( *, template_id: str, version: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -313,6 +326,15 @@ def publish( if not notification_id: raise ValueError(f"Expected a non-empty value for `notification_id` but received {notification_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template( "/journeys/{template_id}/templates/{notification_id}/publish", @@ -570,6 +592,8 @@ async def create( notification: template_create_params.Notification, provider_key: str | Omit = omit, state: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -593,6 +617,15 @@ async def create( """ if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/journeys/{template_id}/templates", template_id=template_id), body=await async_maybe_transform( @@ -792,6 +825,8 @@ async def publish( *, template_id: str, version: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -818,6 +853,15 @@ async def publish( if not notification_id: raise ValueError(f"Expected a non-empty value for `notification_id` but received {notification_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template( "/journeys/{template_id}/templates/{notification_id}/publish", diff --git a/src/courier/resources/lists/subscriptions.py b/src/courier/resources/lists/subscriptions.py index 9d3cd1f0..0e68a3f6 100644 --- a/src/courier/resources/lists/subscriptions.py +++ b/src/courier/resources/lists/subscriptions.py @@ -7,7 +7,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -96,6 +96,8 @@ def add( list_id: str, *, recipients: Iterable[PutSubscriptionsRecipientParam], + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -119,6 +121,15 @@ def add( if not list_id: raise ValueError(f"Expected a non-empty value for `list_id` but received {list_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/lists/{list_id}/subscriptions", list_id=list_id), body=maybe_transform({"recipients": recipients}, subscription_add_params.SubscriptionAddParams), @@ -314,6 +325,8 @@ async def add( list_id: str, *, recipients: Iterable[PutSubscriptionsRecipientParam], + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -337,6 +350,15 @@ async def add( if not list_id: raise ValueError(f"Expected a non-empty value for `list_id` but received {list_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/lists/{list_id}/subscriptions", list_id=list_id), body=await async_maybe_transform({"recipients": recipients}, subscription_add_params.SubscriptionAddParams), diff --git a/src/courier/resources/notifications/notifications.py b/src/courier/resources/notifications/notifications.py index c6a6c1d5..aa50a4ed 100644 --- a/src/courier/resources/notifications/notifications.py +++ b/src/courier/resources/notifications/notifications.py @@ -29,7 +29,7 @@ notification_retrieve_content_params, ) from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -79,6 +79,8 @@ def create( *, notification: NotificationTemplatePayloadParam, state: Literal["DRAFT", "PUBLISHED"] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -106,6 +108,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/notifications", body=maybe_transform( @@ -342,6 +353,8 @@ def publish( id: str, *, version: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -368,6 +381,15 @@ def publish( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/notifications/{id}/publish", id=id), body=maybe_transform({"version": version}, notification_publish_params.NotificationPublishParams), @@ -665,6 +687,8 @@ async def create( *, notification: NotificationTemplatePayloadParam, state: Literal["DRAFT", "PUBLISHED"] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -692,6 +716,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/notifications", body=await async_maybe_transform( @@ -930,6 +963,8 @@ async def publish( id: str, *, version: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -956,6 +991,15 @@ async def publish( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/notifications/{id}/publish", id=id), body=await async_maybe_transform( diff --git a/src/courier/resources/profiles/lists.py b/src/courier/resources/profiles/lists.py index 8cab7b03..481bb243 100644 --- a/src/courier/resources/profiles/lists.py +++ b/src/courier/resources/profiles/lists.py @@ -7,7 +7,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -128,6 +128,8 @@ def subscribe( user_id: str, *, lists: Iterable[SubscribeToListsRequestItemParam], + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -150,6 +152,15 @@ def subscribe( """ if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/profiles/{user_id}/lists", user_id=user_id), body=maybe_transform({"lists": lists}, list_subscribe_params.ListSubscribeParams), @@ -262,6 +273,8 @@ async def subscribe( user_id: str, *, lists: Iterable[SubscribeToListsRequestItemParam], + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -284,6 +297,15 @@ async def subscribe( """ if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/profiles/{user_id}/lists", user_id=user_id), body=await async_maybe_transform({"lists": lists}, list_subscribe_params.ListSubscribeParams), diff --git a/src/courier/resources/profiles/profiles.py b/src/courier/resources/profiles/profiles.py index 51fea6c3..fb3985a6 100644 --- a/src/courier/resources/profiles/profiles.py +++ b/src/courier/resources/profiles/profiles.py @@ -15,8 +15,8 @@ AsyncListsResourceWithStreamingResponse, ) from ...types import profile_create_params, profile_update_params, profile_replace_params -from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -62,6 +62,8 @@ def create( user_id: str, *, profile: Dict[str, object], + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -84,6 +86,15 @@ def create( """ if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/profiles/{user_id}", user_id=user_id), body=maybe_transform({"profile": profile}, profile_create_params.ProfileCreateParams), @@ -269,6 +280,8 @@ async def create( user_id: str, *, profile: Dict[str, object], + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -291,6 +304,15 @@ async def create( """ if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/profiles/{user_id}", user_id=user_id), body=await async_maybe_transform({"profile": profile}, profile_create_params.ProfileCreateParams), diff --git a/src/courier/resources/providers/providers.py b/src/courier/resources/providers/providers.py index b2b6a481..4bdc5d98 100644 --- a/src/courier/resources/providers/providers.py +++ b/src/courier/resources/providers/providers.py @@ -16,7 +16,7 @@ AsyncCatalogResourceWithStreamingResponse, ) from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -63,6 +63,8 @@ def create( alias: str | Omit = omit, settings: Dict[str, object] | Omit = omit, title: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -94,6 +96,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/providers", body=maybe_transform( @@ -308,6 +319,8 @@ async def create( alias: str | Omit = omit, settings: Dict[str, object] | Omit = omit, title: str | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -339,6 +352,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/providers", body=await async_maybe_transform( diff --git a/src/courier/resources/routing_strategies.py b/src/courier/resources/routing_strategies.py index bdcfbf01..57a23e44 100644 --- a/src/courier/resources/routing_strategies.py +++ b/src/courier/resources/routing_strategies.py @@ -13,7 +13,7 @@ routing_strategy_list_notifications_params, ) from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from .._utils import path_template, maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -62,6 +62,8 @@ def create( description: Optional[str] | Omit = omit, providers: Optional[MessageProviders] | Omit = omit, tags: Optional[SequenceNotStr[str]] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -95,6 +97,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/routing-strategies", body=maybe_transform( @@ -378,6 +389,8 @@ async def create( description: Optional[str] | Omit = omit, providers: Optional[MessageProviders] | Omit = omit, tags: Optional[SequenceNotStr[str]] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -411,6 +424,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/routing-strategies", body=await async_maybe_transform( diff --git a/src/courier/resources/send.py b/src/courier/resources/send.py index 212a1dc8..b44f7da8 100644 --- a/src/courier/resources/send.py +++ b/src/courier/resources/send.py @@ -5,8 +5,8 @@ import httpx from ..types import send_message_params -from .._types import Body, Query, Headers, NotGiven, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import maybe_transform, strip_not_given, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -45,6 +45,8 @@ def message( self, *, message: send_message_params.Message, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -69,6 +71,15 @@ def message( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/send", body=maybe_transform({"message": message}, send_message_params.SendMessageParams), @@ -103,6 +114,8 @@ async def message( self, *, message: send_message_params.Message, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -127,6 +140,15 @@ async def message( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/send", body=await async_maybe_transform({"message": message}, send_message_params.SendMessageParams), diff --git a/src/courier/resources/users/preferences.py b/src/courier/resources/users/preferences.py index be363dcc..0c741192 100644 --- a/src/courier/resources/users/preferences.py +++ b/src/courier/resources/users/preferences.py @@ -7,7 +7,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -151,6 +151,8 @@ def bulk_update( *, topics: Iterable[preference_bulk_update_params.Topic], tenant_id: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -178,6 +180,15 @@ def bulk_update( """ if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/users/{user_id}/preferences", user_id=user_id), body=maybe_transform({"topics": topics}, preference_bulk_update_params.PreferenceBulkUpdateParams), @@ -459,6 +470,8 @@ async def bulk_update( *, topics: Iterable[preference_bulk_update_params.Topic], tenant_id: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -486,6 +499,15 @@ async def bulk_update( """ if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/users/{user_id}/preferences", user_id=user_id), body=await async_maybe_transform( diff --git a/src/courier/resources/workspace_preferences/topics.py b/src/courier/resources/workspace_preferences/topics.py index 9ae430b2..702d548a 100644 --- a/src/courier/resources/workspace_preferences/topics.py +++ b/src/courier/resources/workspace_preferences/topics.py @@ -8,7 +8,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -57,6 +57,8 @@ def create( include_unsubscribe_header: Optional[bool] | Omit = omit, routing_options: Optional[List[ChannelClassification]] | Omit = omit, topic_data: Optional[Dict[str, object]] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -95,6 +97,15 @@ def create( """ if not section_id: raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( path_template("/preferences/sections/{section_id}/topics", section_id=section_id), body=maybe_transform( @@ -334,6 +345,8 @@ async def create( include_unsubscribe_header: Optional[bool] | Omit = omit, routing_options: Optional[List[ChannelClassification]] | Omit = omit, topic_data: Optional[Dict[str, object]] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -372,6 +385,15 @@ async def create( """ if not section_id: raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( path_template("/preferences/sections/{section_id}/topics", section_id=section_id), body=await async_maybe_transform( diff --git a/src/courier/resources/workspace_preferences/workspace_preferences.py b/src/courier/resources/workspace_preferences/workspace_preferences.py index 38339b8f..1bf746ba 100644 --- a/src/courier/resources/workspace_preferences/workspace_preferences.py +++ b/src/courier/resources/workspace_preferences/workspace_preferences.py @@ -20,7 +20,7 @@ workspace_preference_replace_params, ) from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -69,6 +69,8 @@ def create( description: Optional[str] | Omit = omit, has_custom_routing: Optional[bool] | Omit = omit, routing_options: Optional[List[ChannelClassification]] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -98,6 +100,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/preferences/sections", body=maybe_transform( @@ -213,6 +224,8 @@ def publish( brand_id: Optional[str] | Omit = omit, description: Optional[str] | Omit = omit, heading: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -240,6 +253,15 @@ def publish( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return self._post( "/preferences/publish", body=maybe_transform( @@ -345,6 +367,8 @@ async def create( description: Optional[str] | Omit = omit, has_custom_routing: Optional[bool] | Omit = omit, routing_options: Optional[List[ChannelClassification]] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -374,6 +398,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/preferences/sections", body=await async_maybe_transform( @@ -489,6 +522,8 @@ async def publish( brand_id: Optional[str] | Omit = omit, description: Optional[str] | Omit = omit, heading: Optional[str] | Omit = omit, + idempotency_key: str | Omit = omit, + x_idempotency_expiration: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -516,6 +551,15 @@ async def publish( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = { + **strip_not_given( + { + "Idempotency-Key": idempotency_key, + "x-idempotency-expiration": x_idempotency_expiration, + } + ), + **(extra_headers or {}), + } return await self._post( "/preferences/publish", body=await async_maybe_transform( diff --git a/src/courier/types/automations/invoke_invoke_ad_hoc_params.py b/src/courier/types/automations/invoke_invoke_ad_hoc_params.py index 8a4b76c6..d2d903c8 100644 --- a/src/courier/types/automations/invoke_invoke_ad_hoc_params.py +++ b/src/courier/types/automations/invoke_invoke_ad_hoc_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from ..._utils import PropertyInfo __all__ = [ "InvokeInvokeAdHocParams", @@ -33,6 +35,10 @@ class InvokeInvokeAdHocParams(TypedDict, total=False): template: Optional[str] + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + class AutomationStepAutomationDelayStep(TypedDict, total=False): action: Required[Literal["delay"]] diff --git a/src/courier/types/automations/invoke_invoke_by_template_params.py b/src/courier/types/automations/invoke_invoke_by_template_params.py index ffe4af83..5a98e774 100644 --- a/src/courier/types/automations/invoke_invoke_by_template_params.py +++ b/src/courier/types/automations/invoke_invoke_by_template_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Dict, Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["InvokeInvokeByTemplateParams"] @@ -18,3 +20,7 @@ class InvokeInvokeByTemplateParams(TypedDict, total=False): profile: Optional[Dict[str, object]] template: Optional[str] + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/brand_create_params.py b/src/courier/types/brand_create_params.py index e7c8ed7a..5afcc3fe 100644 --- a/src/courier/types/brand_create_params.py +++ b/src/courier/types/brand_create_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict +from .._utils import PropertyInfo from .brand_settings_param import BrandSettingsParam from .brand_snippets_param import BrandSnippetsParam @@ -19,3 +20,7 @@ class BrandCreateParams(TypedDict, total=False): id: Optional[str] snippets: Optional[BrandSnippetsParam] + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/journey_cancel_params.py b/src/courier/types/journey_cancel_params.py index 3287312a..e7eb6af5 100644 --- a/src/courier/types/journey_cancel_params.py +++ b/src/courier/types/journey_cancel_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Union -from typing_extensions import Required, TypeAlias, TypedDict +from typing_extensions import Required, Annotated, TypeAlias, TypedDict + +from .._utils import PropertyInfo __all__ = ["JourneyCancelParams", "ByCancelationToken", "ByRunID"] @@ -11,9 +13,17 @@ class ByCancelationToken(TypedDict, total=False): cancelation_token: Required[str] + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + class ByRunID(TypedDict, total=False): run_id: Required[str] + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + JourneyCancelParams: TypeAlias = Union[ByCancelationToken, ByRunID] diff --git a/src/courier/types/journey_create_params.py b/src/courier/types/journey_create_params.py index c5326eef..bec2d0f0 100644 --- a/src/courier/types/journey_create_params.py +++ b/src/courier/types/journey_create_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import Iterable -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict +from .._utils import PropertyInfo from .journey_state import JourneyState __all__ = ["JourneyCreateParams"] @@ -20,5 +21,9 @@ class JourneyCreateParams(TypedDict, total=False): state: JourneyState """Lifecycle state of a journey.""" + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + from .journey_node_param import JourneyNodeParam diff --git a/src/courier/types/journey_invoke_params.py b/src/courier/types/journey_invoke_params.py index 07149e0a..bfc187e1 100644 --- a/src/courier/types/journey_invoke_params.py +++ b/src/courier/types/journey_invoke_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Dict -from typing_extensions import TypedDict +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["JourneyInvokeParams"] @@ -33,3 +35,7 @@ class JourneyInvokeParams(TypedDict, total=False): If not provided, the system will attempt to resolve the user identifier from profile or data objects. """ + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/journey_publish_params.py b/src/courier/types/journey_publish_params.py index 2c6fcb7f..c0f6b89c 100644 --- a/src/courier/types/journey_publish_params.py +++ b/src/courier/types/journey_publish_params.py @@ -2,10 +2,16 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["JourneyPublishParams"] class JourneyPublishParams(TypedDict, total=False): version: str + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/journeys/template_create_params.py b/src/courier/types/journeys/template_create_params.py index e3a4bb80..514816d7 100644 --- a/src/courier/types/journeys/template_create_params.py +++ b/src/courier/types/journeys/template_create_params.py @@ -27,6 +27,10 @@ class TemplateCreateParams(TypedDict, total=False): state: str + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + class NotificationBrand(TypedDict, total=False): id: Required[str] diff --git a/src/courier/types/journeys/template_publish_params.py b/src/courier/types/journeys/template_publish_params.py index efbfdd7a..2c9693e6 100644 --- a/src/courier/types/journeys/template_publish_params.py +++ b/src/courier/types/journeys/template_publish_params.py @@ -13,3 +13,7 @@ class TemplatePublishParams(TypedDict, total=False): template_id: Required[Annotated[str, PropertyInfo(alias="templateId")]] version: str + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/lists/subscription_add_params.py b/src/courier/types/lists/subscription_add_params.py index 3c695de0..46d79bbd 100644 --- a/src/courier/types/lists/subscription_add_params.py +++ b/src/courier/types/lists/subscription_add_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import Iterable -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict +from ..._utils import PropertyInfo from ..put_subscriptions_recipient_param import PutSubscriptionsRecipientParam __all__ = ["SubscriptionAddParams"] @@ -12,3 +13,7 @@ class SubscriptionAddParams(TypedDict, total=False): recipients: Required[Iterable[PutSubscriptionsRecipientParam]] + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/notification_create_params.py b/src/courier/types/notification_create_params.py index 242017c7..1fb8cff1 100644 --- a/src/courier/types/notification_create_params.py +++ b/src/courier/types/notification_create_params.py @@ -2,8 +2,9 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict +from .._utils import PropertyInfo from .notification_template_payload_param import NotificationTemplatePayloadParam __all__ = ["NotificationCreateParams"] @@ -22,3 +23,7 @@ class NotificationCreateParams(TypedDict, total=False): Case-insensitive input, normalized to uppercase in the response. Defaults to "DRAFT". """ + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/notification_publish_params.py b/src/courier/types/notification_publish_params.py index df41fc72..b5945921 100644 --- a/src/courier/types/notification_publish_params.py +++ b/src/courier/types/notification_publish_params.py @@ -2,7 +2,9 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["NotificationPublishParams"] @@ -10,3 +12,7 @@ class NotificationPublishParams(TypedDict, total=False): version: str """Historical version to publish (e.g. "v001"). Omit to publish the current draft.""" + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/profile_create_params.py b/src/courier/types/profile_create_params.py index e37d1735..939ebb1a 100644 --- a/src/courier/types/profile_create_params.py +++ b/src/courier/types/profile_create_params.py @@ -3,10 +3,16 @@ from __future__ import annotations from typing import Dict -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["ProfileCreateParams"] class ProfileCreateParams(TypedDict, total=False): profile: Required[Dict[str, object]] + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/profiles/list_subscribe_params.py b/src/courier/types/profiles/list_subscribe_params.py index 699069f3..2251c365 100644 --- a/src/courier/types/profiles/list_subscribe_params.py +++ b/src/courier/types/profiles/list_subscribe_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import Iterable -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict +from ..._utils import PropertyInfo from ..subscribe_to_lists_request_item_param import SubscribeToListsRequestItemParam __all__ = ["ListSubscribeParams"] @@ -12,3 +13,7 @@ class ListSubscribeParams(TypedDict, total=False): lists: Required[Iterable[SubscribeToListsRequestItemParam]] + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/provider_create_params.py b/src/courier/types/provider_create_params.py index 0f7642f0..687be93f 100644 --- a/src/courier/types/provider_create_params.py +++ b/src/courier/types/provider_create_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Dict -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["ProviderCreateParams"] @@ -29,3 +31,7 @@ class ProviderCreateParams(TypedDict, total=False): title: str """Optional display title. Omit to use "Default Configuration".""" + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/routing_strategy_create_params.py b/src/courier/types/routing_strategy_create_params.py index f62dfd5e..72a5e0df 100644 --- a/src/courier/types/routing_strategy_create_params.py +++ b/src/courier/types/routing_strategy_create_params.py @@ -3,9 +3,10 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict from .._types import SequenceNotStr +from .._utils import PropertyInfo from .shared_params.message_channels import MessageChannels from .shared_params.message_providers import MessageProviders @@ -31,5 +32,9 @@ class RoutingStrategyCreateParams(TypedDict, total=False): tags: Optional[SequenceNotStr[str]] """Optional tags for categorization.""" + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + from .shared_params.message_routing import MessageRouting diff --git a/src/courier/types/send_message_params.py b/src/courier/types/send_message_params.py index ad50e405..f365ac64 100644 --- a/src/courier/types/send_message_params.py +++ b/src/courier/types/send_message_params.py @@ -3,9 +3,10 @@ from __future__ import annotations from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict from .._types import SequenceNotStr +from .._utils import PropertyInfo from .shared_params.utm import Utm from .shared_params.list_recipient import ListRecipient from .shared_params.user_recipient import UserRecipient @@ -43,6 +44,10 @@ class SendMessageParams(TypedDict, total=False): They define the destination and content of the message. """ + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + MessageContent: TypeAlias = Union[ElementalContentSugar, ElementalContent] diff --git a/src/courier/types/users/preference_bulk_update_params.py b/src/courier/types/users/preference_bulk_update_params.py index 70f79640..0de00849 100644 --- a/src/courier/types/users/preference_bulk_update_params.py +++ b/src/courier/types/users/preference_bulk_update_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict +from ..._utils import PropertyInfo from ..shared.channel_classification import ChannelClassification __all__ = ["PreferenceBulkUpdateParams", "Topic"] @@ -20,6 +21,10 @@ class PreferenceBulkUpdateParams(TypedDict, total=False): tenant_id: Optional[str] """Update the preferences of a user for this specific tenant context.""" + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] + class Topic(TypedDict, total=False): status: Required[Literal["OPTED_IN", "OPTED_OUT"]] diff --git a/src/courier/types/workspace_preference_create_params.py b/src/courier/types/workspace_preference_create_params.py index 8f3367ca..c5dbbf10 100644 --- a/src/courier/types/workspace_preference_create_params.py +++ b/src/courier/types/workspace_preference_create_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import List, Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict +from .._utils import PropertyInfo from .shared.channel_classification import ChannelClassification __all__ = ["WorkspacePreferenceCreateParams"] @@ -22,3 +23,7 @@ class WorkspacePreferenceCreateParams(TypedDict, total=False): routing_options: Optional[List[ChannelClassification]] """Default channels for the workspace preference. Defaults to empty if omitted.""" + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/workspace_preference_publish_params.py b/src/courier/types/workspace_preference_publish_params.py index 180318c9..50e3b0fb 100644 --- a/src/courier/types/workspace_preference_publish_params.py +++ b/src/courier/types/workspace_preference_publish_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Optional -from typing_extensions import TypedDict +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["WorkspacePreferencePublishParams"] @@ -20,3 +22,7 @@ class WorkspacePreferencePublishParams(TypedDict, total=False): heading: Optional[str] """Heading shown at the top of the hosted preferences page.""" + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/src/courier/types/workspace_preferences/topic_create_params.py b/src/courier/types/workspace_preferences/topic_create_params.py index 698c9426..d6a926e3 100644 --- a/src/courier/types/workspace_preferences/topic_create_params.py +++ b/src/courier/types/workspace_preferences/topic_create_params.py @@ -3,8 +3,9 @@ from __future__ import annotations from typing import Dict, List, Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict +from ..._utils import PropertyInfo from ..shared.channel_classification import ChannelClassification __all__ = ["TopicCreateParams"] @@ -34,3 +35,7 @@ class TopicCreateParams(TypedDict, total=False): topic_data: Optional[Dict[str, object]] """Arbitrary metadata associated with the topic.""" + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + x_idempotency_expiration: Annotated[str, PropertyInfo(alias="x-idempotency-expiration")] diff --git a/tests/api_resources/automations/test_invoke.py b/tests/api_resources/automations/test_invoke.py index 081b6009..a2fd132a 100644 --- a/tests/api_resources/automations/test_invoke.py +++ b/tests/api_resources/automations/test_invoke.py @@ -52,6 +52,8 @@ def test_method_invoke_ad_hoc_with_all_params(self, client: Courier) -> None: profile={"tenant_id": "bar"}, recipient="user-yes", template="template", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(AutomationInvokeResponse, invoke, path=["response"]) @@ -100,6 +102,8 @@ def test_method_invoke_by_template_with_all_params(self, client: Courier) -> Non data={"foo": "bar"}, profile={"foo": "bar"}, template="template", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(AutomationInvokeResponse, invoke, path=["response"]) @@ -181,6 +185,8 @@ async def test_method_invoke_ad_hoc_with_all_params(self, async_client: AsyncCou profile={"tenant_id": "bar"}, recipient="user-yes", template="template", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(AutomationInvokeResponse, invoke, path=["response"]) @@ -229,6 +235,8 @@ async def test_method_invoke_by_template_with_all_params(self, async_client: Asy data={"foo": "bar"}, profile={"foo": "bar"}, template="template", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(AutomationInvokeResponse, invoke, path=["response"]) diff --git a/tests/api_resources/journeys/test_templates.py b/tests/api_resources/journeys/test_templates.py index 80149a4b..bde3602b 100644 --- a/tests/api_resources/journeys/test_templates.py +++ b/tests/api_resources/journeys/test_templates.py @@ -69,6 +69,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: }, provider_key="x", state="state", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneyTemplateGetResponse, template, path=["response"]) @@ -363,6 +365,8 @@ def test_method_publish_with_all_params(self, client: Courier) -> None: notification_id="x", template_id="x", version="v321669910225", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert template is None @@ -807,6 +811,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - }, provider_key="x", state="state", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneyTemplateGetResponse, template, path=["response"]) @@ -1101,6 +1107,8 @@ async def test_method_publish_with_all_params(self, async_client: AsyncCourier) notification_id="x", template_id="x", version="v321669910225", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert template is None diff --git a/tests/api_resources/lists/test_subscriptions.py b/tests/api_resources/lists/test_subscriptions.py index ee6936d2..b51d1e4b 100644 --- a/tests/api_resources/lists/test_subscriptions.py +++ b/tests/api_resources/lists/test_subscriptions.py @@ -79,6 +79,47 @@ def test_method_add(self, client: Courier) -> None: ) assert subscription is None + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_add_with_all_params(self, client: Courier) -> None: + subscription = client.lists.subscriptions.add( + list_id="list_id", + recipients=[ + { + "recipient_id": "recipientId", + "preferences": { + "categories": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + "notifications": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + }, + } + ], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert subscription is None + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_add(self, client: Courier) -> None: @@ -367,6 +408,47 @@ async def test_method_add(self, async_client: AsyncCourier) -> None: ) assert subscription is None + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_add_with_all_params(self, async_client: AsyncCourier) -> None: + subscription = await async_client.lists.subscriptions.add( + list_id="list_id", + recipients=[ + { + "recipient_id": "recipientId", + "preferences": { + "categories": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + "notifications": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + }, + } + ], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert subscription is None + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_add(self, async_client: AsyncCourier) -> None: diff --git a/tests/api_resources/profiles/test_lists.py b/tests/api_resources/profiles/test_lists.py index 83aeb961..d7458b67 100644 --- a/tests/api_resources/profiles/test_lists.py +++ b/tests/api_resources/profiles/test_lists.py @@ -123,6 +123,47 @@ def test_method_subscribe(self, client: Courier) -> None: ) assert_matches_type(ListSubscribeResponse, list_, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_subscribe_with_all_params(self, client: Courier) -> None: + list_ = client.profiles.lists.subscribe( + user_id="user_id", + lists=[ + { + "list_id": "listId", + "preferences": { + "categories": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + "notifications": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + }, + } + ], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(ListSubscribeResponse, list_, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_subscribe(self, client: Courier) -> None: @@ -268,6 +309,47 @@ async def test_method_subscribe(self, async_client: AsyncCourier) -> None: ) assert_matches_type(ListSubscribeResponse, list_, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_subscribe_with_all_params(self, async_client: AsyncCourier) -> None: + list_ = await async_client.profiles.lists.subscribe( + user_id="user_id", + lists=[ + { + "list_id": "listId", + "preferences": { + "categories": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + "notifications": { + "foo": { + "status": "OPTED_IN", + "channel_preferences": [{"channel": "direct_message"}], + "rules": [ + { + "until": "until", + "start": "start", + } + ], + } + }, + }, + } + ], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(ListSubscribeResponse, list_, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_subscribe(self, async_client: AsyncCourier) -> None: diff --git a/tests/api_resources/test_brands.py b/tests/api_resources/test_brands.py index 118bfaf0..dd548d5c 100644 --- a/tests/api_resources/test_brands.py +++ b/tests/api_resources/test_brands.py @@ -105,6 +105,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: } ] }, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(Brand, brand, path=["response"]) @@ -472,6 +474,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - } ] }, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(Brand, brand, path=["response"]) diff --git a/tests/api_resources/test_journeys.py b/tests/api_resources/test_journeys.py index 22962b21..3b1c49d4 100644 --- a/tests/api_resources/test_journeys.py +++ b/tests/api_resources/test_journeys.py @@ -64,6 +64,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: ], enabled=True, state="DRAFT", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneyResponse, journey, path=["response"]) @@ -251,6 +253,16 @@ def test_method_cancel_overload_1(self, client: Courier) -> None: ) assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_cancel_with_all_params_overload_1(self, client: Courier) -> None: + journey = client.journeys.cancel( + cancelation_token="x", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_cancel_overload_1(self, client: Courier) -> None: @@ -285,6 +297,16 @@ def test_method_cancel_overload_2(self, client: Courier) -> None: ) assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_cancel_with_all_params_overload_2(self, client: Courier) -> None: + journey = client.journeys.cancel( + run_id="x", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_cancel_overload_2(self, client: Courier) -> None: @@ -330,6 +352,8 @@ def test_method_invoke_with_all_params(self, client: Courier) -> None: }, profile={"foo": "bar"}, user_id="user-123", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneysInvokeResponse, journey, path=["response"]) @@ -423,6 +447,8 @@ def test_method_publish_with_all_params(self, client: Courier) -> None: journey = client.journeys.publish( template_id="x", version="v321669910225", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneyResponse, journey, path=["response"]) @@ -597,6 +623,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - ], enabled=True, state="DRAFT", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneyResponse, journey, path=["response"]) @@ -784,6 +812,16 @@ async def test_method_cancel_overload_1(self, async_client: AsyncCourier) -> Non ) assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_cancel_with_all_params_overload_1(self, async_client: AsyncCourier) -> None: + journey = await async_client.journeys.cancel( + cancelation_token="x", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_cancel_overload_1(self, async_client: AsyncCourier) -> None: @@ -818,6 +856,16 @@ async def test_method_cancel_overload_2(self, async_client: AsyncCourier) -> Non ) assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_cancel_with_all_params_overload_2(self, async_client: AsyncCourier) -> None: + journey = await async_client.journeys.cancel( + run_id="x", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(CancelJourneyResponse, journey, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_cancel_overload_2(self, async_client: AsyncCourier) -> None: @@ -863,6 +911,8 @@ async def test_method_invoke_with_all_params(self, async_client: AsyncCourier) - }, profile={"foo": "bar"}, user_id="user-123", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneysInvokeResponse, journey, path=["response"]) @@ -956,6 +1006,8 @@ async def test_method_publish_with_all_params(self, async_client: AsyncCourier) journey = await async_client.journeys.publish( template_id="x", version="v321669910225", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(JourneyResponse, journey, path=["response"]) diff --git a/tests/api_resources/test_notifications.py b/tests/api_resources/test_notifications.py index e4c9a1f9..db8f81e6 100644 --- a/tests/api_resources/test_notifications.py +++ b/tests/api_resources/test_notifications.py @@ -57,6 +57,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: "tags": ["onboarding", "welcome"], }, state="DRAFT", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(NotificationTemplateResponse, notification, path=["response"]) @@ -345,6 +347,8 @@ def test_method_publish_with_all_params(self, client: Courier) -> None: notification = client.notifications.publish( id="id", version="v321669910225", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert notification is None @@ -779,6 +783,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - "tags": ["onboarding", "welcome"], }, state="DRAFT", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(NotificationTemplateResponse, notification, path=["response"]) @@ -1067,6 +1073,8 @@ async def test_method_publish_with_all_params(self, async_client: AsyncCourier) notification = await async_client.notifications.publish( id="id", version="v321669910225", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert notification is None diff --git a/tests/api_resources/test_profiles.py b/tests/api_resources/test_profiles.py index a3859583..b90cb5f0 100644 --- a/tests/api_resources/test_profiles.py +++ b/tests/api_resources/test_profiles.py @@ -30,6 +30,17 @@ def test_method_create(self, client: Courier) -> None: ) assert_matches_type(ProfileCreateResponse, profile, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Courier) -> None: + profile = client.profiles.create( + user_id="user_id", + profile={"foo": "bar"}, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(ProfileCreateResponse, profile, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_create(self, client: Courier) -> None: @@ -282,6 +293,17 @@ async def test_method_create(self, async_client: AsyncCourier) -> None: ) assert_matches_type(ProfileCreateResponse, profile, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCourier) -> None: + profile = await async_client.profiles.create( + user_id="user_id", + profile={"foo": "bar"}, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", + ) + assert_matches_type(ProfileCreateResponse, profile, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_create(self, async_client: AsyncCourier) -> None: diff --git a/tests/api_resources/test_providers.py b/tests/api_resources/test_providers.py index 5915dced..10e8d743 100644 --- a/tests/api_resources/test_providers.py +++ b/tests/api_resources/test_providers.py @@ -36,6 +36,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: alias="alias", settings={"foo": "bar"}, title="title", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(Provider, provider, path=["response"]) @@ -265,6 +267,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - alias="alias", settings={"foo": "bar"}, title="title", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(Provider, provider, path=["response"]) diff --git a/tests/api_resources/test_routing_strategies.py b/tests/api_resources/test_routing_strategies.py index 8d314b65..2a19e86e 100644 --- a/tests/api_resources/test_routing_strategies.py +++ b/tests/api_resources/test_routing_strategies.py @@ -82,6 +82,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: } }, tags=["production", "email"], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(RoutingStrategyGetResponse, routing_strategy, path=["response"]) @@ -474,6 +476,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - } }, tags=["production", "email"], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(RoutingStrategyGetResponse, routing_strategy, path=["response"]) diff --git a/tests/api_resources/test_send.py b/tests/api_resources/test_send.py index 81bb3fad..7f92c54c 100644 --- a/tests/api_resources/test_send.py +++ b/tests/api_resources/test_send.py @@ -150,6 +150,8 @@ def test_method_message_with_all_params(self, client: Courier) -> None: "user_id": "user_id", }, }, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(SendMessageResponse, send, path=["response"]) @@ -318,6 +320,8 @@ async def test_method_message_with_all_params(self, async_client: AsyncCourier) "user_id": "user_id", }, }, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(SendMessageResponse, send, path=["response"]) diff --git a/tests/api_resources/test_workspace_preferences.py b/tests/api_resources/test_workspace_preferences.py index 791e1667..b3802b5e 100644 --- a/tests/api_resources/test_workspace_preferences.py +++ b/tests/api_resources/test_workspace_preferences.py @@ -37,6 +37,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: description="description", has_custom_routing=True, routing_options=["direct_message"], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(WorkspacePreferenceGetResponse, workspace_preference, path=["response"]) @@ -191,6 +193,8 @@ def test_method_publish_with_all_params(self, client: Courier) -> None: brand_id="brand_id", description="description", heading="heading", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(PublishPreferencesResponse, workspace_preference, path=["response"]) @@ -296,6 +300,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - description="description", has_custom_routing=True, routing_options=["direct_message"], + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(WorkspacePreferenceGetResponse, workspace_preference, path=["response"]) @@ -450,6 +456,8 @@ async def test_method_publish_with_all_params(self, async_client: AsyncCourier) brand_id="brand_id", description="description", heading="heading", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(PublishPreferencesResponse, workspace_preference, path=["response"]) diff --git a/tests/api_resources/users/test_preferences.py b/tests/api_resources/users/test_preferences.py index 8d96730e..f791c4f5 100644 --- a/tests/api_resources/users/test_preferences.py +++ b/tests/api_resources/users/test_preferences.py @@ -195,6 +195,8 @@ def test_method_bulk_update_with_all_params(self, client: Courier) -> None: }, ], tenant_id="tenant_id", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(PreferenceBulkUpdateResponse, preference, path=["response"]) @@ -636,6 +638,8 @@ async def test_method_bulk_update_with_all_params(self, async_client: AsyncCouri }, ], tenant_id="tenant_id", + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(PreferenceBulkUpdateResponse, preference, path=["response"]) diff --git a/tests/api_resources/workspace_preferences/test_topics.py b/tests/api_resources/workspace_preferences/test_topics.py index 5647167b..0d6e92de 100644 --- a/tests/api_resources/workspace_preferences/test_topics.py +++ b/tests/api_resources/workspace_preferences/test_topics.py @@ -39,6 +39,8 @@ def test_method_create_with_all_params(self, client: Courier) -> None: include_unsubscribe_header=True, routing_options=["direct_message"], topic_data={"foo": "bar"}, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(WorkspacePreferenceTopicGetResponse, topic, path=["response"]) @@ -334,6 +336,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncCourier) - include_unsubscribe_header=True, routing_options=["direct_message"], topic_data={"foo": "bar"}, + idempotency_key="order-ORD-456-user-123", + x_idempotency_expiration="1785312000", ) assert_matches_type(WorkspacePreferenceTopicGetResponse, topic, path=["response"]) From 6e32a5cb55d541ba89ac260aa62fa0d1d40505d9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:32:34 +0000 Subject: [PATCH 4/6] feat: Document DELETE/PUT restore for inbox messages (C-19268) (#175) Adds the public REST endpoints for the new backend inbox delete feature: - DELETE /inbox/messages/{message_id} - PUT /inbox/messages/{message_id}/restore New `inbox.messages` resource in stainless.yml (delete + restore) so the methods generate across the SDKs. Pairs with trycourier/backend#9759. Co-authored-by: Claude Opus 4.8 --- .stats.yml | 8 +- api.md | 9 + src/courier/_client.py | 38 ++++ src/courier/resources/__init__.py | 14 ++ src/courier/resources/inbox/__init__.py | 33 +++ src/courier/resources/inbox/inbox.py | 102 +++++++++ src/courier/resources/inbox/messages.py | 249 +++++++++++++++++++++ src/courier/types/inbox/__init__.py | 3 + tests/api_resources/inbox/__init__.py | 1 + tests/api_resources/inbox/test_messages.py | 190 ++++++++++++++++ 10 files changed, 643 insertions(+), 4 deletions(-) create mode 100644 src/courier/resources/inbox/__init__.py create mode 100644 src/courier/resources/inbox/inbox.py create mode 100644 src/courier/resources/inbox/messages.py create mode 100644 src/courier/types/inbox/__init__.py create mode 100644 tests/api_resources/inbox/__init__.py create mode 100644 tests/api_resources/inbox/test_messages.py diff --git a/.stats.yml b/.stats.yml index a6b7b828..91c3ad3d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 134 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-0319162d68adb4d442698563aee11cce71cc310b70cbbe908b16287934ffc548.yml -openapi_spec_hash: 729cfea83369faf0261496c24692dce8 -config_hash: 8d28dbeabe9d4dcc7d5b8c021a4cbbd7 +configured_endpoints: 136 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-e0b0d58ce19411b3126e6d5cb0f9ae93061e2ec859aae4ec17a15f80dc74cd04.yml +openapi_spec_hash: 38d1ecc4bd77bb5245afe86f2d8ffb48 +config_hash: b30c4b3086cd9f3da06a63b256d8c189 diff --git a/api.md b/api.md index 160903ed..17836458 100644 --- a/api.md +++ b/api.md @@ -355,6 +355,15 @@ Methods: - client.lists.subscriptions.subscribe_user(user_id, \*, list_id, \*\*params) -> None - client.lists.subscriptions.unsubscribe_user(user_id, \*, list_id) -> None +# Inbox + +## Messages + +Methods: + +- client.inbox.messages.delete(message_id) -> None +- client.inbox.messages.restore(message_id) -> None + # Messages Types: diff --git a/src/courier/_client.py b/src/courier/_client.py index 8ab22078..64690146 100644 --- a/src/courier/_client.py +++ b/src/courier/_client.py @@ -38,6 +38,7 @@ from .resources import ( auth, send, + inbox, lists, users, brands, @@ -64,6 +65,7 @@ from .resources.messages import MessagesResource, AsyncMessagesResource from .resources.requests import RequestsResource, AsyncRequestsResource from .resources.audiences import AudiencesResource, AsyncAudiencesResource + from .resources.inbox.inbox import InboxResource, AsyncInboxResource from .resources.lists.lists import ListsResource, AsyncListsResource from .resources.users.users import UsersResource, AsyncUsersResource from .resources.audit_events import AuditEventsResource, AsyncAuditEventsResource @@ -214,6 +216,12 @@ def lists(self) -> ListsResource: return ListsResource(self) + @cached_property + def inbox(self) -> InboxResource: + from .resources.inbox import InboxResource + + return InboxResource(self) + @cached_property def messages(self) -> MessagesResource: from .resources.messages import MessagesResource @@ -511,6 +519,12 @@ def lists(self) -> AsyncListsResource: return AsyncListsResource(self) + @cached_property + def inbox(self) -> AsyncInboxResource: + from .resources.inbox import AsyncInboxResource + + return AsyncInboxResource(self) + @cached_property def messages(self) -> AsyncMessagesResource: from .resources.messages import AsyncMessagesResource @@ -750,6 +764,12 @@ def lists(self) -> lists.ListsResourceWithRawResponse: return ListsResourceWithRawResponse(self._client.lists) + @cached_property + def inbox(self) -> inbox.InboxResourceWithRawResponse: + from .resources.inbox import InboxResourceWithRawResponse + + return InboxResourceWithRawResponse(self._client.inbox) + @cached_property def messages(self) -> messages.MessagesResourceWithRawResponse: from .resources.messages import MessagesResourceWithRawResponse @@ -877,6 +897,12 @@ def lists(self) -> lists.AsyncListsResourceWithRawResponse: return AsyncListsResourceWithRawResponse(self._client.lists) + @cached_property + def inbox(self) -> inbox.AsyncInboxResourceWithRawResponse: + from .resources.inbox import AsyncInboxResourceWithRawResponse + + return AsyncInboxResourceWithRawResponse(self._client.inbox) + @cached_property def messages(self) -> messages.AsyncMessagesResourceWithRawResponse: from .resources.messages import AsyncMessagesResourceWithRawResponse @@ -1004,6 +1030,12 @@ def lists(self) -> lists.ListsResourceWithStreamingResponse: return ListsResourceWithStreamingResponse(self._client.lists) + @cached_property + def inbox(self) -> inbox.InboxResourceWithStreamingResponse: + from .resources.inbox import InboxResourceWithStreamingResponse + + return InboxResourceWithStreamingResponse(self._client.inbox) + @cached_property def messages(self) -> messages.MessagesResourceWithStreamingResponse: from .resources.messages import MessagesResourceWithStreamingResponse @@ -1131,6 +1163,12 @@ def lists(self) -> lists.AsyncListsResourceWithStreamingResponse: return AsyncListsResourceWithStreamingResponse(self._client.lists) + @cached_property + def inbox(self) -> inbox.AsyncInboxResourceWithStreamingResponse: + from .resources.inbox import AsyncInboxResourceWithStreamingResponse + + return AsyncInboxResourceWithStreamingResponse(self._client.inbox) + @cached_property def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse: from .resources.messages import AsyncMessagesResourceWithStreamingResponse diff --git a/src/courier/resources/__init__.py b/src/courier/resources/__init__.py index 625b8b1d..3c433ca9 100644 --- a/src/courier/resources/__init__.py +++ b/src/courier/resources/__init__.py @@ -16,6 +16,14 @@ SendResourceWithStreamingResponse, AsyncSendResourceWithStreamingResponse, ) +from .inbox import ( + InboxResource, + AsyncInboxResource, + InboxResourceWithRawResponse, + AsyncInboxResourceWithRawResponse, + InboxResourceWithStreamingResponse, + AsyncInboxResourceWithStreamingResponse, +) from .lists import ( ListsResource, AsyncListsResource, @@ -228,6 +236,12 @@ "AsyncListsResourceWithRawResponse", "ListsResourceWithStreamingResponse", "AsyncListsResourceWithStreamingResponse", + "InboxResource", + "AsyncInboxResource", + "InboxResourceWithRawResponse", + "AsyncInboxResourceWithRawResponse", + "InboxResourceWithStreamingResponse", + "AsyncInboxResourceWithStreamingResponse", "MessagesResource", "AsyncMessagesResource", "MessagesResourceWithRawResponse", diff --git a/src/courier/resources/inbox/__init__.py b/src/courier/resources/inbox/__init__.py new file mode 100644 index 00000000..13574c16 --- /dev/null +++ b/src/courier/resources/inbox/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .inbox import ( + InboxResource, + AsyncInboxResource, + InboxResourceWithRawResponse, + AsyncInboxResourceWithRawResponse, + InboxResourceWithStreamingResponse, + AsyncInboxResourceWithStreamingResponse, +) +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) + +__all__ = [ + "MessagesResource", + "AsyncMessagesResource", + "MessagesResourceWithRawResponse", + "AsyncMessagesResourceWithRawResponse", + "MessagesResourceWithStreamingResponse", + "AsyncMessagesResourceWithStreamingResponse", + "InboxResource", + "AsyncInboxResource", + "InboxResourceWithRawResponse", + "AsyncInboxResourceWithRawResponse", + "InboxResourceWithStreamingResponse", + "AsyncInboxResourceWithStreamingResponse", +] diff --git a/src/courier/resources/inbox/inbox.py b/src/courier/resources/inbox/inbox.py new file mode 100644 index 00000000..b132aff0 --- /dev/null +++ b/src/courier/resources/inbox/inbox.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["InboxResource", "AsyncInboxResource"] + + +class InboxResource(SyncAPIResource): + @cached_property + def messages(self) -> MessagesResource: + return MessagesResource(self._client) + + @cached_property + def with_raw_response(self) -> InboxResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return InboxResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InboxResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return InboxResourceWithStreamingResponse(self) + + +class AsyncInboxResource(AsyncAPIResource): + @cached_property + def messages(self) -> AsyncMessagesResource: + return AsyncMessagesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncInboxResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return AsyncInboxResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInboxResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return AsyncInboxResourceWithStreamingResponse(self) + + +class InboxResourceWithRawResponse: + def __init__(self, inbox: InboxResource) -> None: + self._inbox = inbox + + @cached_property + def messages(self) -> MessagesResourceWithRawResponse: + return MessagesResourceWithRawResponse(self._inbox.messages) + + +class AsyncInboxResourceWithRawResponse: + def __init__(self, inbox: AsyncInboxResource) -> None: + self._inbox = inbox + + @cached_property + def messages(self) -> AsyncMessagesResourceWithRawResponse: + return AsyncMessagesResourceWithRawResponse(self._inbox.messages) + + +class InboxResourceWithStreamingResponse: + def __init__(self, inbox: InboxResource) -> None: + self._inbox = inbox + + @cached_property + def messages(self) -> MessagesResourceWithStreamingResponse: + return MessagesResourceWithStreamingResponse(self._inbox.messages) + + +class AsyncInboxResourceWithStreamingResponse: + def __init__(self, inbox: AsyncInboxResource) -> None: + self._inbox = inbox + + @cached_property + def messages(self) -> AsyncMessagesResourceWithStreamingResponse: + return AsyncMessagesResourceWithStreamingResponse(self._inbox.messages) diff --git a/src/courier/resources/inbox/messages.py b/src/courier/resources/inbox/messages.py new file mode 100644 index 00000000..ee4c03ed --- /dev/null +++ b/src/courier/resources/inbox/messages.py @@ -0,0 +1,249 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ..._utils import path_template +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options + +__all__ = ["MessagesResource", "AsyncMessagesResource"] + + +class MessagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MessagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return MessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MessagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return MessagesResourceWithStreamingResponse(self) + + def delete( + self, + message_id: 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. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete a user's inbox message. + + The message is removed from every inbox read (it + stops appearing in the recipient's Inbox); it can be restored. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not message_id: + raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/inbox/messages/{message_id}", message_id=message_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def restore( + self, + message_id: 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. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Restore a previously deleted inbox message. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not message_id: + raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._put( + path_template("/inbox/messages/{message_id}/restore", message_id=message_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncMessagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return AsyncMessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return AsyncMessagesResourceWithStreamingResponse(self) + + async def delete( + self, + message_id: 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. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete a user's inbox message. + + The message is removed from every inbox read (it + stops appearing in the recipient's Inbox); it can be restored. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not message_id: + raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/inbox/messages/{message_id}", message_id=message_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def restore( + self, + message_id: 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. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Restore a previously deleted inbox message. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not message_id: + raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._put( + path_template("/inbox/messages/{message_id}/restore", message_id=message_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class MessagesResourceWithRawResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.delete = to_raw_response_wrapper( + messages.delete, + ) + self.restore = to_raw_response_wrapper( + messages.restore, + ) + + +class AsyncMessagesResourceWithRawResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.delete = async_to_raw_response_wrapper( + messages.delete, + ) + self.restore = async_to_raw_response_wrapper( + messages.restore, + ) + + +class MessagesResourceWithStreamingResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.delete = to_streamed_response_wrapper( + messages.delete, + ) + self.restore = to_streamed_response_wrapper( + messages.restore, + ) + + +class AsyncMessagesResourceWithStreamingResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.delete = async_to_streamed_response_wrapper( + messages.delete, + ) + self.restore = async_to_streamed_response_wrapper( + messages.restore, + ) diff --git a/src/courier/types/inbox/__init__.py b/src/courier/types/inbox/__init__.py new file mode 100644 index 00000000..f8ee8b14 --- /dev/null +++ b/src/courier/types/inbox/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/tests/api_resources/inbox/__init__.py b/tests/api_resources/inbox/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/inbox/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/inbox/test_messages.py b/tests/api_resources/inbox/test_messages.py new file mode 100644 index 00000000..129fbfe4 --- /dev/null +++ b/tests/api_resources/inbox/test_messages.py @@ -0,0 +1,190 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from courier import Courier, AsyncCourier + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMessages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Courier) -> None: + message = client.inbox.messages.delete( + "message_id", + ) + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Courier) -> None: + response = client.inbox.messages.with_raw_response.delete( + "message_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Courier) -> None: + with client.inbox.messages.with_streaming_response.delete( + "message_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert message is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + client.inbox.messages.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_restore(self, client: Courier) -> None: + message = client.inbox.messages.restore( + "message_id", + ) + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_restore(self, client: Courier) -> None: + response = client.inbox.messages.with_raw_response.restore( + "message_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_restore(self, client: Courier) -> None: + with client.inbox.messages.with_streaming_response.restore( + "message_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert message is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_restore(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + client.inbox.messages.with_raw_response.restore( + "", + ) + + +class TestAsyncMessages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncCourier) -> None: + message = await async_client.inbox.messages.delete( + "message_id", + ) + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCourier) -> None: + response = await async_client.inbox.messages.with_raw_response.delete( + "message_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = await response.parse() + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCourier) -> None: + async with async_client.inbox.messages.with_streaming_response.delete( + "message_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert message is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + await async_client.inbox.messages.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_restore(self, async_client: AsyncCourier) -> None: + message = await async_client.inbox.messages.restore( + "message_id", + ) + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_restore(self, async_client: AsyncCourier) -> None: + response = await async_client.inbox.messages.with_raw_response.restore( + "message_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = await response.parse() + assert message is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_restore(self, async_client: AsyncCourier) -> None: + async with async_client.inbox.messages.with_streaming_response.restore( + "message_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert message is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_restore(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + await async_client.inbox.messages.with_raw_response.restore( + "", + ) From 742efe6045de6ae33afeb780205ea7010d93a98b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:17:53 +0000 Subject: [PATCH 5/6] feat: spec: rename and reorder the API reference sections (#179) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a top-level `tags:` array that defines the section order and gives each section a description, renames 7 sections, and reorders the `paths:` blocks so document order matches — with a `# ---- Section ----` banner per group. New order follows the docs IA: auth -> send -> inspect -> content -> recipients -> preferences -> multi-tenancy -> orchestration -> in-app -> workspace config. Renames: Sent Messages -> Messages Notification Templates -> Templates User Profiles -> Profiles Workspace Preferences -> Preference Topics User Tenants -> Tenant Memberships Courier Create -> Tenant Templates Inbound -> Track Events Also corrects 6 operation summaries inside renamed groups that named the old section: the five `/preferences/sections` operations manage preference sections (not "workspace preferences"), and `/inbound/courier` is now "Track an event". No request/response schema, path, or operationId changes — verified by structural diff of the parsed spec. Co-authored-by: Claude Opus 5 (1M context) --- .stats.yml | 4 +- src/courier/_client.py | 312 ++++++++++++++++++ src/courier/resources/audiences.py | 8 + src/courier/resources/audit_events.py | 4 + src/courier/resources/auth.py | 8 + .../resources/automations/automations.py | 26 ++ src/courier/resources/automations/invoke.py | 8 + src/courier/resources/brands.py | 8 + src/courier/resources/digests/digests.py | 18 + src/courier/resources/digests/schedules.py | 8 + src/courier/resources/inbound.py | 8 + src/courier/resources/inbox/inbox.py | 6 + src/courier/resources/inbox/messages.py | 4 + src/courier/resources/journeys/journeys.py | 26 ++ src/courier/resources/journeys/templates.py | 8 + src/courier/resources/lists/lists.py | 26 ++ src/courier/resources/lists/subscriptions.py | 8 + src/courier/resources/messages.py | 8 + src/courier/resources/notifications/checks.py | 8 + .../resources/notifications/notifications.py | 26 ++ src/courier/resources/profiles/lists.py | 8 + src/courier/resources/profiles/profiles.py | 26 ++ src/courier/resources/providers/catalog.py | 8 + src/courier/resources/providers/providers.py | 26 ++ src/courier/resources/requests.py | 8 + src/courier/resources/routing_strategies.py | 8 + src/courier/resources/send.py | 8 + .../resources/tenants/preferences/items.py | 8 + .../tenants/preferences/preferences.py | 18 + .../resources/tenants/templates/templates.py | 26 ++ .../resources/tenants/templates/versions.py | 8 + src/courier/resources/tenants/tenants.py | 26 ++ src/courier/resources/translations.py | 8 + src/courier/resources/users/preferences.py | 8 + src/courier/resources/users/tenants.py | 8 + src/courier/resources/users/tokens.py | 8 + src/courier/resources/users/users.py | 54 +++ .../resources/workspace_preferences/topics.py | 8 + .../workspace_preferences.py | 26 ++ 39 files changed, 828 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 91c3ad3d..cf69b295 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-e0b0d58ce19411b3126e6d5cb0f9ae93061e2ec859aae4ec17a15f80dc74cd04.yml -openapi_spec_hash: 38d1ecc4bd77bb5245afe86f2d8ffb48 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-47bd7f89519b4aa68b039b9a03888b689fac9d6ee763d26be0b267bbb0b2ddaa.yml +openapi_spec_hash: 67ff63b23cbfb19beac58d6e471836d3 config_hash: b30c4b3086cd9f3da06a63b256d8c189 diff --git a/src/courier/_client.py b/src/courier/_client.py index 64690146..1e024eb6 100644 --- a/src/courier/_client.py +++ b/src/courier/_client.py @@ -152,48 +152,70 @@ def __init__( @cached_property def send(self) -> SendResource: + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ from .resources.send import SendResource return SendResource(self) @cached_property def audiences(self) -> AudiencesResource: + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ from .resources.audiences import AudiencesResource return AudiencesResource(self) @cached_property def providers(self) -> ProvidersResource: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ from .resources.providers import ProvidersResource return ProvidersResource(self) @cached_property def audit_events(self) -> AuditEventsResource: + """Read the audit trail of configuration and access changes in your workspace.""" from .resources.audit_events import AuditEventsResource return AuditEventsResource(self) @cached_property def auth(self) -> AuthResource: + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ from .resources.auth import AuthResource return AuthResource(self) @cached_property def automations(self) -> AutomationsResource: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ from .resources.automations import AutomationsResource return AutomationsResource(self) @cached_property def journeys(self) -> JourneysResource: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ from .resources.journeys import JourneysResource return JourneysResource(self) @cached_property def brands(self) -> BrandsResource: + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ from .resources.brands import BrandsResource return BrandsResource(self) @@ -206,12 +228,18 @@ def digests(self) -> DigestsResource: @cached_property def inbound(self) -> InboundResource: + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ from .resources.inbound import InboundResource return InboundResource(self) @cached_property def lists(self) -> ListsResource: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ from .resources.lists import ListsResource return ListsResource(self) @@ -224,48 +252,72 @@ def inbox(self) -> InboxResource: @cached_property def messages(self) -> MessagesResource: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.messages import MessagesResource return MessagesResource(self) @cached_property def requests(self) -> RequestsResource: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.requests import RequestsResource return RequestsResource(self) @cached_property def notifications(self) -> NotificationsResource: + """ + Create, update, version, publish, and localize notification templates and their content. + """ from .resources.notifications import NotificationsResource return NotificationsResource(self) @cached_property def routing_strategies(self) -> RoutingStrategiesResource: + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ from .resources.routing_strategies import RoutingStrategiesResource return RoutingStrategiesResource(self) @cached_property def workspace_preferences(self) -> WorkspacePreferencesResource: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ from .resources.workspace_preferences import WorkspacePreferencesResource return WorkspacePreferencesResource(self) @cached_property def profiles(self) -> ProfilesResource: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ from .resources.profiles import ProfilesResource return ProfilesResource(self) @cached_property def tenants(self) -> TenantsResource: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ from .resources.tenants import TenantsResource return TenantsResource(self) @cached_property def translations(self) -> TranslationsResource: + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ from .resources.translations import TranslationsResource return TranslationsResource(self) @@ -455,48 +507,70 @@ def __init__( @cached_property def send(self) -> AsyncSendResource: + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ from .resources.send import AsyncSendResource return AsyncSendResource(self) @cached_property def audiences(self) -> AsyncAudiencesResource: + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ from .resources.audiences import AsyncAudiencesResource return AsyncAudiencesResource(self) @cached_property def providers(self) -> AsyncProvidersResource: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ from .resources.providers import AsyncProvidersResource return AsyncProvidersResource(self) @cached_property def audit_events(self) -> AsyncAuditEventsResource: + """Read the audit trail of configuration and access changes in your workspace.""" from .resources.audit_events import AsyncAuditEventsResource return AsyncAuditEventsResource(self) @cached_property def auth(self) -> AsyncAuthResource: + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ from .resources.auth import AsyncAuthResource return AsyncAuthResource(self) @cached_property def automations(self) -> AsyncAutomationsResource: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ from .resources.automations import AsyncAutomationsResource return AsyncAutomationsResource(self) @cached_property def journeys(self) -> AsyncJourneysResource: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ from .resources.journeys import AsyncJourneysResource return AsyncJourneysResource(self) @cached_property def brands(self) -> AsyncBrandsResource: + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ from .resources.brands import AsyncBrandsResource return AsyncBrandsResource(self) @@ -509,12 +583,18 @@ def digests(self) -> AsyncDigestsResource: @cached_property def inbound(self) -> AsyncInboundResource: + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ from .resources.inbound import AsyncInboundResource return AsyncInboundResource(self) @cached_property def lists(self) -> AsyncListsResource: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ from .resources.lists import AsyncListsResource return AsyncListsResource(self) @@ -527,48 +607,72 @@ def inbox(self) -> AsyncInboxResource: @cached_property def messages(self) -> AsyncMessagesResource: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.messages import AsyncMessagesResource return AsyncMessagesResource(self) @cached_property def requests(self) -> AsyncRequestsResource: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.requests import AsyncRequestsResource return AsyncRequestsResource(self) @cached_property def notifications(self) -> AsyncNotificationsResource: + """ + Create, update, version, publish, and localize notification templates and their content. + """ from .resources.notifications import AsyncNotificationsResource return AsyncNotificationsResource(self) @cached_property def routing_strategies(self) -> AsyncRoutingStrategiesResource: + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ from .resources.routing_strategies import AsyncRoutingStrategiesResource return AsyncRoutingStrategiesResource(self) @cached_property def workspace_preferences(self) -> AsyncWorkspacePreferencesResource: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ from .resources.workspace_preferences import AsyncWorkspacePreferencesResource return AsyncWorkspacePreferencesResource(self) @cached_property def profiles(self) -> AsyncProfilesResource: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ from .resources.profiles import AsyncProfilesResource return AsyncProfilesResource(self) @cached_property def tenants(self) -> AsyncTenantsResource: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ from .resources.tenants import AsyncTenantsResource return AsyncTenantsResource(self) @cached_property def translations(self) -> AsyncTranslationsResource: + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ from .resources.translations import AsyncTranslationsResource return AsyncTranslationsResource(self) @@ -700,48 +804,70 @@ def __init__(self, client: Courier) -> None: @cached_property def send(self) -> send.SendResourceWithRawResponse: + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ from .resources.send import SendResourceWithRawResponse return SendResourceWithRawResponse(self._client.send) @cached_property def audiences(self) -> audiences.AudiencesResourceWithRawResponse: + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ from .resources.audiences import AudiencesResourceWithRawResponse return AudiencesResourceWithRawResponse(self._client.audiences) @cached_property def providers(self) -> providers.ProvidersResourceWithRawResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ from .resources.providers import ProvidersResourceWithRawResponse return ProvidersResourceWithRawResponse(self._client.providers) @cached_property def audit_events(self) -> audit_events.AuditEventsResourceWithRawResponse: + """Read the audit trail of configuration and access changes in your workspace.""" from .resources.audit_events import AuditEventsResourceWithRawResponse return AuditEventsResourceWithRawResponse(self._client.audit_events) @cached_property def auth(self) -> auth.AuthResourceWithRawResponse: + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ from .resources.auth import AuthResourceWithRawResponse return AuthResourceWithRawResponse(self._client.auth) @cached_property def automations(self) -> automations.AutomationsResourceWithRawResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ from .resources.automations import AutomationsResourceWithRawResponse return AutomationsResourceWithRawResponse(self._client.automations) @cached_property def journeys(self) -> journeys.JourneysResourceWithRawResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ from .resources.journeys import JourneysResourceWithRawResponse return JourneysResourceWithRawResponse(self._client.journeys) @cached_property def brands(self) -> brands.BrandsResourceWithRawResponse: + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ from .resources.brands import BrandsResourceWithRawResponse return BrandsResourceWithRawResponse(self._client.brands) @@ -754,12 +880,18 @@ def digests(self) -> digests.DigestsResourceWithRawResponse: @cached_property def inbound(self) -> inbound.InboundResourceWithRawResponse: + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ from .resources.inbound import InboundResourceWithRawResponse return InboundResourceWithRawResponse(self._client.inbound) @cached_property def lists(self) -> lists.ListsResourceWithRawResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ from .resources.lists import ListsResourceWithRawResponse return ListsResourceWithRawResponse(self._client.lists) @@ -772,48 +904,72 @@ def inbox(self) -> inbox.InboxResourceWithRawResponse: @cached_property def messages(self) -> messages.MessagesResourceWithRawResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.messages import MessagesResourceWithRawResponse return MessagesResourceWithRawResponse(self._client.messages) @cached_property def requests(self) -> requests.RequestsResourceWithRawResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.requests import RequestsResourceWithRawResponse return RequestsResourceWithRawResponse(self._client.requests) @cached_property def notifications(self) -> notifications.NotificationsResourceWithRawResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ from .resources.notifications import NotificationsResourceWithRawResponse return NotificationsResourceWithRawResponse(self._client.notifications) @cached_property def routing_strategies(self) -> routing_strategies.RoutingStrategiesResourceWithRawResponse: + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ from .resources.routing_strategies import RoutingStrategiesResourceWithRawResponse return RoutingStrategiesResourceWithRawResponse(self._client.routing_strategies) @cached_property def workspace_preferences(self) -> workspace_preferences.WorkspacePreferencesResourceWithRawResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ from .resources.workspace_preferences import WorkspacePreferencesResourceWithRawResponse return WorkspacePreferencesResourceWithRawResponse(self._client.workspace_preferences) @cached_property def profiles(self) -> profiles.ProfilesResourceWithRawResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ from .resources.profiles import ProfilesResourceWithRawResponse return ProfilesResourceWithRawResponse(self._client.profiles) @cached_property def tenants(self) -> tenants.TenantsResourceWithRawResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ from .resources.tenants import TenantsResourceWithRawResponse return TenantsResourceWithRawResponse(self._client.tenants) @cached_property def translations(self) -> translations.TranslationsResourceWithRawResponse: + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ from .resources.translations import TranslationsResourceWithRawResponse return TranslationsResourceWithRawResponse(self._client.translations) @@ -833,48 +989,70 @@ def __init__(self, client: AsyncCourier) -> None: @cached_property def send(self) -> send.AsyncSendResourceWithRawResponse: + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ from .resources.send import AsyncSendResourceWithRawResponse return AsyncSendResourceWithRawResponse(self._client.send) @cached_property def audiences(self) -> audiences.AsyncAudiencesResourceWithRawResponse: + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ from .resources.audiences import AsyncAudiencesResourceWithRawResponse return AsyncAudiencesResourceWithRawResponse(self._client.audiences) @cached_property def providers(self) -> providers.AsyncProvidersResourceWithRawResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ from .resources.providers import AsyncProvidersResourceWithRawResponse return AsyncProvidersResourceWithRawResponse(self._client.providers) @cached_property def audit_events(self) -> audit_events.AsyncAuditEventsResourceWithRawResponse: + """Read the audit trail of configuration and access changes in your workspace.""" from .resources.audit_events import AsyncAuditEventsResourceWithRawResponse return AsyncAuditEventsResourceWithRawResponse(self._client.audit_events) @cached_property def auth(self) -> auth.AsyncAuthResourceWithRawResponse: + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ from .resources.auth import AsyncAuthResourceWithRawResponse return AsyncAuthResourceWithRawResponse(self._client.auth) @cached_property def automations(self) -> automations.AsyncAutomationsResourceWithRawResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ from .resources.automations import AsyncAutomationsResourceWithRawResponse return AsyncAutomationsResourceWithRawResponse(self._client.automations) @cached_property def journeys(self) -> journeys.AsyncJourneysResourceWithRawResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ from .resources.journeys import AsyncJourneysResourceWithRawResponse return AsyncJourneysResourceWithRawResponse(self._client.journeys) @cached_property def brands(self) -> brands.AsyncBrandsResourceWithRawResponse: + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ from .resources.brands import AsyncBrandsResourceWithRawResponse return AsyncBrandsResourceWithRawResponse(self._client.brands) @@ -887,12 +1065,18 @@ def digests(self) -> digests.AsyncDigestsResourceWithRawResponse: @cached_property def inbound(self) -> inbound.AsyncInboundResourceWithRawResponse: + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ from .resources.inbound import AsyncInboundResourceWithRawResponse return AsyncInboundResourceWithRawResponse(self._client.inbound) @cached_property def lists(self) -> lists.AsyncListsResourceWithRawResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ from .resources.lists import AsyncListsResourceWithRawResponse return AsyncListsResourceWithRawResponse(self._client.lists) @@ -905,48 +1089,72 @@ def inbox(self) -> inbox.AsyncInboxResourceWithRawResponse: @cached_property def messages(self) -> messages.AsyncMessagesResourceWithRawResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.messages import AsyncMessagesResourceWithRawResponse return AsyncMessagesResourceWithRawResponse(self._client.messages) @cached_property def requests(self) -> requests.AsyncRequestsResourceWithRawResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.requests import AsyncRequestsResourceWithRawResponse return AsyncRequestsResourceWithRawResponse(self._client.requests) @cached_property def notifications(self) -> notifications.AsyncNotificationsResourceWithRawResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ from .resources.notifications import AsyncNotificationsResourceWithRawResponse return AsyncNotificationsResourceWithRawResponse(self._client.notifications) @cached_property def routing_strategies(self) -> routing_strategies.AsyncRoutingStrategiesResourceWithRawResponse: + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ from .resources.routing_strategies import AsyncRoutingStrategiesResourceWithRawResponse return AsyncRoutingStrategiesResourceWithRawResponse(self._client.routing_strategies) @cached_property def workspace_preferences(self) -> workspace_preferences.AsyncWorkspacePreferencesResourceWithRawResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ from .resources.workspace_preferences import AsyncWorkspacePreferencesResourceWithRawResponse return AsyncWorkspacePreferencesResourceWithRawResponse(self._client.workspace_preferences) @cached_property def profiles(self) -> profiles.AsyncProfilesResourceWithRawResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ from .resources.profiles import AsyncProfilesResourceWithRawResponse return AsyncProfilesResourceWithRawResponse(self._client.profiles) @cached_property def tenants(self) -> tenants.AsyncTenantsResourceWithRawResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ from .resources.tenants import AsyncTenantsResourceWithRawResponse return AsyncTenantsResourceWithRawResponse(self._client.tenants) @cached_property def translations(self) -> translations.AsyncTranslationsResourceWithRawResponse: + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ from .resources.translations import AsyncTranslationsResourceWithRawResponse return AsyncTranslationsResourceWithRawResponse(self._client.translations) @@ -966,48 +1174,70 @@ def __init__(self, client: Courier) -> None: @cached_property def send(self) -> send.SendResourceWithStreamingResponse: + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ from .resources.send import SendResourceWithStreamingResponse return SendResourceWithStreamingResponse(self._client.send) @cached_property def audiences(self) -> audiences.AudiencesResourceWithStreamingResponse: + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ from .resources.audiences import AudiencesResourceWithStreamingResponse return AudiencesResourceWithStreamingResponse(self._client.audiences) @cached_property def providers(self) -> providers.ProvidersResourceWithStreamingResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ from .resources.providers import ProvidersResourceWithStreamingResponse return ProvidersResourceWithStreamingResponse(self._client.providers) @cached_property def audit_events(self) -> audit_events.AuditEventsResourceWithStreamingResponse: + """Read the audit trail of configuration and access changes in your workspace.""" from .resources.audit_events import AuditEventsResourceWithStreamingResponse return AuditEventsResourceWithStreamingResponse(self._client.audit_events) @cached_property def auth(self) -> auth.AuthResourceWithStreamingResponse: + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ from .resources.auth import AuthResourceWithStreamingResponse return AuthResourceWithStreamingResponse(self._client.auth) @cached_property def automations(self) -> automations.AutomationsResourceWithStreamingResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ from .resources.automations import AutomationsResourceWithStreamingResponse return AutomationsResourceWithStreamingResponse(self._client.automations) @cached_property def journeys(self) -> journeys.JourneysResourceWithStreamingResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ from .resources.journeys import JourneysResourceWithStreamingResponse return JourneysResourceWithStreamingResponse(self._client.journeys) @cached_property def brands(self) -> brands.BrandsResourceWithStreamingResponse: + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ from .resources.brands import BrandsResourceWithStreamingResponse return BrandsResourceWithStreamingResponse(self._client.brands) @@ -1020,12 +1250,18 @@ def digests(self) -> digests.DigestsResourceWithStreamingResponse: @cached_property def inbound(self) -> inbound.InboundResourceWithStreamingResponse: + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ from .resources.inbound import InboundResourceWithStreamingResponse return InboundResourceWithStreamingResponse(self._client.inbound) @cached_property def lists(self) -> lists.ListsResourceWithStreamingResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ from .resources.lists import ListsResourceWithStreamingResponse return ListsResourceWithStreamingResponse(self._client.lists) @@ -1038,48 +1274,72 @@ def inbox(self) -> inbox.InboxResourceWithStreamingResponse: @cached_property def messages(self) -> messages.MessagesResourceWithStreamingResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.messages import MessagesResourceWithStreamingResponse return MessagesResourceWithStreamingResponse(self._client.messages) @cached_property def requests(self) -> requests.RequestsResourceWithStreamingResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.requests import RequestsResourceWithStreamingResponse return RequestsResourceWithStreamingResponse(self._client.requests) @cached_property def notifications(self) -> notifications.NotificationsResourceWithStreamingResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ from .resources.notifications import NotificationsResourceWithStreamingResponse return NotificationsResourceWithStreamingResponse(self._client.notifications) @cached_property def routing_strategies(self) -> routing_strategies.RoutingStrategiesResourceWithStreamingResponse: + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ from .resources.routing_strategies import RoutingStrategiesResourceWithStreamingResponse return RoutingStrategiesResourceWithStreamingResponse(self._client.routing_strategies) @cached_property def workspace_preferences(self) -> workspace_preferences.WorkspacePreferencesResourceWithStreamingResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ from .resources.workspace_preferences import WorkspacePreferencesResourceWithStreamingResponse return WorkspacePreferencesResourceWithStreamingResponse(self._client.workspace_preferences) @cached_property def profiles(self) -> profiles.ProfilesResourceWithStreamingResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ from .resources.profiles import ProfilesResourceWithStreamingResponse return ProfilesResourceWithStreamingResponse(self._client.profiles) @cached_property def tenants(self) -> tenants.TenantsResourceWithStreamingResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ from .resources.tenants import TenantsResourceWithStreamingResponse return TenantsResourceWithStreamingResponse(self._client.tenants) @cached_property def translations(self) -> translations.TranslationsResourceWithStreamingResponse: + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ from .resources.translations import TranslationsResourceWithStreamingResponse return TranslationsResourceWithStreamingResponse(self._client.translations) @@ -1099,48 +1359,70 @@ def __init__(self, client: AsyncCourier) -> None: @cached_property def send(self) -> send.AsyncSendResourceWithStreamingResponse: + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ from .resources.send import AsyncSendResourceWithStreamingResponse return AsyncSendResourceWithStreamingResponse(self._client.send) @cached_property def audiences(self) -> audiences.AsyncAudiencesResourceWithStreamingResponse: + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ from .resources.audiences import AsyncAudiencesResourceWithStreamingResponse return AsyncAudiencesResourceWithStreamingResponse(self._client.audiences) @cached_property def providers(self) -> providers.AsyncProvidersResourceWithStreamingResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ from .resources.providers import AsyncProvidersResourceWithStreamingResponse return AsyncProvidersResourceWithStreamingResponse(self._client.providers) @cached_property def audit_events(self) -> audit_events.AsyncAuditEventsResourceWithStreamingResponse: + """Read the audit trail of configuration and access changes in your workspace.""" from .resources.audit_events import AsyncAuditEventsResourceWithStreamingResponse return AsyncAuditEventsResourceWithStreamingResponse(self._client.audit_events) @cached_property def auth(self) -> auth.AsyncAuthResourceWithStreamingResponse: + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ from .resources.auth import AsyncAuthResourceWithStreamingResponse return AsyncAuthResourceWithStreamingResponse(self._client.auth) @cached_property def automations(self) -> automations.AsyncAutomationsResourceWithStreamingResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ from .resources.automations import AsyncAutomationsResourceWithStreamingResponse return AsyncAutomationsResourceWithStreamingResponse(self._client.automations) @cached_property def journeys(self) -> journeys.AsyncJourneysResourceWithStreamingResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ from .resources.journeys import AsyncJourneysResourceWithStreamingResponse return AsyncJourneysResourceWithStreamingResponse(self._client.journeys) @cached_property def brands(self) -> brands.AsyncBrandsResourceWithStreamingResponse: + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ from .resources.brands import AsyncBrandsResourceWithStreamingResponse return AsyncBrandsResourceWithStreamingResponse(self._client.brands) @@ -1153,12 +1435,18 @@ def digests(self) -> digests.AsyncDigestsResourceWithStreamingResponse: @cached_property def inbound(self) -> inbound.AsyncInboundResourceWithStreamingResponse: + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ from .resources.inbound import AsyncInboundResourceWithStreamingResponse return AsyncInboundResourceWithStreamingResponse(self._client.inbound) @cached_property def lists(self) -> lists.AsyncListsResourceWithStreamingResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ from .resources.lists import AsyncListsResourceWithStreamingResponse return AsyncListsResourceWithStreamingResponse(self._client.lists) @@ -1171,48 +1459,72 @@ def inbox(self) -> inbox.AsyncInboxResourceWithStreamingResponse: @cached_property def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.messages import AsyncMessagesResourceWithStreamingResponse return AsyncMessagesResourceWithStreamingResponse(self._client.messages) @cached_property def requests(self) -> requests.AsyncRequestsResourceWithStreamingResponse: + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ from .resources.requests import AsyncRequestsResourceWithStreamingResponse return AsyncRequestsResourceWithStreamingResponse(self._client.requests) @cached_property def notifications(self) -> notifications.AsyncNotificationsResourceWithStreamingResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ from .resources.notifications import AsyncNotificationsResourceWithStreamingResponse return AsyncNotificationsResourceWithStreamingResponse(self._client.notifications) @cached_property def routing_strategies(self) -> routing_strategies.AsyncRoutingStrategiesResourceWithStreamingResponse: + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ from .resources.routing_strategies import AsyncRoutingStrategiesResourceWithStreamingResponse return AsyncRoutingStrategiesResourceWithStreamingResponse(self._client.routing_strategies) @cached_property def workspace_preferences(self) -> workspace_preferences.AsyncWorkspacePreferencesResourceWithStreamingResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ from .resources.workspace_preferences import AsyncWorkspacePreferencesResourceWithStreamingResponse return AsyncWorkspacePreferencesResourceWithStreamingResponse(self._client.workspace_preferences) @cached_property def profiles(self) -> profiles.AsyncProfilesResourceWithStreamingResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ from .resources.profiles import AsyncProfilesResourceWithStreamingResponse return AsyncProfilesResourceWithStreamingResponse(self._client.profiles) @cached_property def tenants(self) -> tenants.AsyncTenantsResourceWithStreamingResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ from .resources.tenants import AsyncTenantsResourceWithStreamingResponse return AsyncTenantsResourceWithStreamingResponse(self._client.tenants) @cached_property def translations(self) -> translations.AsyncTranslationsResourceWithStreamingResponse: + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ from .resources.translations import AsyncTranslationsResourceWithStreamingResponse return AsyncTranslationsResourceWithStreamingResponse(self._client.translations) diff --git a/src/courier/resources/audiences.py b/src/courier/resources/audiences.py index 89bc7835..9a2c2ad7 100644 --- a/src/courier/resources/audiences.py +++ b/src/courier/resources/audiences.py @@ -29,6 +29,10 @@ class AudiencesResource(SyncAPIResource): + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ + @cached_property def with_raw_response(self) -> AudiencesResourceWithRawResponse: """ @@ -257,6 +261,10 @@ def list_members( class AsyncAudiencesResource(AsyncAPIResource): + """ + Define filter-based groups whose membership Courier recalculates as user profiles change. + """ + @cached_property def with_raw_response(self) -> AsyncAudiencesResourceWithRawResponse: """ diff --git a/src/courier/resources/audit_events.py b/src/courier/resources/audit_events.py index 289597ab..042d4b2e 100644 --- a/src/courier/resources/audit_events.py +++ b/src/courier/resources/audit_events.py @@ -25,6 +25,8 @@ class AuditEventsResource(SyncAPIResource): + """Read the audit trail of configuration and access changes in your workspace.""" + @cached_property def with_raw_response(self) -> AuditEventsResourceWithRawResponse: """ @@ -119,6 +121,8 @@ def list( class AsyncAuditEventsResource(AsyncAPIResource): + """Read the audit trail of configuration and access changes in your workspace.""" + @cached_property def with_raw_response(self) -> AsyncAuditEventsResourceWithRawResponse: """ diff --git a/src/courier/resources/auth.py b/src/courier/resources/auth.py index 4ba679c9..c3e17fcc 100644 --- a/src/courier/resources/auth.py +++ b/src/courier/resources/auth.py @@ -22,6 +22,10 @@ class AuthResource(SyncAPIResource): + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ + @cached_property def with_raw_response(self) -> AuthResourceWithRawResponse: """ @@ -114,6 +118,10 @@ def issue_token( class AsyncAuthResource(AsyncAPIResource): + """ + Issue scoped, short-lived JWTs so client-side SDKs — Inbox, Preferences, and the embedded designer — can call Courier as a single user. Server-side requests authenticate with your workspace API key instead. + """ + @cached_property def with_raw_response(self) -> AsyncAuthResourceWithRawResponse: """ diff --git a/src/courier/resources/automations/automations.py b/src/courier/resources/automations/automations.py index 00635564..1ae9add2 100644 --- a/src/courier/resources/automations/automations.py +++ b/src/courier/resources/automations/automations.py @@ -32,8 +32,15 @@ class AutomationsResource(SyncAPIResource): + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ + @cached_property def invoke(self) -> InvokeResource: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ return InvokeResource(self._client) @cached_property @@ -106,8 +113,15 @@ def list( class AsyncAutomationsResource(AsyncAPIResource): + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ + @cached_property def invoke(self) -> AsyncInvokeResource: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ return AsyncInvokeResource(self._client) @cached_property @@ -189,6 +203,9 @@ def __init__(self, automations: AutomationsResource) -> None: @cached_property def invoke(self) -> InvokeResourceWithRawResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ return InvokeResourceWithRawResponse(self._automations.invoke) @@ -202,6 +219,9 @@ def __init__(self, automations: AsyncAutomationsResource) -> None: @cached_property def invoke(self) -> AsyncInvokeResourceWithRawResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ return AsyncInvokeResourceWithRawResponse(self._automations.invoke) @@ -215,6 +235,9 @@ def __init__(self, automations: AutomationsResource) -> None: @cached_property def invoke(self) -> InvokeResourceWithStreamingResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ return InvokeResourceWithStreamingResponse(self._automations.invoke) @@ -228,4 +251,7 @@ def __init__(self, automations: AsyncAutomationsResource) -> None: @cached_property def invoke(self) -> AsyncInvokeResourceWithStreamingResponse: + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ return AsyncInvokeResourceWithStreamingResponse(self._automations.invoke) diff --git a/src/courier/resources/automations/invoke.py b/src/courier/resources/automations/invoke.py index a50a22c1..c1e9cfe5 100644 --- a/src/courier/resources/automations/invoke.py +++ b/src/courier/resources/automations/invoke.py @@ -24,6 +24,10 @@ class InvokeResource(SyncAPIResource): + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ + @cached_property def with_raw_response(self) -> InvokeResourceWithRawResponse: """ @@ -164,6 +168,10 @@ def invoke_by_template( class AsyncInvokeResource(AsyncAPIResource): + """ + Invoke a stored automation template or an ad hoc automation defined in the request. + """ + @cached_property def with_raw_response(self) -> AsyncInvokeResourceWithRawResponse: """ diff --git a/src/courier/resources/brands.py b/src/courier/resources/brands.py index 00a9f6d2..ca96b48f 100644 --- a/src/courier/resources/brands.py +++ b/src/courier/resources/brands.py @@ -27,6 +27,10 @@ class BrandsResource(SyncAPIResource): + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ + @cached_property def with_raw_response(self) -> BrandsResourceWithRawResponse: """ @@ -260,6 +264,10 @@ def delete( class AsyncBrandsResource(AsyncAPIResource): + """ + Manage the logos, colors, and layout that give the templates you send a consistent look. + """ + @cached_property def with_raw_response(self) -> AsyncBrandsResourceWithRawResponse: """ diff --git a/src/courier/resources/digests/digests.py b/src/courier/resources/digests/digests.py index b50742c5..d2d31d1e 100644 --- a/src/courier/resources/digests/digests.py +++ b/src/courier/resources/digests/digests.py @@ -19,6 +19,9 @@ class DigestsResource(SyncAPIResource): @cached_property def schedules(self) -> SchedulesResource: + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ return SchedulesResource(self._client) @cached_property @@ -44,6 +47,9 @@ def with_streaming_response(self) -> DigestsResourceWithStreamingResponse: class AsyncDigestsResource(AsyncAPIResource): @cached_property def schedules(self) -> AsyncSchedulesResource: + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ return AsyncSchedulesResource(self._client) @cached_property @@ -72,6 +78,9 @@ def __init__(self, digests: DigestsResource) -> None: @cached_property def schedules(self) -> SchedulesResourceWithRawResponse: + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ return SchedulesResourceWithRawResponse(self._digests.schedules) @@ -81,6 +90,9 @@ def __init__(self, digests: AsyncDigestsResource) -> None: @cached_property def schedules(self) -> AsyncSchedulesResourceWithRawResponse: + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ return AsyncSchedulesResourceWithRawResponse(self._digests.schedules) @@ -90,6 +102,9 @@ def __init__(self, digests: DigestsResource) -> None: @cached_property def schedules(self) -> SchedulesResourceWithStreamingResponse: + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ return SchedulesResourceWithStreamingResponse(self._digests.schedules) @@ -99,4 +114,7 @@ def __init__(self, digests: AsyncDigestsResource) -> None: @cached_property def schedules(self) -> AsyncSchedulesResourceWithStreamingResponse: + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ return AsyncSchedulesResourceWithStreamingResponse(self._digests.schedules) diff --git a/src/courier/resources/digests/schedules.py b/src/courier/resources/digests/schedules.py index 4c488392..006e4b5d 100644 --- a/src/courier/resources/digests/schedules.py +++ b/src/courier/resources/digests/schedules.py @@ -22,6 +22,10 @@ class SchedulesResource(SyncAPIResource): + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ + @cached_property def with_raw_response(self) -> SchedulesResourceWithRawResponse: """ @@ -129,6 +133,10 @@ def release( class AsyncSchedulesResource(AsyncAPIResource): + """ + Inspect what has accumulated in a digest schedule and release a digest ahead of its next scheduled delivery. + """ + @cached_property def with_raw_response(self) -> AsyncSchedulesResourceWithRawResponse: """ diff --git a/src/courier/resources/inbound.py b/src/courier/resources/inbound.py index 9474c374..d5af1bbc 100644 --- a/src/courier/resources/inbound.py +++ b/src/courier/resources/inbound.py @@ -25,6 +25,10 @@ class InboundResource(SyncAPIResource): + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ + @cached_property def with_raw_response(self) -> InboundResourceWithRawResponse: """ @@ -101,6 +105,10 @@ def track_event( class AsyncInboundResource(AsyncAPIResource): + """ + Record an inbound event that triggers the journeys and automations mapped to it. + """ + @cached_property def with_raw_response(self) -> AsyncInboundResourceWithRawResponse: """ diff --git a/src/courier/resources/inbox/inbox.py b/src/courier/resources/inbox/inbox.py index b132aff0..4ab70842 100644 --- a/src/courier/resources/inbox/inbox.py +++ b/src/courier/resources/inbox/inbox.py @@ -19,6 +19,7 @@ class InboxResource(SyncAPIResource): @cached_property def messages(self) -> MessagesResource: + """Manage the messages in a user's in-app inbox.""" return MessagesResource(self._client) @cached_property @@ -44,6 +45,7 @@ def with_streaming_response(self) -> InboxResourceWithStreamingResponse: class AsyncInboxResource(AsyncAPIResource): @cached_property def messages(self) -> AsyncMessagesResource: + """Manage the messages in a user's in-app inbox.""" return AsyncMessagesResource(self._client) @cached_property @@ -72,6 +74,7 @@ def __init__(self, inbox: InboxResource) -> None: @cached_property def messages(self) -> MessagesResourceWithRawResponse: + """Manage the messages in a user's in-app inbox.""" return MessagesResourceWithRawResponse(self._inbox.messages) @@ -81,6 +84,7 @@ def __init__(self, inbox: AsyncInboxResource) -> None: @cached_property def messages(self) -> AsyncMessagesResourceWithRawResponse: + """Manage the messages in a user's in-app inbox.""" return AsyncMessagesResourceWithRawResponse(self._inbox.messages) @@ -90,6 +94,7 @@ def __init__(self, inbox: InboxResource) -> None: @cached_property def messages(self) -> MessagesResourceWithStreamingResponse: + """Manage the messages in a user's in-app inbox.""" return MessagesResourceWithStreamingResponse(self._inbox.messages) @@ -99,4 +104,5 @@ def __init__(self, inbox: AsyncInboxResource) -> None: @cached_property def messages(self) -> AsyncMessagesResourceWithStreamingResponse: + """Manage the messages in a user's in-app inbox.""" return AsyncMessagesResourceWithStreamingResponse(self._inbox.messages) diff --git a/src/courier/resources/inbox/messages.py b/src/courier/resources/inbox/messages.py index ee4c03ed..75bf3da5 100644 --- a/src/courier/resources/inbox/messages.py +++ b/src/courier/resources/inbox/messages.py @@ -20,6 +20,8 @@ class MessagesResource(SyncAPIResource): + """Manage the messages in a user's in-app inbox.""" + @cached_property def with_raw_response(self) -> MessagesResourceWithRawResponse: """ @@ -111,6 +113,8 @@ def restore( class AsyncMessagesResource(AsyncAPIResource): + """Manage the messages in a user's in-app inbox.""" + @cached_property def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: """ diff --git a/src/courier/resources/journeys/journeys.py b/src/courier/resources/journeys/journeys.py index e228e7d8..7bb1439a 100644 --- a/src/courier/resources/journeys/journeys.py +++ b/src/courier/resources/journeys/journeys.py @@ -48,8 +48,15 @@ class JourneysResource(SyncAPIResource): + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ + @cached_property def templates(self) -> TemplatesResource: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ return TemplatesResource(self._client) @cached_property @@ -561,8 +568,15 @@ def replace( class AsyncJourneysResource(AsyncAPIResource): + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ + @cached_property def templates(self) -> AsyncTemplatesResource: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ return AsyncTemplatesResource(self._client) @cached_property @@ -1107,6 +1121,9 @@ def __init__(self, journeys: JourneysResource) -> None: @cached_property def templates(self) -> TemplatesResourceWithRawResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ return TemplatesResourceWithRawResponse(self._journeys.templates) @@ -1144,6 +1161,9 @@ def __init__(self, journeys: AsyncJourneysResource) -> None: @cached_property def templates(self) -> AsyncTemplatesResourceWithRawResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ return AsyncTemplatesResourceWithRawResponse(self._journeys.templates) @@ -1181,6 +1201,9 @@ def __init__(self, journeys: JourneysResource) -> None: @cached_property def templates(self) -> TemplatesResourceWithStreamingResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ return TemplatesResourceWithStreamingResponse(self._journeys.templates) @@ -1218,4 +1241,7 @@ def __init__(self, journeys: AsyncJourneysResource) -> None: @cached_property def templates(self) -> AsyncTemplatesResourceWithStreamingResponse: + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ return AsyncTemplatesResourceWithStreamingResponse(self._journeys.templates) diff --git a/src/courier/resources/journeys/templates.py b/src/courier/resources/journeys/templates.py index 68e2b8c5..b030ff6c 100644 --- a/src/courier/resources/journeys/templates.py +++ b/src/courier/resources/journeys/templates.py @@ -38,6 +38,10 @@ class TemplatesResource(SyncAPIResource): + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ + @cached_property def with_raw_response(self) -> TemplatesResourceWithRawResponse: """ @@ -565,6 +569,10 @@ def retrieve_content( class AsyncTemplatesResource(AsyncAPIResource): + """ + Build, version, publish, invoke, and cancel multi-step notification workflows, along with the templates scoped to them. + """ + @cached_property def with_raw_response(self) -> AsyncTemplatesResourceWithRawResponse: """ diff --git a/src/courier/resources/lists/lists.py b/src/courier/resources/lists/lists.py index 37063764..95b43ebd 100644 --- a/src/courier/resources/lists/lists.py +++ b/src/courier/resources/lists/lists.py @@ -34,8 +34,15 @@ class ListsResource(SyncAPIResource): + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ + @cached_property def subscriptions(self) -> SubscriptionsResource: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ return SubscriptionsResource(self._client) @cached_property @@ -261,8 +268,15 @@ def restore( class AsyncListsResource(AsyncAPIResource): + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ + @cached_property def subscriptions(self) -> AsyncSubscriptionsResource: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ return AsyncSubscriptionsResource(self._client) @cached_property @@ -509,6 +523,9 @@ def __init__(self, lists: ListsResource) -> None: @cached_property def subscriptions(self) -> SubscriptionsResourceWithRawResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ return SubscriptionsResourceWithRawResponse(self._lists.subscriptions) @@ -534,6 +551,9 @@ def __init__(self, lists: AsyncListsResource) -> None: @cached_property def subscriptions(self) -> AsyncSubscriptionsResourceWithRawResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ return AsyncSubscriptionsResourceWithRawResponse(self._lists.subscriptions) @@ -559,6 +579,9 @@ def __init__(self, lists: ListsResource) -> None: @cached_property def subscriptions(self) -> SubscriptionsResourceWithStreamingResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ return SubscriptionsResourceWithStreamingResponse(self._lists.subscriptions) @@ -584,4 +607,7 @@ def __init__(self, lists: AsyncListsResource) -> None: @cached_property def subscriptions(self) -> AsyncSubscriptionsResourceWithStreamingResponse: + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ return AsyncSubscriptionsResourceWithStreamingResponse(self._lists.subscriptions) diff --git a/src/courier/resources/lists/subscriptions.py b/src/courier/resources/lists/subscriptions.py index 0e68a3f6..a9b5ef55 100644 --- a/src/courier/resources/lists/subscriptions.py +++ b/src/courier/resources/lists/subscriptions.py @@ -31,6 +31,10 @@ class SubscriptionsResource(SyncAPIResource): + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ + @cached_property def with_raw_response(self) -> SubscriptionsResourceWithRawResponse: """ @@ -260,6 +264,10 @@ def unsubscribe_user( class AsyncSubscriptionsResource(AsyncAPIResource): + """ + Manage static groups of users that you subscribe explicitly, and send to them by list id or list pattern. + """ + @cached_property def with_raw_response(self) -> AsyncSubscriptionsResourceWithRawResponse: """ diff --git a/src/courier/resources/messages.py b/src/courier/resources/messages.py index 10dbf259..9784b2b2 100644 --- a/src/courier/resources/messages.py +++ b/src/courier/resources/messages.py @@ -29,6 +29,10 @@ class MessagesResource(SyncAPIResource): + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ + @cached_property def with_raw_response(self) -> MessagesResourceWithRawResponse: """ @@ -331,6 +335,10 @@ def resend( class AsyncMessagesResource(AsyncAPIResource): + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ + @cached_property def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: """ diff --git a/src/courier/resources/notifications/checks.py b/src/courier/resources/notifications/checks.py index 4da0afe6..d26396c5 100644 --- a/src/courier/resources/notifications/checks.py +++ b/src/courier/resources/notifications/checks.py @@ -26,6 +26,10 @@ class ChecksResource(SyncAPIResource): + """ + Create, update, version, publish, and localize notification templates and their content. + """ + @cached_property def with_raw_response(self) -> ChecksResourceWithRawResponse: """ @@ -162,6 +166,10 @@ def delete( class AsyncChecksResource(AsyncAPIResource): + """ + Create, update, version, publish, and localize notification templates and their content. + """ + @cached_property def with_raw_response(self) -> AsyncChecksResourceWithRawResponse: """ diff --git a/src/courier/resources/notifications/notifications.py b/src/courier/resources/notifications/notifications.py index aa50a4ed..3c772f94 100644 --- a/src/courier/resources/notifications/notifications.py +++ b/src/courier/resources/notifications/notifications.py @@ -51,8 +51,15 @@ class NotificationsResource(SyncAPIResource): + """ + Create, update, version, publish, and localize notification templates and their content. + """ + @cached_property def checks(self) -> ChecksResource: + """ + Create, update, version, publish, and localize notification templates and their content. + """ return ChecksResource(self._client) @cached_property @@ -659,8 +666,15 @@ def retrieve_content( class AsyncNotificationsResource(AsyncAPIResource): + """ + Create, update, version, publish, and localize notification templates and their content. + """ + @cached_property def checks(self) -> AsyncChecksResource: + """ + Create, update, version, publish, and localize notification templates and their content. + """ return AsyncChecksResource(self._client) @cached_property @@ -1313,6 +1327,9 @@ def __init__(self, notifications: NotificationsResource) -> None: @cached_property def checks(self) -> ChecksResourceWithRawResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ return ChecksResourceWithRawResponse(self._notifications.checks) @@ -1359,6 +1376,9 @@ def __init__(self, notifications: AsyncNotificationsResource) -> None: @cached_property def checks(self) -> AsyncChecksResourceWithRawResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ return AsyncChecksResourceWithRawResponse(self._notifications.checks) @@ -1405,6 +1425,9 @@ def __init__(self, notifications: NotificationsResource) -> None: @cached_property def checks(self) -> ChecksResourceWithStreamingResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ return ChecksResourceWithStreamingResponse(self._notifications.checks) @@ -1451,4 +1474,7 @@ def __init__(self, notifications: AsyncNotificationsResource) -> None: @cached_property def checks(self) -> AsyncChecksResourceWithStreamingResponse: + """ + Create, update, version, publish, and localize notification templates and their content. + """ return AsyncChecksResourceWithStreamingResponse(self._notifications.checks) diff --git a/src/courier/resources/profiles/lists.py b/src/courier/resources/profiles/lists.py index 481bb243..7e2c040f 100644 --- a/src/courier/resources/profiles/lists.py +++ b/src/courier/resources/profiles/lists.py @@ -27,6 +27,10 @@ class ListsResource(SyncAPIResource): + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ + @cached_property def with_raw_response(self) -> ListsResourceWithRawResponse: """ @@ -172,6 +176,10 @@ def subscribe( class AsyncListsResource(AsyncAPIResource): + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ + @cached_property def with_raw_response(self) -> AsyncListsResourceWithRawResponse: """ diff --git a/src/courier/resources/profiles/profiles.py b/src/courier/resources/profiles/profiles.py index fb3985a6..afd7d636 100644 --- a/src/courier/resources/profiles/profiles.py +++ b/src/courier/resources/profiles/profiles.py @@ -34,8 +34,15 @@ class ProfilesResource(SyncAPIResource): + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ + @cached_property def lists(self) -> ListsResource: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ return ListsResource(self._client) @cached_property @@ -252,8 +259,15 @@ def replace( class AsyncProfilesResource(AsyncAPIResource): + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ + @cached_property def lists(self) -> AsyncListsResource: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ return AsyncListsResource(self._client) @cached_property @@ -491,6 +505,9 @@ def __init__(self, profiles: ProfilesResource) -> None: @cached_property def lists(self) -> ListsResourceWithRawResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ return ListsResourceWithRawResponse(self._profiles.lists) @@ -516,6 +533,9 @@ def __init__(self, profiles: AsyncProfilesResource) -> None: @cached_property def lists(self) -> AsyncListsResourceWithRawResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ return AsyncListsResourceWithRawResponse(self._profiles.lists) @@ -541,6 +561,9 @@ def __init__(self, profiles: ProfilesResource) -> None: @cached_property def lists(self) -> ListsResourceWithStreamingResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ return ListsResourceWithStreamingResponse(self._profiles.lists) @@ -566,4 +589,7 @@ def __init__(self, profiles: AsyncProfilesResource) -> None: @cached_property def lists(self) -> AsyncListsResourceWithStreamingResponse: + """ + Store the contact information Courier delivers to for each user — email, phone number, push tokens, and any custom data you send to. + """ return AsyncListsResourceWithStreamingResponse(self._profiles.lists) diff --git a/src/courier/resources/providers/catalog.py b/src/courier/resources/providers/catalog.py index 3587b36c..57daa70d 100644 --- a/src/courier/resources/providers/catalog.py +++ b/src/courier/resources/providers/catalog.py @@ -22,6 +22,10 @@ class CatalogResource(SyncAPIResource): + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ + @cached_property def with_raw_response(self) -> CatalogResourceWithRawResponse: """ @@ -95,6 +99,10 @@ def list( class AsyncCatalogResource(AsyncAPIResource): + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ + @cached_property def with_raw_response(self) -> AsyncCatalogResourceWithRawResponse: """ diff --git a/src/courier/resources/providers/providers.py b/src/courier/resources/providers/providers.py index 4bdc5d98..dadeb0df 100644 --- a/src/courier/resources/providers/providers.py +++ b/src/courier/resources/providers/providers.py @@ -33,8 +33,15 @@ class ProvidersResource(SyncAPIResource): + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ + @cached_property def catalog(self) -> CatalogResource: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ return CatalogResource(self._client) @cached_property @@ -289,8 +296,15 @@ def delete( class AsyncProvidersResource(AsyncAPIResource): + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ + @cached_property def catalog(self) -> AsyncCatalogResource: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ return AsyncCatalogResource(self._client) @cached_property @@ -566,6 +580,9 @@ def __init__(self, providers: ProvidersResource) -> None: @cached_property def catalog(self) -> CatalogResourceWithRawResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ return CatalogResourceWithRawResponse(self._providers.catalog) @@ -591,6 +608,9 @@ def __init__(self, providers: AsyncProvidersResource) -> None: @cached_property def catalog(self) -> AsyncCatalogResourceWithRawResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ return AsyncCatalogResourceWithRawResponse(self._providers.catalog) @@ -616,6 +636,9 @@ def __init__(self, providers: ProvidersResource) -> None: @cached_property def catalog(self) -> CatalogResourceWithStreamingResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ return CatalogResourceWithStreamingResponse(self._providers.catalog) @@ -641,4 +664,7 @@ def __init__(self, providers: AsyncProvidersResource) -> None: @cached_property def catalog(self) -> AsyncCatalogResourceWithStreamingResponse: + """ + Configure the channel providers Courier delivers through, and browse the provider types it supports. + """ return AsyncCatalogResourceWithStreamingResponse(self._providers.catalog) diff --git a/src/courier/resources/requests.py b/src/courier/resources/requests.py index 4b94972b..3dfd380a 100644 --- a/src/courier/resources/requests.py +++ b/src/courier/resources/requests.py @@ -20,6 +20,10 @@ class RequestsResource(SyncAPIResource): + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ + @cached_property def with_raw_response(self) -> RequestsResourceWithRawResponse: """ @@ -77,6 +81,10 @@ def archive( class AsyncRequestsResource(AsyncAPIResource): + """ + Look up the messages Courier has accepted, inspect their delivery history and rendered output, and cancel, resend, or archive them. + """ + @cached_property def with_raw_response(self) -> AsyncRequestsResourceWithRawResponse: """ diff --git a/src/courier/resources/routing_strategies.py b/src/courier/resources/routing_strategies.py index 57a23e44..48aaf066 100644 --- a/src/courier/resources/routing_strategies.py +++ b/src/courier/resources/routing_strategies.py @@ -34,6 +34,10 @@ class RoutingStrategiesResource(SyncAPIResource): + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ + @cached_property def with_raw_response(self) -> RoutingStrategiesResourceWithRawResponse: """ @@ -361,6 +365,10 @@ def replace( class AsyncRoutingStrategiesResource(AsyncAPIResource): + """ + Define reusable channel routing and failover strategies, and see which templates use them. + """ + @cached_property def with_raw_response(self) -> AsyncRoutingStrategiesResourceWithRawResponse: """ diff --git a/src/courier/resources/send.py b/src/courier/resources/send.py index b44f7da8..1c25a491 100644 --- a/src/courier/resources/send.py +++ b/src/courier/resources/send.py @@ -22,6 +22,10 @@ class SendResource(SyncAPIResource): + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ + @cached_property def with_raw_response(self) -> SendResourceWithRawResponse: """ @@ -91,6 +95,10 @@ def message( class AsyncSendResource(AsyncAPIResource): + """ + Send a message to one or more recipients — users, lists, audiences, or tenants — across every channel you have configured. + """ + @cached_property def with_raw_response(self) -> AsyncSendResourceWithRawResponse: """ diff --git a/src/courier/resources/tenants/preferences/items.py b/src/courier/resources/tenants/preferences/items.py index 4e0f397d..103d9af3 100644 --- a/src/courier/resources/tenants/preferences/items.py +++ b/src/courier/resources/tenants/preferences/items.py @@ -25,6 +25,10 @@ class ItemsResource(SyncAPIResource): + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ + @cached_property def with_raw_response(self) -> ItemsResourceWithRawResponse: """ @@ -143,6 +147,10 @@ def delete( class AsyncItemsResource(AsyncAPIResource): + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ + @cached_property def with_raw_response(self) -> AsyncItemsResourceWithRawResponse: """ diff --git a/src/courier/resources/tenants/preferences/preferences.py b/src/courier/resources/tenants/preferences/preferences.py index 0d8c47d4..6b0408dc 100644 --- a/src/courier/resources/tenants/preferences/preferences.py +++ b/src/courier/resources/tenants/preferences/preferences.py @@ -19,6 +19,9 @@ class PreferencesResource(SyncAPIResource): @cached_property def items(self) -> ItemsResource: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ return ItemsResource(self._client) @cached_property @@ -44,6 +47,9 @@ def with_streaming_response(self) -> PreferencesResourceWithStreamingResponse: class AsyncPreferencesResource(AsyncAPIResource): @cached_property def items(self) -> AsyncItemsResource: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ return AsyncItemsResource(self._client) @cached_property @@ -72,6 +78,9 @@ def __init__(self, preferences: PreferencesResource) -> None: @cached_property def items(self) -> ItemsResourceWithRawResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ return ItemsResourceWithRawResponse(self._preferences.items) @@ -81,6 +90,9 @@ def __init__(self, preferences: AsyncPreferencesResource) -> None: @cached_property def items(self) -> AsyncItemsResourceWithRawResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ return AsyncItemsResourceWithRawResponse(self._preferences.items) @@ -90,6 +102,9 @@ def __init__(self, preferences: PreferencesResource) -> None: @cached_property def items(self) -> ItemsResourceWithStreamingResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ return ItemsResourceWithStreamingResponse(self._preferences.items) @@ -99,4 +114,7 @@ def __init__(self, preferences: AsyncPreferencesResource) -> None: @cached_property def items(self) -> AsyncItemsResourceWithStreamingResponse: + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ return AsyncItemsResourceWithStreamingResponse(self._preferences.items) diff --git a/src/courier/resources/tenants/templates/templates.py b/src/courier/resources/tenants/templates/templates.py index e617ec2b..20015941 100644 --- a/src/courier/resources/tenants/templates/templates.py +++ b/src/courier/resources/tenants/templates/templates.py @@ -36,8 +36,15 @@ class TemplatesResource(SyncAPIResource): + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ + @cached_property def versions(self) -> VersionsResource: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return VersionsResource(self._client) @cached_property @@ -283,8 +290,15 @@ def replace( class AsyncTemplatesResource(AsyncAPIResource): + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ + @cached_property def versions(self) -> AsyncVersionsResource: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return AsyncVersionsResource(self._client) @cached_property @@ -551,6 +565,9 @@ def __init__(self, templates: TemplatesResource) -> None: @cached_property def versions(self) -> VersionsResourceWithRawResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return VersionsResourceWithRawResponse(self._templates.versions) @@ -576,6 +593,9 @@ def __init__(self, templates: AsyncTemplatesResource) -> None: @cached_property def versions(self) -> AsyncVersionsResourceWithRawResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return AsyncVersionsResourceWithRawResponse(self._templates.versions) @@ -601,6 +621,9 @@ def __init__(self, templates: TemplatesResource) -> None: @cached_property def versions(self) -> VersionsResourceWithStreamingResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return VersionsResourceWithStreamingResponse(self._templates.versions) @@ -626,4 +649,7 @@ def __init__(self, templates: AsyncTemplatesResource) -> None: @cached_property def versions(self) -> AsyncVersionsResourceWithStreamingResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return AsyncVersionsResourceWithStreamingResponse(self._templates.versions) diff --git a/src/courier/resources/tenants/templates/versions.py b/src/courier/resources/tenants/templates/versions.py index 8b33fe1e..bd91faa9 100644 --- a/src/courier/resources/tenants/templates/versions.py +++ b/src/courier/resources/tenants/templates/versions.py @@ -21,6 +21,10 @@ class VersionsResource(SyncAPIResource): + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ + @cached_property def with_raw_response(self) -> VersionsResourceWithRawResponse: """ @@ -87,6 +91,10 @@ def retrieve( class AsyncVersionsResource(AsyncAPIResource): + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ + @cached_property def with_raw_response(self) -> AsyncVersionsResourceWithRawResponse: """ diff --git a/src/courier/resources/tenants/tenants.py b/src/courier/resources/tenants/tenants.py index 5d60c53d..a05a830c 100644 --- a/src/courier/resources/tenants/tenants.py +++ b/src/courier/resources/tenants/tenants.py @@ -43,12 +43,19 @@ class TenantsResource(SyncAPIResource): + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ + @cached_property def preferences(self) -> PreferencesResource: return PreferencesResource(self._client) @cached_property def templates(self) -> TemplatesResource: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return TemplatesResource(self._client) @cached_property @@ -308,12 +315,19 @@ def list_users( class AsyncTenantsResource(AsyncAPIResource): + """ + Manage tenants — the organizations, teams, or accounts your users belong to — along with their users and default preferences. + """ + @cached_property def preferences(self) -> AsyncPreferencesResource: return AsyncPreferencesResource(self._client) @cached_property def templates(self) -> AsyncTemplatesResource: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return AsyncTemplatesResource(self._client) @cached_property @@ -598,6 +612,9 @@ def preferences(self) -> PreferencesResourceWithRawResponse: @cached_property def templates(self) -> TemplatesResourceWithRawResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return TemplatesResourceWithRawResponse(self._tenants.templates) @@ -627,6 +644,9 @@ def preferences(self) -> AsyncPreferencesResourceWithRawResponse: @cached_property def templates(self) -> AsyncTemplatesResourceWithRawResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return AsyncTemplatesResourceWithRawResponse(self._tenants.templates) @@ -656,6 +676,9 @@ def preferences(self) -> PreferencesResourceWithStreamingResponse: @cached_property def templates(self) -> TemplatesResourceWithStreamingResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return TemplatesResourceWithStreamingResponse(self._tenants.templates) @@ -685,4 +708,7 @@ def preferences(self) -> AsyncPreferencesResourceWithStreamingResponse: @cached_property def templates(self) -> AsyncTemplatesResourceWithStreamingResponse: + """ + Manage the templates and template versions scoped to a single tenant, including the ones authored in the embedded designer. + """ return AsyncTemplatesResourceWithStreamingResponse(self._tenants.templates) diff --git a/src/courier/resources/translations.py b/src/courier/resources/translations.py index da61bc77..dc20557c 100644 --- a/src/courier/resources/translations.py +++ b/src/courier/resources/translations.py @@ -21,6 +21,10 @@ class TranslationsResource(SyncAPIResource): + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ + @cached_property def with_raw_response(self) -> TranslationsResourceWithRawResponse: """ @@ -120,6 +124,10 @@ def update( class AsyncTranslationsResource(AsyncAPIResource): + """ + Store and retrieve the translation strings Courier uses to render localized template content. + """ + @cached_property def with_raw_response(self) -> AsyncTranslationsResourceWithRawResponse: """ diff --git a/src/courier/resources/users/preferences.py b/src/courier/resources/users/preferences.py index 0c741192..61d18743 100644 --- a/src/courier/resources/users/preferences.py +++ b/src/courier/resources/users/preferences.py @@ -35,6 +35,10 @@ class PreferencesResource(SyncAPIResource): + """ + Read and write a single user's notification preferences, per topic and per channel. + """ + @cached_property def with_raw_response(self) -> PreferencesResourceWithRawResponse: """ @@ -350,6 +354,10 @@ def update_or_create_topic( class AsyncPreferencesResource(AsyncAPIResource): + """ + Read and write a single user's notification preferences, per topic and per channel. + """ + @cached_property def with_raw_response(self) -> AsyncPreferencesResourceWithRawResponse: """ diff --git a/src/courier/resources/users/tenants.py b/src/courier/resources/users/tenants.py index 1b958f7d..b7b13102 100644 --- a/src/courier/resources/users/tenants.py +++ b/src/courier/resources/users/tenants.py @@ -25,6 +25,10 @@ class TenantsResource(SyncAPIResource): + """ + Associate a user with one or more tenants, and read or remove those associations. + """ + @cached_property def with_raw_response(self) -> TenantsResourceWithRawResponse: """ @@ -249,6 +253,10 @@ def remove_single( class AsyncTenantsResource(AsyncAPIResource): + """ + Associate a user with one or more tenants, and read or remove those associations. + """ + @cached_property def with_raw_response(self) -> AsyncTenantsResourceWithRawResponse: """ diff --git a/src/courier/resources/users/tokens.py b/src/courier/resources/users/tokens.py index ef065605..c43acb01 100644 --- a/src/courier/resources/users/tokens.py +++ b/src/courier/resources/users/tokens.py @@ -26,6 +26,10 @@ class TokensResource(SyncAPIResource): + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ + @cached_property def with_raw_response(self) -> TokensResourceWithRawResponse: """ @@ -293,6 +297,10 @@ def add_single( class AsyncTokensResource(AsyncAPIResource): + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ + @cached_property def with_raw_response(self) -> AsyncTokensResourceWithRawResponse: """ diff --git a/src/courier/resources/users/users.py b/src/courier/resources/users/users.py index 185580b7..9d080525 100644 --- a/src/courier/resources/users/users.py +++ b/src/courier/resources/users/users.py @@ -35,14 +35,23 @@ class UsersResource(SyncAPIResource): @cached_property def preferences(self) -> PreferencesResource: + """ + Read and write a single user's notification preferences, per topic and per channel. + """ return PreferencesResource(self._client) @cached_property def tenants(self) -> TenantsResource: + """ + Associate a user with one or more tenants, and read or remove those associations. + """ return TenantsResource(self._client) @cached_property def tokens(self) -> TokensResource: + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ return TokensResource(self._client) @cached_property @@ -68,14 +77,23 @@ def with_streaming_response(self) -> UsersResourceWithStreamingResponse: class AsyncUsersResource(AsyncAPIResource): @cached_property def preferences(self) -> AsyncPreferencesResource: + """ + Read and write a single user's notification preferences, per topic and per channel. + """ return AsyncPreferencesResource(self._client) @cached_property def tenants(self) -> AsyncTenantsResource: + """ + Associate a user with one or more tenants, and read or remove those associations. + """ return AsyncTenantsResource(self._client) @cached_property def tokens(self) -> AsyncTokensResource: + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ return AsyncTokensResource(self._client) @cached_property @@ -104,14 +122,23 @@ def __init__(self, users: UsersResource) -> None: @cached_property def preferences(self) -> PreferencesResourceWithRawResponse: + """ + Read and write a single user's notification preferences, per topic and per channel. + """ return PreferencesResourceWithRawResponse(self._users.preferences) @cached_property def tenants(self) -> TenantsResourceWithRawResponse: + """ + Associate a user with one or more tenants, and read or remove those associations. + """ return TenantsResourceWithRawResponse(self._users.tenants) @cached_property def tokens(self) -> TokensResourceWithRawResponse: + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ return TokensResourceWithRawResponse(self._users.tokens) @@ -121,14 +148,23 @@ def __init__(self, users: AsyncUsersResource) -> None: @cached_property def preferences(self) -> AsyncPreferencesResourceWithRawResponse: + """ + Read and write a single user's notification preferences, per topic and per channel. + """ return AsyncPreferencesResourceWithRawResponse(self._users.preferences) @cached_property def tenants(self) -> AsyncTenantsResourceWithRawResponse: + """ + Associate a user with one or more tenants, and read or remove those associations. + """ return AsyncTenantsResourceWithRawResponse(self._users.tenants) @cached_property def tokens(self) -> AsyncTokensResourceWithRawResponse: + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ return AsyncTokensResourceWithRawResponse(self._users.tokens) @@ -138,14 +174,23 @@ def __init__(self, users: UsersResource) -> None: @cached_property def preferences(self) -> PreferencesResourceWithStreamingResponse: + """ + Read and write a single user's notification preferences, per topic and per channel. + """ return PreferencesResourceWithStreamingResponse(self._users.preferences) @cached_property def tenants(self) -> TenantsResourceWithStreamingResponse: + """ + Associate a user with one or more tenants, and read or remove those associations. + """ return TenantsResourceWithStreamingResponse(self._users.tenants) @cached_property def tokens(self) -> TokensResourceWithStreamingResponse: + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ return TokensResourceWithStreamingResponse(self._users.tokens) @@ -155,12 +200,21 @@ def __init__(self, users: AsyncUsersResource) -> None: @cached_property def preferences(self) -> AsyncPreferencesResourceWithStreamingResponse: + """ + Read and write a single user's notification preferences, per topic and per channel. + """ return AsyncPreferencesResourceWithStreamingResponse(self._users.preferences) @cached_property def tenants(self) -> AsyncTenantsResourceWithStreamingResponse: + """ + Associate a user with one or more tenants, and read or remove those associations. + """ return AsyncTenantsResourceWithStreamingResponse(self._users.tenants) @cached_property def tokens(self) -> AsyncTokensResourceWithStreamingResponse: + """ + Register and manage the APNS and FCM device tokens Courier delivers push notifications to. + """ return AsyncTokensResourceWithStreamingResponse(self._users.tokens) diff --git a/src/courier/resources/workspace_preferences/topics.py b/src/courier/resources/workspace_preferences/topics.py index 702d548a..2e9d5f3b 100644 --- a/src/courier/resources/workspace_preferences/topics.py +++ b/src/courier/resources/workspace_preferences/topics.py @@ -27,6 +27,10 @@ class TopicsResource(SyncAPIResource): + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ + @cached_property def with_raw_response(self) -> TopicsResourceWithRawResponse: """ @@ -315,6 +319,10 @@ def replace( class AsyncTopicsResource(AsyncAPIResource): + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ + @cached_property def with_raw_response(self) -> AsyncTopicsResourceWithRawResponse: """ diff --git a/src/courier/resources/workspace_preferences/workspace_preferences.py b/src/courier/resources/workspace_preferences/workspace_preferences.py index 1bf746ba..cdb79e2d 100644 --- a/src/courier/resources/workspace_preferences/workspace_preferences.py +++ b/src/courier/resources/workspace_preferences/workspace_preferences.py @@ -39,8 +39,15 @@ class WorkspacePreferencesResource(SyncAPIResource): + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ + @cached_property def topics(self) -> TopicsResource: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ return TopicsResource(self._client) @cached_property @@ -337,8 +344,15 @@ def replace( class AsyncWorkspacePreferencesResource(AsyncAPIResource): + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ + @cached_property def topics(self) -> AsyncTopicsResource: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ return AsyncTopicsResource(self._client) @cached_property @@ -659,6 +673,9 @@ def __init__(self, workspace_preferences: WorkspacePreferencesResource) -> None: @cached_property def topics(self) -> TopicsResourceWithRawResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ return TopicsResourceWithRawResponse(self._workspace_preferences.topics) @@ -687,6 +704,9 @@ def __init__(self, workspace_preferences: AsyncWorkspacePreferencesResource) -> @cached_property def topics(self) -> AsyncTopicsResourceWithRawResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ return AsyncTopicsResourceWithRawResponse(self._workspace_preferences.topics) @@ -715,6 +735,9 @@ def __init__(self, workspace_preferences: WorkspacePreferencesResource) -> None: @cached_property def topics(self) -> TopicsResourceWithStreamingResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ return TopicsResourceWithStreamingResponse(self._workspace_preferences.topics) @@ -743,4 +766,7 @@ def __init__(self, workspace_preferences: AsyncWorkspacePreferencesResource) -> @cached_property def topics(self) -> AsyncTopicsResourceWithStreamingResponse: + """ + Manage the workspace catalog of subscription topics, the sections that group them, and publishing the preference page. + """ return AsyncTopicsResourceWithStreamingResponse(self._workspace_preferences.topics) From ab4a24e0a5c133c64100214c3a4b69858ec39377 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:18:15 +0000 Subject: [PATCH 6/6] release: 7.22.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 16 ++++++++++++++++ pyproject.toml | 2 +- src/courier/_version.py | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8696062a..afe4ebfd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.21.0" + ".": "7.22.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 55b22b49..468bcb90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 7.22.0 (2026-07-29) + +Full Changelog: [v7.21.0...v7.22.0](https://github.com/trycourier/courier-python/compare/v7.21.0...v7.22.0) + +### Features + +* Document DELETE/PUT restore for inbox messages (C-19268) ([#175](https://github.com/trycourier/courier-python/issues/175)) ([6e32a5c](https://github.com/trycourier/courier-python/commit/6e32a5cb55d541ba89ac260aa62fa0d1d40505d9)) +* spec: rename and reorder the API reference sections ([#179](https://github.com/trycourier/courier-python/issues/179)) ([742efe6](https://github.com/trycourier/courier-python/commit/742efe6045de6ae33afeb780205ea7010d93a98b)) + + +### Documentation + +* **openapi:** describe user topic-preference fields explicitly ([#172](https://github.com/trycourier/courier-python/issues/172)) ([842699a](https://github.com/trycourier/courier-python/commit/842699a68811d63aca9ef8d8865266623ff3e42c)) +* **openapi:** document Idempotency-Key header on idempotent POST endpoints ([#176](https://github.com/trycourier/courier-python/issues/176)) ([9209315](https://github.com/trycourier/courier-python/commit/92093156c03c0c8a56e7a43fe41b4d4490fcc7b2)) +* **openapi:** rewrite operation descriptions for agents and SEO ([#174](https://github.com/trycourier/courier-python/issues/174)) ([c90b5d3](https://github.com/trycourier/courier-python/commit/c90b5d325da4e542a46a089084205ce145d65ef1)) + ## 7.21.0 (2026-07-23) Full Changelog: [v7.20.0...v7.21.0](https://github.com/trycourier/courier-python/compare/v7.20.0...v7.21.0) diff --git a/pyproject.toml b/pyproject.toml index caddccb4..55734103 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "trycourier" -version = "7.21.0" +version = "7.22.0" description = "The official Python library for the Courier API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/courier/_version.py b/src/courier/_version.py index 04464d32..6b18c056 100644 --- a/src/courier/_version.py +++ b/src/courier/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "courier" -__version__ = "7.21.0" # x-release-please-version +__version__ = "7.22.0" # x-release-please-version