From 8eb868f447a312a8003cf529e206d28a25493c21 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 01:49:44 +0000 Subject: [PATCH 01/10] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 02e38ed..1733316 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq%2Flinq-api-v3-37a94929911f4b5944524a51b722bb0eea0b0b167fd79814181f58ed877aa341.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-4125b28145b56dd1f57a46a7b5953f055c4522180140fa5b36f2a7cf0eb3a30b.yml openapi_spec_hash: a3d001964480c894a5b6cb9ffa4fa47b config_hash: 3ab31decde29ec61e02db7dcb5313f82 From 79ec47708d4966cdb22401b6e2ec3324a6e72ab6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 04:00:11 +0000 Subject: [PATCH 02/10] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 1733316..d8bc6a1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-4125b28145b56dd1f57a46a7b5953f055c4522180140fa5b36f2a7cf0eb3a30b.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-caf996001bdccbdc93d88c448cff6f151034276a25b7c494eeb191d58a5c34c5.yml openapi_spec_hash: a3d001964480c894a5b6cb9ffa4fa47b config_hash: 3ab31decde29ec61e02db7dcb5313f82 From 3ab97d9f5daea08054fba6086ca2c1849289d8ff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 04:03:16 +0000 Subject: [PATCH 03/10] chore(internal): reformat pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4893044..7039faf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,7 +154,7 @@ show_error_codes = true # # We also exclude our `tests` as mypy doesn't always infer # types correctly and Pyright will still catch any type errors. -exclude = ['src/linq/_files.py', '_dev/.*.py', 'tests/.*'] +exclude = ["src/linq/_files.py", "_dev/.*.py", "tests/.*"] strict_equality = true implicit_reexport = true From ae5f1461f6468c48ec88d999d59293e2f364ddd6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 21:24:39 +0000 Subject: [PATCH 04/10] feat(chat-service): expose health_score.updated_at on chat reads + webhooks --- .stats.yml | 4 ++-- src/linq/types/chat.py | 3 +++ src/linq/types/chat_create_response.py | 4 ++++ src/linq/types/message_event_v2.py | 3 +++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d8bc6a1..cc15275 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-caf996001bdccbdc93d88c448cff6f151034276a25b7c494eeb191d58a5c34c5.yml -openapi_spec_hash: a3d001964480c894a5b6cb9ffa4fa47b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-f52596449498b8035cf2b0b6134e04f7a9ddbe0286bac18b2aa777af11b64721.yml +openapi_spec_hash: 6175408f7082dba8242e588b768659d1 config_hash: 3ab31decde29ec61e02db7dcb5313f82 diff --git a/src/linq/types/chat.py b/src/linq/types/chat.py index 43aaeba..359fb20 100644 --- a/src/linq/types/chat.py +++ b/src/linq/types/chat.py @@ -23,6 +23,9 @@ class HealthScore(BaseModel): score: int """Health score from 0 to 100. Higher is healthier.""" + updated_at: datetime + """When this health score was last computed.""" + class Chat(BaseModel): id: str diff --git a/src/linq/types/chat_create_response.py b/src/linq/types/chat_create_response.py index 50c26d0..58cd7f5 100644 --- a/src/linq/types/chat_create_response.py +++ b/src/linq/types/chat_create_response.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Optional +from datetime import datetime from .._models import BaseModel from .chats.sent_message import SentMessage @@ -23,6 +24,9 @@ class ChatHealthScore(BaseModel): score: int """Health score from 0 to 100. Higher is healthier.""" + updated_at: datetime + """When this health score was last computed.""" + class Chat(BaseModel): id: str diff --git a/src/linq/types/message_event_v2.py b/src/linq/types/message_event_v2.py index 06360ab..f28e803 100644 --- a/src/linq/types/message_event_v2.py +++ b/src/linq/types/message_event_v2.py @@ -28,6 +28,9 @@ class ChatHealthScore(BaseModel): score: int """Health score from 0 to 100. Higher is healthier.""" + updated_at: datetime + """When this health score was last computed.""" + class Chat(BaseModel): """Chat information""" From cfe66814352435b5cca1f586a04343b3635a5e3b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 17:36:51 +0000 Subject: [PATCH 05/10] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cc15275..bc6ff2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-f52596449498b8035cf2b0b6134e04f7a9ddbe0286bac18b2aa777af11b64721.yml -openapi_spec_hash: 6175408f7082dba8242e588b768659d1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-39592002e94ea1907c9330a0853d8025e2e89a57390970800291a7940cf80922.yml +openapi_spec_hash: f7c86b1f5c9fbe85bf6813bfe568993f config_hash: 3ab31decde29ec61e02db7dcb5313f82 From d4e37118b71348796cb029bed6f3b831c3996941 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 18:03:06 +0000 Subject: [PATCH 06/10] docs(openapi): add HealthStatus [BETA] + deprecate HealthScore --- .stats.yml | 4 +- src/linq/types/chat.py | 64 ++++++++++++++++++++--- src/linq/types/chat_create_response.py | 64 ++++++++++++++++++++--- src/linq/types/message_event_v2.py | 71 +++++++++++++++++++++++--- 4 files changed, 180 insertions(+), 23 deletions(-) diff --git a/.stats.yml b/.stats.yml index bc6ff2e..1180c31 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-39592002e94ea1907c9330a0853d8025e2e89a57390970800291a7940cf80922.yml -openapi_spec_hash: f7c86b1f5c9fbe85bf6813bfe568993f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-88cc80d3e8400e4b11ae0bd3892f1a4961b7bcdd5d0f5a0c30900f3c446dfcd0.yml +openapi_spec_hash: 4df352407b51ce1f2254725c836119ec config_hash: 3ab31decde29ec61e02db7dcb5313f82 diff --git a/src/linq/types/chat.py b/src/linq/types/chat.py index 359fb20..4ec5b15 100644 --- a/src/linq/types/chat.py +++ b/src/linq/types/chat.py @@ -2,19 +2,47 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from .._models import BaseModel from .shared.chat_handle import ChatHandle from .shared.service_type import ServiceType -__all__ = ["Chat", "HealthScore"] +__all__ = ["Chat", "HealthStatus", "HealthScore"] + + +class HealthStatus(BaseModel): + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and delivery signals on the conversation. Many `at_risk` or `critical` chats on a single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is the long-term contract. Each status carries a `doc_url` that deep-links to the relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status means and how to react. + """ + + doc_url: str + """Deep-link to the relevant section of the Chat Health guide for this status.""" + + status: Literal["healthy", "at_risk", "critical", "opted_out"] + """Current health bucket for the chat. + + See the [Chat Health guide](/guides/chats/chat-health) for what each value means + and how to react. `doc_url` deep-links to the relevant section. + """ + + updated_at: datetime + """When this status last changed.""" class HealthScore(BaseModel): - """**[BETA]** Health assessment for a chat. + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - Higher `score` is healthier. - `null` when a score isn't available yet. Scoring may change during beta. + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. """ reason: str @@ -48,6 +76,21 @@ class Chat(BaseModel): participant). """ + health_status: HealthStatus + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and + delivery signals on the conversation. Many `at_risk` or `critical` chats on a + single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is + the long-term contract. Each status carries a `doc_url` that deep-links to the + relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status + means and how to react. + """ + is_archived: bool """Whether the chat is archived""" @@ -58,10 +101,17 @@ class Chat(BaseModel): """When the chat was last updated""" health_score: Optional[HealthScore] = None - """**[BETA]** Health assessment for a chat. + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health + scores across multiple chats increase risk of line flagging. Scoring model may + change during beta. This field will be removed in a future release; partners on + new integrations should switch on `health_status.status`. - Higher `score` is healthier. `null` when a score isn't available yet. Scoring - may change during beta. + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and + how it relates to line health. """ service: Optional[ServiceType] = None diff --git a/src/linq/types/chat_create_response.py b/src/linq/types/chat_create_response.py index 58cd7f5..9a5df15 100644 --- a/src/linq/types/chat_create_response.py +++ b/src/linq/types/chat_create_response.py @@ -2,20 +2,48 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from .._models import BaseModel from .chats.sent_message import SentMessage from .shared.chat_handle import ChatHandle from .shared.service_type import ServiceType -__all__ = ["ChatCreateResponse", "Chat", "ChatHealthScore"] +__all__ = ["ChatCreateResponse", "Chat", "ChatHealthStatus", "ChatHealthScore"] + + +class ChatHealthStatus(BaseModel): + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and delivery signals on the conversation. Many `at_risk` or `critical` chats on a single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is the long-term contract. Each status carries a `doc_url` that deep-links to the relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status means and how to react. + """ + + doc_url: str + """Deep-link to the relevant section of the Chat Health guide for this status.""" + + status: Literal["healthy", "at_risk", "critical", "opted_out"] + """Current health bucket for the chat. + + See the [Chat Health guide](/guides/chats/chat-health) for what each value means + and how to react. `doc_url` deep-links to the relevant section. + """ + + updated_at: datetime + """When this status last changed.""" class ChatHealthScore(BaseModel): - """**[BETA]** Health assessment for a chat. + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - Higher `score` is healthier. - `null` when a score isn't available yet. Scoring may change during beta. + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. """ reason: str @@ -46,6 +74,21 @@ class Chat(BaseModel): participant). """ + health_status: ChatHealthStatus + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and + delivery signals on the conversation. Many `at_risk` or `critical` chats on a + single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is + the long-term contract. Each status carries a `doc_url` that deep-links to the + relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status + means and how to react. + """ + is_group: bool """Whether this is a group chat""" @@ -56,10 +99,17 @@ class Chat(BaseModel): """Messaging service type""" health_score: Optional[ChatHealthScore] = None - """**[BETA]** Health assessment for a chat. + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health + scores across multiple chats increase risk of line flagging. Scoring model may + change during beta. This field will be removed in a future release; partners on + new integrations should switch on `health_status.status`. - Higher `score` is healthier. `null` when a score isn't available yet. Scoring - may change during beta. + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and + how it relates to line health. """ diff --git a/src/linq/types/message_event_v2.py b/src/linq/types/message_event_v2.py index f28e803..dd4ab38 100644 --- a/src/linq/types/message_event_v2.py +++ b/src/linq/types/message_event_v2.py @@ -12,14 +12,25 @@ from .schemas_text_part_response import SchemasTextPartResponse from .schemas_media_part_response import SchemasMediaPartResponse -__all__ = ["MessageEventV2", "Chat", "ChatHealthScore", "Part", "PartSchemasLinkPartResponse", "ReplyTo"] +__all__ = [ + "MessageEventV2", + "Chat", + "ChatHealthScore", + "ChatHealthStatus", + "Part", + "PartSchemasLinkPartResponse", + "ReplyTo", +] class ChatHealthScore(BaseModel): - """**[BETA]** Health assessment for a chat. + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - Higher `score` is healthier. - `null` when a score isn't available yet. Scoring may change during beta. + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. """ reason: str @@ -32,6 +43,30 @@ class ChatHealthScore(BaseModel): """When this health score was last computed.""" +class ChatHealthStatus(BaseModel): + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and delivery signals on the conversation. Many `at_risk` or `critical` chats on a single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is the long-term contract. Each status carries a `doc_url` that deep-links to the relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status means and how to react. + """ + + doc_url: str + """Deep-link to the relevant section of the Chat Health guide for this status.""" + + status: Literal["healthy", "at_risk", "critical", "opted_out"] + """Current health bucket for the chat. + + See the [Chat Health guide](/guides/chats/chat-health) for what each value means + and how to react. `doc_url` deep-links to the relevant section. + """ + + updated_at: datetime + """When this status last changed.""" + + class Chat(BaseModel): """Chat information""" @@ -39,10 +74,32 @@ class Chat(BaseModel): """Chat identifier""" health_score: Optional[ChatHealthScore] = None - """**[BETA]** Health assessment for a chat. + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health + scores across multiple chats increase risk of line flagging. Scoring model may + change during beta. This field will be removed in a future release; partners on + new integrations should switch on `health_status.status`. + + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and + how it relates to line health. + """ + + health_status: Optional[ChatHealthStatus] = None + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and + delivery signals on the conversation. Many `at_risk` or `critical` chats on a + single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is + the long-term contract. Each status carries a `doc_url` that deep-links to the + relevant section of the Chat Health guide. - Higher `score` is healthier. `null` when a score isn't available yet. Scoring - may change during beta. + See the [Chat Health guide](/guides/chats/chat-health) for what each status + means and how to react. """ is_group: Optional[bool] = None From ff222969e755bd20e352de665b5e7fe47ea99705 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 20:08:03 +0000 Subject: [PATCH 07/10] fix(chat-service): stamp health_status from risk-service sync reply --- .stats.yml | 4 +- src/linq/types/chat_created_webhook_event.py | 42 ++++++++++- .../types/message_edited_webhook_event.py | 41 ++++++++++- src/linq/types/message_event_v2.py | 70 +++++++++---------- 4 files changed, 118 insertions(+), 39 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1180c31..dd48493 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-88cc80d3e8400e4b11ae0bd3892f1a4961b7bcdd5d0f5a0c30900f3c446dfcd0.yml -openapi_spec_hash: 4df352407b51ce1f2254725c836119ec +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-322ceada126beab916cee4e28b48a9e80b1f22d57ae821c3590eca1267eea307.yml +openapi_spec_hash: 2c7bd0a81edf9239e83139d4dbccbb90 config_hash: 3ab31decde29ec61e02db7dcb5313f82 diff --git a/src/linq/types/chat_created_webhook_event.py b/src/linq/types/chat_created_webhook_event.py index 88678bc..0ac3883 100644 --- a/src/linq/types/chat_created_webhook_event.py +++ b/src/linq/types/chat_created_webhook_event.py @@ -2,13 +2,38 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from .._models import BaseModel from .shared.chat_handle import ChatHandle from .webhook_event_type import WebhookEventType from .shared.service_type import ServiceType -__all__ = ["ChatCreatedWebhookEvent", "Data"] +__all__ = ["ChatCreatedWebhookEvent", "Data", "DataHealthStatus"] + + +class DataHealthStatus(BaseModel): + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and delivery signals on the conversation. Many `at_risk` or `critical` chats on a single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is the long-term contract. Each status carries a `doc_url` that deep-links to the relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status means and how to react. + """ + + doc_url: str + """Deep-link to the relevant section of the Chat Health guide for this status.""" + + status: Literal["healthy", "at_risk", "critical", "opted_out"] + """Current health bucket for the chat. + + See the [Chat Health guide](/guides/chats/chat-health) for what each value means + and how to react. `doc_url` deep-links to the relevant section. + """ + + updated_at: datetime + """When this status last changed.""" class Data(BaseModel): @@ -37,6 +62,21 @@ class Data(BaseModel): participant). """ + health_status: DataHealthStatus + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and + delivery signals on the conversation. Many `at_risk` or `critical` chats on a + single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is + the long-term contract. Each status carries a `doc_url` that deep-links to the + relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status + means and how to react. + """ + is_group: bool """Whether this is a group chat""" diff --git a/src/linq/types/message_edited_webhook_event.py b/src/linq/types/message_edited_webhook_event.py index 4833b6e..1202081 100644 --- a/src/linq/types/message_edited_webhook_event.py +++ b/src/linq/types/message_edited_webhook_event.py @@ -7,7 +7,31 @@ from .shared.chat_handle import ChatHandle from .webhook_event_type import WebhookEventType -__all__ = ["MessageEditedWebhookEvent", "Data", "DataChat", "DataPart"] +__all__ = ["MessageEditedWebhookEvent", "Data", "DataChat", "DataChatHealthStatus", "DataPart"] + + +class DataChatHealthStatus(BaseModel): + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and delivery signals on the conversation. Many `at_risk` or `critical` chats on a single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is the long-term contract. Each status carries a `doc_url` that deep-links to the relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status means and how to react. + """ + + doc_url: str + """Deep-link to the relevant section of the Chat Health guide for this status.""" + + status: Literal["healthy", "at_risk", "critical", "opted_out"] + """Current health bucket for the chat. + + See the [Chat Health guide](/guides/chats/chat-health) for what each value means + and how to react. `doc_url` deep-links to the relevant section. + """ + + updated_at: datetime + """When this status last changed.""" class DataChat(BaseModel): @@ -16,6 +40,21 @@ class DataChat(BaseModel): id: str """Chat identifier""" + health_status: DataChatHealthStatus + """**[BETA]** Current health for a chat. + + Always present — chats start at `healthy` and may shift based on engagement and + delivery signals on the conversation. Many `at_risk` or `critical` chats on a + single line increase the risk of line flagging. + + Switch on `status` to gate sends or surface line health in your UI — the enum is + the long-term contract. Each status carries a `doc_url` that deep-links to the + relevant section of the Chat Health guide. + + See the [Chat Health guide](/guides/chats/chat-health) for what each status + means and how to react. + """ + is_group: bool """Whether this is a group chat""" diff --git a/src/linq/types/message_event_v2.py b/src/linq/types/message_event_v2.py index dd4ab38..4e0d75b 100644 --- a/src/linq/types/message_event_v2.py +++ b/src/linq/types/message_event_v2.py @@ -15,34 +15,14 @@ __all__ = [ "MessageEventV2", "Chat", - "ChatHealthScore", "ChatHealthStatus", + "ChatHealthScore", "Part", "PartSchemasLinkPartResponse", "ReplyTo", ] -class ChatHealthScore(BaseModel): - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. - """ - - reason: str - """Short summary of what's affecting the score. Empty when the score is 100.""" - - score: int - """Health score from 0 to 100. Higher is healthier.""" - - updated_at: datetime - """When this health score was last computed.""" - - class ChatHealthStatus(BaseModel): """**[BETA]** Current health for a chat. @@ -67,27 +47,33 @@ class ChatHealthStatus(BaseModel): """When this status last changed.""" -class Chat(BaseModel): - """Chat information""" - - id: str - """Chat identifier""" - - health_score: Optional[ChatHealthScore] = None +class ChatHealthScore(BaseModel): """**[BETA — DEPRECATED]** Legacy health assessment for a chat. Use `health_status` instead — it's the long-term contract. - Higher `score` is healthier. `null` when a score isn't available yet. Low health - scores across multiple chats increase risk of line flagging. Scoring model may - change during beta. This field will be removed in a future release; partners on - new integrations should switch on `health_status.status`. + Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and - how it relates to line health. + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. """ - health_status: Optional[ChatHealthStatus] = None + reason: str + """Short summary of what's affecting the score. Empty when the score is 100.""" + + score: int + """Health score from 0 to 100. Higher is healthier.""" + + updated_at: datetime + """When this health score was last computed.""" + + +class Chat(BaseModel): + """Chat information""" + + id: str + """Chat identifier""" + + health_status: ChatHealthStatus """**[BETA]** Current health for a chat. Always present — chats start at `healthy` and may shift based on engagement and @@ -102,6 +88,20 @@ class Chat(BaseModel): means and how to react. """ + health_score: Optional[ChatHealthScore] = None + """**[BETA — DEPRECATED]** Legacy health assessment for a chat. + + Use `health_status` instead — it's the long-term contract. + + Higher `score` is healthier. `null` when a score isn't available yet. Low health + scores across multiple chats increase risk of line flagging. Scoring model may + change during beta. This field will be removed in a future release; partners on + new integrations should switch on `health_status.status`. + + See the [Chat Health guide](/guides/chats/chat-health) for what we score on and + how it relates to line health. + """ + is_group: Optional[bool] = None """Whether this is a group chat""" From 5ec27d1544c85532b8d0344b3108a88cf474db90 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 21:18:50 +0000 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20remove=20health=5Fscore=20from=20?= =?UTF-8?q?synapse=20=E2=80=94=20health=5Fstatus=20is=20the=20contract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .stats.yml | 4 +-- src/linq/types/chat.py | 36 +-------------------- src/linq/types/chat_create_response.py | 36 +-------------------- src/linq/types/message_event_v2.py | 44 +------------------------- 4 files changed, 5 insertions(+), 115 deletions(-) diff --git a/.stats.yml b/.stats.yml index dd48493..2cd53f2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-322ceada126beab916cee4e28b48a9e80b1f22d57ae821c3590eca1267eea307.yml -openapi_spec_hash: 2c7bd0a81edf9239e83139d4dbccbb90 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-4f67089dc5ea5bffa511c6efe29e2aa2b687f163bd59b83c92bcac8bf738dc76.yml +openapi_spec_hash: 7f7fc9c6b4b88f6a37126d60a0f2411c config_hash: 3ab31decde29ec61e02db7dcb5313f82 diff --git a/src/linq/types/chat.py b/src/linq/types/chat.py index 4ec5b15..1d0138d 100644 --- a/src/linq/types/chat.py +++ b/src/linq/types/chat.py @@ -8,7 +8,7 @@ from .shared.chat_handle import ChatHandle from .shared.service_type import ServiceType -__all__ = ["Chat", "HealthStatus", "HealthScore"] +__all__ = ["Chat", "HealthStatus"] class HealthStatus(BaseModel): @@ -35,26 +35,6 @@ class HealthStatus(BaseModel): """When this status last changed.""" -class HealthScore(BaseModel): - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. - """ - - reason: str - """Short summary of what's affecting the score. Empty when the score is 100.""" - - score: int - """Health score from 0 to 100. Higher is healthier.""" - - updated_at: datetime - """When this health score was last computed.""" - - class Chat(BaseModel): id: str """Unique identifier for the chat""" @@ -100,19 +80,5 @@ class Chat(BaseModel): updated_at: datetime """When the chat was last updated""" - health_score: Optional[HealthScore] = None - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health - scores across multiple chats increase risk of line flagging. Scoring model may - change during beta. This field will be removed in a future release; partners on - new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and - how it relates to line health. - """ - service: Optional[ServiceType] = None """Messaging service type""" diff --git a/src/linq/types/chat_create_response.py b/src/linq/types/chat_create_response.py index 9a5df15..19f3a10 100644 --- a/src/linq/types/chat_create_response.py +++ b/src/linq/types/chat_create_response.py @@ -9,7 +9,7 @@ from .shared.chat_handle import ChatHandle from .shared.service_type import ServiceType -__all__ = ["ChatCreateResponse", "Chat", "ChatHealthStatus", "ChatHealthScore"] +__all__ = ["ChatCreateResponse", "Chat", "ChatHealthStatus"] class ChatHealthStatus(BaseModel): @@ -36,26 +36,6 @@ class ChatHealthStatus(BaseModel): """When this status last changed.""" -class ChatHealthScore(BaseModel): - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. - """ - - reason: str - """Short summary of what's affecting the score. Empty when the score is 100.""" - - score: int - """Health score from 0 to 100. Higher is healthier.""" - - updated_at: datetime - """When this health score was last computed.""" - - class Chat(BaseModel): id: str """Unique identifier for the created chat (UUID)""" @@ -98,20 +78,6 @@ class Chat(BaseModel): service: ServiceType """Messaging service type""" - health_score: Optional[ChatHealthScore] = None - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health - scores across multiple chats increase risk of line flagging. Scoring model may - change during beta. This field will be removed in a future release; partners on - new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and - how it relates to line health. - """ - class ChatCreateResponse(BaseModel): """Response for creating a new chat with an initial message""" diff --git a/src/linq/types/message_event_v2.py b/src/linq/types/message_event_v2.py index 4e0d75b..28ba778 100644 --- a/src/linq/types/message_event_v2.py +++ b/src/linq/types/message_event_v2.py @@ -12,15 +12,7 @@ from .schemas_text_part_response import SchemasTextPartResponse from .schemas_media_part_response import SchemasMediaPartResponse -__all__ = [ - "MessageEventV2", - "Chat", - "ChatHealthStatus", - "ChatHealthScore", - "Part", - "PartSchemasLinkPartResponse", - "ReplyTo", -] +__all__ = ["MessageEventV2", "Chat", "ChatHealthStatus", "Part", "PartSchemasLinkPartResponse", "ReplyTo"] class ChatHealthStatus(BaseModel): @@ -47,26 +39,6 @@ class ChatHealthStatus(BaseModel): """When this status last changed.""" -class ChatHealthScore(BaseModel): - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health scores across multiple chats increase risk of line flagging. Scoring model may change during beta. This field will be removed in a future release; partners on new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and how it relates to line health. - """ - - reason: str - """Short summary of what's affecting the score. Empty when the score is 100.""" - - score: int - """Health score from 0 to 100. Higher is healthier.""" - - updated_at: datetime - """When this health score was last computed.""" - - class Chat(BaseModel): """Chat information""" @@ -88,20 +60,6 @@ class Chat(BaseModel): means and how to react. """ - health_score: Optional[ChatHealthScore] = None - """**[BETA — DEPRECATED]** Legacy health assessment for a chat. - - Use `health_status` instead — it's the long-term contract. - - Higher `score` is healthier. `null` when a score isn't available yet. Low health - scores across multiple chats increase risk of line flagging. Scoring model may - change during beta. This field will be removed in a future release; partners on - new integrations should switch on `health_status.status`. - - See the [Chat Health guide](/guides/chats/chat-health) for what we score on and - how it relates to line health. - """ - is_group: Optional[bool] = None """Whether this is a group chat""" From 6a37d71c0aa57feefc85810a5012da74153b835f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 01:00:38 +0000 Subject: [PATCH 09/10] docs(openapi): add named examples to unblock docs OpExample --- .stats.yml | 4 ++-- tests/api_resources/test_contact_card.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2cd53f2..28d4e49 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-4f67089dc5ea5bffa511c6efe29e2aa2b687f163bd59b83c92bcac8bf738dc76.yml -openapi_spec_hash: 7f7fc9c6b4b88f6a37126d60a0f2411c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/linq/linq-api-v3-68d71a6222b9b76fc00fbf74cb8ac86e5e5a6a65a472969269c912235e3c4cf7.yml +openapi_spec_hash: 8fdc1be6f5741bc4d478af7eddfff24c config_hash: 3ab31decde29ec61e02db7dcb5313f82 diff --git a/tests/api_resources/test_contact_card.py b/tests/api_resources/test_contact_card.py index 11bd6a6..ae0bc6c 100644 --- a/tests/api_resources/test_contact_card.py +++ b/tests/api_resources/test_contact_card.py @@ -24,7 +24,7 @@ class TestContactCard: @parametrize def test_method_create(self, client: LinqAPIV3) -> None: contact_card = client.contact_card.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", ) assert_matches_type(SetContactCard, contact_card, path=["response"]) @@ -33,10 +33,10 @@ def test_method_create(self, client: LinqAPIV3) -> None: @parametrize def test_method_create_with_all_params(self, client: LinqAPIV3) -> None: contact_card = client.contact_card.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", image_url="https://cdn.linqapp.com/contact-card/example.jpg", - last_name="Doe", + last_name="Support", ) assert_matches_type(SetContactCard, contact_card, path=["response"]) @@ -44,7 +44,7 @@ def test_method_create_with_all_params(self, client: LinqAPIV3) -> None: @parametrize def test_raw_response_create(self, client: LinqAPIV3) -> None: response = client.contact_card.with_raw_response.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", ) @@ -57,7 +57,7 @@ def test_raw_response_create(self, client: LinqAPIV3) -> None: @parametrize def test_streaming_response_create(self, client: LinqAPIV3) -> None: with client.contact_card.with_streaming_response.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", ) as response: assert not response.is_closed @@ -159,7 +159,7 @@ class TestAsyncContactCard: @parametrize async def test_method_create(self, async_client: AsyncLinqAPIV3) -> None: contact_card = await async_client.contact_card.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", ) assert_matches_type(SetContactCard, contact_card, path=["response"]) @@ -168,10 +168,10 @@ async def test_method_create(self, async_client: AsyncLinqAPIV3) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncLinqAPIV3) -> None: contact_card = await async_client.contact_card.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", image_url="https://cdn.linqapp.com/contact-card/example.jpg", - last_name="Doe", + last_name="Support", ) assert_matches_type(SetContactCard, contact_card, path=["response"]) @@ -179,7 +179,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncLinqAPIV3) @parametrize async def test_raw_response_create(self, async_client: AsyncLinqAPIV3) -> None: response = await async_client.contact_card.with_raw_response.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", ) @@ -192,7 +192,7 @@ async def test_raw_response_create(self, async_client: AsyncLinqAPIV3) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncLinqAPIV3) -> None: async with async_client.contact_card.with_streaming_response.create( - first_name="John", + first_name="Acme", phone_number="+15551234567", ) as response: assert not response.is_closed From 9149bedac5cf430d5424f77e6efe8898867c392d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 01:50:49 +0000 Subject: [PATCH 10/10] release: 0.8.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 25 +++++++++++++++++++++++++ pyproject.toml | 2 +- src/linq/_version.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1b77f50..6538ca9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.7.0" + ".": "0.8.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b99d8..00dd039 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 0.8.0 (2026-05-07) + +Full Changelog: [v0.7.0...v0.8.0](https://github.com/linq-team/linq-python/compare/v0.7.0...v0.8.0) + +### Features + +* **chat-service:** expose health_score.updated_at on chat reads + webhooks ([ae5f146](https://github.com/linq-team/linq-python/commit/ae5f1461f6468c48ec88d999d59293e2f364ddd6)) +* remove health_score from synapse — health_status is the contract ([5ec27d1](https://github.com/linq-team/linq-python/commit/5ec27d1544c85532b8d0344b3108a88cf474db90)) + + +### Bug Fixes + +* **chat-service:** stamp health_status from risk-service sync reply ([ff22296](https://github.com/linq-team/linq-python/commit/ff222969e755bd20e352de665b5e7fe47ea99705)) + + +### Chores + +* **internal:** reformat pyproject.toml ([3ab97d9](https://github.com/linq-team/linq-python/commit/3ab97d9f5daea08054fba6086ca2c1849289d8ff)) + + +### Documentation + +* **openapi:** add HealthStatus [BETA] + deprecate HealthScore ([d4e3711](https://github.com/linq-team/linq-python/commit/d4e37118b71348796cb029bed6f3b831c3996941)) +* **openapi:** add named examples to unblock docs OpExample ([6a37d71](https://github.com/linq-team/linq-python/commit/6a37d71c0aa57feefc85810a5012da74153b835f)) + ## 0.7.0 (2026-04-30) Full Changelog: [v0.6.0...v0.7.0](https://github.com/linq-team/linq-python/compare/v0.6.0...v0.7.0) diff --git a/pyproject.toml b/pyproject.toml index 7039faf..5ac8aba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "linq-python" -version = "0.7.0" +version = "0.8.0" description = "The official Python library for the linq-api-v3 API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/linq/_version.py b/src/linq/_version.py index 38bd5ac..57ea29d 100644 --- a/src/linq/_version.py +++ b/src/linq/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "linq" -__version__ = "0.7.0" # x-release-please-version +__version__ = "0.8.0" # x-release-please-version