linq-python 0.12.0__tar.gz → 0.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. linq_python-0.13.0/.release-please-manifest.json +3 -0
  2. linq_python-0.13.0/CHANGELOG.md +8 -0
  3. {linq_python-0.12.0 → linq_python-0.13.0}/PKG-INFO +5 -3
  4. {linq_python-0.12.0 → linq_python-0.13.0}/README.md +2 -2
  5. {linq_python-0.12.0 → linq_python-0.13.0}/api.md +1 -1
  6. {linq_python-0.12.0 → linq_python-0.13.0}/pyproject.toml +2 -1
  7. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/__init__.py +2 -0
  8. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_client.py +22 -2
  9. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_exceptions.py +4 -0
  10. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_version.py +1 -1
  11. linq_python-0.13.0/src/linq/resources/webhooks.py +69 -0
  12. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/__init__.py +1 -1
  13. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/sent_message.py +5 -2
  14. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message.py +12 -3
  15. linq_python-0.12.0/src/linq/types/events_webhook_event.py → linq_python-0.13.0/src/linq/types/unwrap_webhook_event.py +2 -2
  16. linq_python-0.13.0/tests/api_resources/test_webhooks.py +103 -0
  17. {linq_python-0.12.0 → linq_python-0.13.0}/uv.lock +156 -3
  18. linq_python-0.12.0/.release-please-manifest.json +0 -3
  19. linq_python-0.12.0/CHANGELOG.md +0 -8
  20. linq_python-0.12.0/src/linq/resources/webhooks.py +0 -34
  21. linq_python-0.12.0/tests/api_resources/test_webhooks.py +0 -19
  22. {linq_python-0.12.0 → linq_python-0.13.0}/.gitignore +0 -0
  23. {linq_python-0.12.0 → linq_python-0.13.0}/CONTRIBUTING.md +0 -0
  24. {linq_python-0.12.0 → linq_python-0.13.0}/LICENSE +0 -0
  25. {linq_python-0.12.0 → linq_python-0.13.0}/SECURITY.md +0 -0
  26. {linq_python-0.12.0 → linq_python-0.13.0}/bin/check-release-environment +0 -0
  27. {linq_python-0.12.0 → linq_python-0.13.0}/bin/publish-pypi +0 -0
  28. {linq_python-0.12.0 → linq_python-0.13.0}/examples/.keep +0 -0
  29. {linq_python-0.12.0 → linq_python-0.13.0}/release-please-config.json +0 -0
  30. {linq_python-0.12.0 → linq_python-0.13.0}/requirements-dev.lock +0 -0
  31. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_base_client.py +0 -0
  32. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_compat.py +0 -0
  33. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_constants.py +0 -0
  34. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_files.py +0 -0
  35. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_models.py +0 -0
  36. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_qs.py +0 -0
  37. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_resource.py +0 -0
  38. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_response.py +0 -0
  39. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_streaming.py +0 -0
  40. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_types.py +0 -0
  41. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/__init__.py +0 -0
  42. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_compat.py +0 -0
  43. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_datetime_parse.py +0 -0
  44. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_json.py +0 -0
  45. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_logs.py +0 -0
  46. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_path.py +0 -0
  47. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_proxy.py +0 -0
  48. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_reflection.py +0 -0
  49. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_resources_proxy.py +0 -0
  50. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_streams.py +0 -0
  51. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_sync.py +0 -0
  52. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_transform.py +0 -0
  53. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_typing.py +0 -0
  54. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/_utils/_utils.py +0 -0
  55. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/lib/.keep +0 -0
  56. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/pagination.py +0 -0
  57. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/py.typed +0 -0
  58. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/__init__.py +0 -0
  59. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/attachments.py +0 -0
  60. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/capability.py +0 -0
  61. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/chats/__init__.py +0 -0
  62. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/chats/chats.py +0 -0
  63. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/chats/location.py +0 -0
  64. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/chats/messages.py +0 -0
  65. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/chats/participants.py +0 -0
  66. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/chats/typing.py +0 -0
  67. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/contact_card.py +0 -0
  68. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/messages.py +0 -0
  69. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/phone_numbers.py +0 -0
  70. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/phonenumbers.py +0 -0
  71. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/webhook_events.py +0 -0
  72. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/resources/webhook_subscriptions.py +0 -0
  73. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/attachment_create_params.py +0 -0
  74. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/attachment_create_response.py +0 -0
  75. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/attachment_retrieve_response.py +0 -0
  76. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/capability_check_RCS_params.py +0 -0
  77. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/capability_check_i_message_params.py +0 -0
  78. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat.py +0 -0
  79. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_create_params.py +0 -0
  80. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_create_response.py +0 -0
  81. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_created_webhook_event.py +0 -0
  82. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_group_icon_update_failed_webhook_event.py +0 -0
  83. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_group_icon_updated_webhook_event.py +0 -0
  84. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_group_name_update_failed_webhook_event.py +0 -0
  85. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_group_name_updated_webhook_event.py +0 -0
  86. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_leave_chat_response.py +0 -0
  87. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_list_chats_params.py +0 -0
  88. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_send_voicememo_params.py +0 -0
  89. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_send_voicememo_response.py +0 -0
  90. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_typing_indicator_started_webhook_event.py +0 -0
  91. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_typing_indicator_stopped_webhook_event.py +0 -0
  92. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_update_params.py +0 -0
  93. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chat_update_response.py +0 -0
  94. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/__init__.py +0 -0
  95. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/get_chat_location_response.py +0 -0
  96. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/location_request_response.py +0 -0
  97. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/message_list_params.py +0 -0
  98. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/message_send_params.py +0 -0
  99. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/message_send_response.py +0 -0
  100. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/participant_add_params.py +0 -0
  101. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/participant_add_response.py +0 -0
  102. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/participant_remove_params.py +0 -0
  103. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/chats/participant_remove_response.py +0 -0
  104. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/contact_card_create_params.py +0 -0
  105. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/contact_card_retrieve_params.py +0 -0
  106. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/contact_card_retrieve_response.py +0 -0
  107. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/contact_card_update_params.py +0 -0
  108. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/handle_check_response.py +0 -0
  109. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/link_part_param.py +0 -0
  110. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/media_part_param.py +0 -0
  111. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_add_reaction_params.py +0 -0
  112. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_add_reaction_response.py +0 -0
  113. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_content_param.py +0 -0
  114. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_delivered_webhook_event.py +0 -0
  115. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_edited_webhook_event.py +0 -0
  116. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_effect.py +0 -0
  117. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_effect_param.py +0 -0
  118. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_event_v2.py +0 -0
  119. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_failed_webhook_event.py +0 -0
  120. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_list_messages_thread_params.py +0 -0
  121. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_read_webhook_event.py +0 -0
  122. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_received_webhook_event.py +0 -0
  123. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_sent_webhook_event.py +0 -0
  124. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/message_update_params.py +0 -0
  125. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/participant_added_webhook_event.py +0 -0
  126. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/participant_removed_webhook_event.py +0 -0
  127. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/phone_number_list_response.py +0 -0
  128. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/phone_number_status_updated_webhook_event.py +0 -0
  129. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/phonenumber_list_response.py +0 -0
  130. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/reaction_added_webhook_event.py +0 -0
  131. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/reaction_event_base.py +0 -0
  132. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/reaction_removed_webhook_event.py +0 -0
  133. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/reply_to.py +0 -0
  134. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/reply_to_param.py +0 -0
  135. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/schemas_media_part_response.py +0 -0
  136. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/schemas_message_effect.py +0 -0
  137. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/schemas_text_part_response.py +0 -0
  138. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/set_contact_card.py +0 -0
  139. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/__init__.py +0 -0
  140. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/chat_handle.py +0 -0
  141. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/link_part_response.py +0 -0
  142. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/media_part_response.py +0 -0
  143. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/reaction.py +0 -0
  144. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/reaction_type.py +0 -0
  145. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/service_type.py +0 -0
  146. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/text_decoration.py +0 -0
  147. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared/text_part_response.py +0 -0
  148. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared_params/__init__.py +0 -0
  149. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared_params/reaction_type.py +0 -0
  150. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared_params/service_type.py +0 -0
  151. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/shared_params/text_decoration.py +0 -0
  152. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/supported_content_type.py +0 -0
  153. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/text_part_param.py +0 -0
  154. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_event_list_response.py +0 -0
  155. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_event_type.py +0 -0
  156. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_subscription.py +0 -0
  157. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_subscription_create_params.py +0 -0
  158. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_subscription_create_response.py +0 -0
  159. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_subscription_list_response.py +0 -0
  160. {linq_python-0.12.0 → linq_python-0.13.0}/src/linq/types/webhook_subscription_update_params.py +0 -0
  161. {linq_python-0.12.0 → linq_python-0.13.0}/tests/__init__.py +0 -0
  162. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/__init__.py +0 -0
  163. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/chats/__init__.py +0 -0
  164. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/chats/test_location.py +0 -0
  165. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/chats/test_messages.py +0 -0
  166. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/chats/test_participants.py +0 -0
  167. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/chats/test_typing.py +0 -0
  168. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_attachments.py +0 -0
  169. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_capability.py +0 -0
  170. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_chats.py +0 -0
  171. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_contact_card.py +0 -0
  172. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_messages.py +0 -0
  173. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_phone_numbers.py +0 -0
  174. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_phonenumbers.py +0 -0
  175. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_webhook_events.py +0 -0
  176. {linq_python-0.12.0 → linq_python-0.13.0}/tests/api_resources/test_webhook_subscriptions.py +0 -0
  177. {linq_python-0.12.0 → linq_python-0.13.0}/tests/conftest.py +0 -0
  178. {linq_python-0.12.0 → linq_python-0.13.0}/tests/sample_file.txt +0 -0
  179. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_client.py +0 -0
  180. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_extract_files.py +0 -0
  181. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_files.py +0 -0
  182. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_models.py +0 -0
  183. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_qs.py +0 -0
  184. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_required_args.py +0 -0
  185. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_response.py +0 -0
  186. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_streaming.py +0 -0
  187. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_transform.py +0 -0
  188. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_utils/test_datetime_parse.py +0 -0
  189. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_utils/test_json.py +0 -0
  190. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_utils/test_path.py +0 -0
  191. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_utils/test_proxy.py +0 -0
  192. {linq_python-0.12.0 → linq_python-0.13.0}/tests/test_utils/test_typing.py +0 -0
  193. {linq_python-0.12.0 → linq_python-0.13.0}/tests/utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.13.0"
3
+ }
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [0.13.0](https://github.com/linq-team/linq-python/compare/v0.12.0...v0.13.0) (2026-06-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * add delivery_status field and deprecate is_read/is_delivered ([#23](https://github.com/linq-team/linq-python/issues/23)) ([0f5f6fa](https://github.com/linq-team/linq-python/commit/0f5f6fab581ea5fab03f4fe29abc916cf7a3eef4))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: linq-python
3
- Version: 0.12.0
3
+ Version: 0.13.0
4
4
  Summary: The official Python library for the linq-api-v3 API
5
5
  Project-URL: Homepage, https://github.com/linq-team/linq-python
6
6
  Project-URL: Repository, https://github.com/linq-team/linq-python
@@ -31,6 +31,8 @@ Requires-Dist: typing-extensions<5,>=4.14
31
31
  Provides-Extra: aiohttp
32
32
  Requires-Dist: aiohttp; extra == 'aiohttp'
33
33
  Requires-Dist: httpx-aiohttp>=0.1.9; extra == 'aiohttp'
34
+ Provides-Extra: webhooks
35
+ Requires-Dist: standardwebhooks<2,>=1.0.1; extra == 'webhooks'
34
36
  Description-Content-Type: text/markdown
35
37
 
36
38
  # Linq API V3 Python API library
@@ -48,8 +50,8 @@ It is generated with [Stainless](https://www.stainless.com/).
48
50
 
49
51
  Use the Linq API V3 MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
50
52
 
51
- [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5In19)
52
- [![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)
53
+ [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5IiwiTElOUV9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19)
54
+ [![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%2C%22LINQ_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)
53
55
 
54
56
  > Note: You may need to set environment variables in your MCP client.
55
57
 
@@ -13,8 +13,8 @@ It is generated with [Stainless](https://www.stainless.com/).
13
13
 
14
14
  Use the Linq API V3 MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
15
15
 
16
- [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5In19)
17
- [![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)
16
+ [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5IiwiTElOUV9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19)
17
+ [![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%2C%22LINQ_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)
18
18
 
19
19
  > Note: You may need to set environment variables in your MCP client.
20
20
 
@@ -217,7 +217,7 @@ from linq.types import (
217
217
  ChatTypingIndicatorStartedWebhookEvent,
218
218
  ChatTypingIndicatorStoppedWebhookEvent,
219
219
  PhoneNumberStatusUpdatedWebhookEvent,
220
- EventsWebhookEvent,
220
+ UnwrapWebhookEvent,
221
221
  )
222
222
  ```
223
223
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "linq-python"
3
- version = "0.12.0"
3
+ version = "0.13.0"
4
4
  description = "The official Python library for the linq-api-v3 API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -42,6 +42,7 @@ Repository = "https://github.com/linq-team/linq-python"
42
42
 
43
43
  [project.optional-dependencies]
44
44
  aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"]
45
+ webhooks = ["standardwebhooks >= 1.0.1, < 2"]
45
46
 
46
47
  [tool.uv]
47
48
  managed = true
@@ -34,6 +34,7 @@ from ._exceptions import (
34
34
  InternalServerError,
35
35
  PermissionDeniedError,
36
36
  UnprocessableEntityError,
37
+ APIWebhookValidationError,
37
38
  APIResponseValidationError,
38
39
  )
39
40
  from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
@@ -57,6 +58,7 @@ __all__ = [
57
58
  "APITimeoutError",
58
59
  "APIConnectionError",
59
60
  "APIResponseValidationError",
61
+ "APIWebhookValidationError",
60
62
  "BadRequestError",
61
63
  "AuthenticationError",
62
64
  "PermissionDeniedError",
@@ -73,11 +73,13 @@ __all__ = [
73
73
  class LinqAPIV3(SyncAPIClient):
74
74
  # client options
75
75
  api_key: str
76
+ webhook_secret: str | None
76
77
 
77
78
  def __init__(
78
79
  self,
79
80
  *,
80
81
  api_key: str | None = None,
82
+ webhook_secret: str | None = None,
81
83
  base_url: str | httpx.URL | None = None,
82
84
  timeout: float | Timeout | None | NotGiven = not_given,
83
85
  max_retries: int = DEFAULT_MAX_RETRIES,
@@ -99,7 +101,9 @@ class LinqAPIV3(SyncAPIClient):
99
101
  ) -> None:
100
102
  """Construct a new synchronous LinqAPIV3 client instance.
101
103
 
102
- This automatically infers the `api_key` argument from the `LINQ_API_V3_API_KEY` environment variable if it is not provided.
104
+ This automatically infers the following arguments from their corresponding environment variables if they are not provided:
105
+ - `api_key` from `LINQ_API_V3_API_KEY`
106
+ - `webhook_secret` from `LINQ_WEBHOOK_SECRET`
103
107
  """
104
108
  if api_key is None:
105
109
  api_key = os.environ.get("LINQ_API_V3_API_KEY")
@@ -109,6 +113,10 @@ class LinqAPIV3(SyncAPIClient):
109
113
  )
110
114
  self.api_key = api_key
111
115
 
116
+ if webhook_secret is None:
117
+ webhook_secret = os.environ.get("LINQ_WEBHOOK_SECRET")
118
+ self.webhook_secret = webhook_secret
119
+
112
120
  if base_url is None:
113
121
  base_url = os.environ.get("LINQ_API_V3_BASE_URL")
114
122
  if base_url is None:
@@ -712,6 +720,7 @@ class LinqAPIV3(SyncAPIClient):
712
720
  self,
713
721
  *,
714
722
  api_key: str | None = None,
723
+ webhook_secret: str | None = None,
715
724
  base_url: str | httpx.URL | None = None,
716
725
  timeout: float | Timeout | None | NotGiven = not_given,
717
726
  http_client: httpx.Client | None = None,
@@ -746,6 +755,7 @@ class LinqAPIV3(SyncAPIClient):
746
755
  http_client = http_client or self._client
747
756
  return self.__class__(
748
757
  api_key=api_key or self.api_key,
758
+ webhook_secret=webhook_secret or self.webhook_secret,
749
759
  base_url=base_url or self.base_url,
750
760
  timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
751
761
  http_client=http_client,
@@ -796,11 +806,13 @@ class LinqAPIV3(SyncAPIClient):
796
806
  class AsyncLinqAPIV3(AsyncAPIClient):
797
807
  # client options
798
808
  api_key: str
809
+ webhook_secret: str | None
799
810
 
800
811
  def __init__(
801
812
  self,
802
813
  *,
803
814
  api_key: str | None = None,
815
+ webhook_secret: str | None = None,
804
816
  base_url: str | httpx.URL | None = None,
805
817
  timeout: float | Timeout | None | NotGiven = not_given,
806
818
  max_retries: int = DEFAULT_MAX_RETRIES,
@@ -822,7 +834,9 @@ class AsyncLinqAPIV3(AsyncAPIClient):
822
834
  ) -> None:
823
835
  """Construct a new async AsyncLinqAPIV3 client instance.
824
836
 
825
- This automatically infers the `api_key` argument from the `LINQ_API_V3_API_KEY` environment variable if it is not provided.
837
+ This automatically infers the following arguments from their corresponding environment variables if they are not provided:
838
+ - `api_key` from `LINQ_API_V3_API_KEY`
839
+ - `webhook_secret` from `LINQ_WEBHOOK_SECRET`
826
840
  """
827
841
  if api_key is None:
828
842
  api_key = os.environ.get("LINQ_API_V3_API_KEY")
@@ -832,6 +846,10 @@ class AsyncLinqAPIV3(AsyncAPIClient):
832
846
  )
833
847
  self.api_key = api_key
834
848
 
849
+ if webhook_secret is None:
850
+ webhook_secret = os.environ.get("LINQ_WEBHOOK_SECRET")
851
+ self.webhook_secret = webhook_secret
852
+
835
853
  if base_url is None:
836
854
  base_url = os.environ.get("LINQ_API_V3_BASE_URL")
837
855
  if base_url is None:
@@ -1435,6 +1453,7 @@ class AsyncLinqAPIV3(AsyncAPIClient):
1435
1453
  self,
1436
1454
  *,
1437
1455
  api_key: str | None = None,
1456
+ webhook_secret: str | None = None,
1438
1457
  base_url: str | httpx.URL | None = None,
1439
1458
  timeout: float | Timeout | None | NotGiven = not_given,
1440
1459
  http_client: httpx.AsyncClient | None = None,
@@ -1469,6 +1488,7 @@ class AsyncLinqAPIV3(AsyncAPIClient):
1469
1488
  http_client = http_client or self._client
1470
1489
  return self.__class__(
1471
1490
  api_key=api_key or self.api_key,
1491
+ webhook_secret=webhook_secret or self.webhook_secret,
1472
1492
  base_url=base_url or self.base_url,
1473
1493
  timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
1474
1494
  http_client=http_client,
@@ -54,6 +54,10 @@ class APIResponseValidationError(APIError):
54
54
  self.status_code = response.status_code
55
55
 
56
56
 
57
+ class APIWebhookValidationError(APIError):
58
+ pass
59
+
60
+
57
61
  class APIStatusError(APIError):
58
62
  """Raised when an API response has a status code of 4xx or 5xx."""
59
63
 
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "linq"
4
- __version__ = "0.12.0" # x-release-please-version
4
+ __version__ = "0.13.0" # x-release-please-version
@@ -0,0 +1,69 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import Mapping, cast
7
+
8
+ from .._models import construct_type
9
+ from .._resource import SyncAPIResource, AsyncAPIResource
10
+ from .._exceptions import LinqApiv3Error
11
+ from ..types.unwrap_webhook_event import UnwrapWebhookEvent
12
+
13
+ __all__ = ["WebhooksResource", "AsyncWebhooksResource"]
14
+
15
+
16
+ class WebhooksResource(SyncAPIResource):
17
+ def unwrap(self, payload: str, *, headers: Mapping[str, str], key: str | bytes | None = None) -> UnwrapWebhookEvent:
18
+ try:
19
+ from standardwebhooks import Webhook
20
+ except ImportError as exc:
21
+ raise LinqApiv3Error("You need to install `linq-python[webhooks]` to use this method") from exc
22
+
23
+ if key is None:
24
+ key = self._client.webhook_secret
25
+ if key is None:
26
+ raise ValueError(
27
+ "Cannot verify a webhook without a key on either the client's webhook_secret or passed in as an argument"
28
+ )
29
+
30
+ if not isinstance(headers, dict):
31
+ headers = dict(headers)
32
+
33
+ Webhook(key).verify(payload, headers)
34
+
35
+ return cast(
36
+ UnwrapWebhookEvent,
37
+ construct_type(
38
+ type_=UnwrapWebhookEvent,
39
+ value=json.loads(payload),
40
+ ),
41
+ )
42
+
43
+
44
+ class AsyncWebhooksResource(AsyncAPIResource):
45
+ def unwrap(self, payload: str, *, headers: Mapping[str, str], key: str | bytes | None = None) -> UnwrapWebhookEvent:
46
+ try:
47
+ from standardwebhooks import Webhook
48
+ except ImportError as exc:
49
+ raise LinqApiv3Error("You need to install `linq-python[webhooks]` to use this method") from exc
50
+
51
+ if key is None:
52
+ key = self._client.webhook_secret
53
+ if key is None:
54
+ raise ValueError(
55
+ "Cannot verify a webhook without a key on either the client's webhook_secret or passed in as an argument"
56
+ )
57
+
58
+ if not isinstance(headers, dict):
59
+ headers = dict(headers)
60
+
61
+ Webhook(key).verify(payload, headers)
62
+
63
+ return cast(
64
+ UnwrapWebhookEvent,
65
+ construct_type(
66
+ type_=UnwrapWebhookEvent,
67
+ value=json.loads(payload),
68
+ ),
69
+ )
@@ -28,8 +28,8 @@ from .webhook_event_type import WebhookEventType as WebhookEventType
28
28
  from .reaction_event_base import ReactionEventBase as ReactionEventBase
29
29
  from .chat_create_response import ChatCreateResponse as ChatCreateResponse
30
30
  from .chat_update_response import ChatUpdateResponse as ChatUpdateResponse
31
- from .events_webhook_event import EventsWebhookEvent as EventsWebhookEvent
32
31
  from .message_effect_param import MessageEffectParam as MessageEffectParam
32
+ from .unwrap_webhook_event import UnwrapWebhookEvent as UnwrapWebhookEvent
33
33
  from .webhook_subscription import WebhookSubscription as WebhookSubscription
34
34
  from .handle_check_response import HandleCheckResponse as HandleCheckResponse
35
35
  from .message_content_param import MessageContentParam as MessageContentParam
@@ -27,11 +27,14 @@ class SentMessage(BaseModel):
27
27
  created_at: datetime
28
28
  """When the message was created"""
29
29
 
30
- delivery_status: Literal["pending", "queued", "sent", "delivered", "failed"]
30
+ delivery_status: Literal["pending", "queued", "sent", "delivered", "received", "read", "failed"]
31
31
  """Current delivery status of a message"""
32
32
 
33
33
  is_read: bool
34
- """Whether the message has been read"""
34
+ """DEPRECATED: Use `delivery_status == "read"` instead.
35
+
36
+ Whether the message has been read.
37
+ """
35
38
 
36
39
  parts: List[Part]
37
40
  """Message parts in order (text, media, and link)"""
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import List, Union, Optional
4
4
  from datetime import datetime
5
- from typing_extensions import TypeAlias
5
+ from typing_extensions import Literal, TypeAlias
6
6
 
7
7
  from pydantic import Field as FieldInfo
8
8
 
@@ -30,14 +30,23 @@ class Message(BaseModel):
30
30
  created_at: datetime
31
31
  """When the message was created"""
32
32
 
33
+ delivery_status: Literal["pending", "queued", "sent", "delivered", "received", "read", "failed"]
34
+ """Current delivery status of a message"""
35
+
33
36
  is_delivered: bool
34
- """Whether the message has been delivered"""
37
+ """
38
+ DEPRECATED: Use `delivery_status` instead (true when `delivery_status` is
39
+ `delivered` or `read`). Whether the message has been delivered.
40
+ """
35
41
 
36
42
  is_from_me: bool
37
43
  """Whether this message was sent by the authenticated user"""
38
44
 
39
45
  is_read: bool
40
- """Whether the message has been read"""
46
+ """DEPRECATED: Use `delivery_status == "read"` instead.
47
+
48
+ Whether the message has been read.
49
+ """
41
50
 
42
51
  updated_at: datetime
43
52
  """When the message was last updated"""
@@ -23,9 +23,9 @@ from .chat_group_name_update_failed_webhook_event import ChatGroupNameUpdateFail
23
23
  from .chat_typing_indicator_started_webhook_event import ChatTypingIndicatorStartedWebhookEvent
24
24
  from .chat_typing_indicator_stopped_webhook_event import ChatTypingIndicatorStoppedWebhookEvent
25
25
 
26
- __all__ = ["EventsWebhookEvent"]
26
+ __all__ = ["UnwrapWebhookEvent"]
27
27
 
28
- EventsWebhookEvent: TypeAlias = Annotated[
28
+ UnwrapWebhookEvent: TypeAlias = Annotated[
29
29
  Union[
30
30
  MessageSentWebhookEvent,
31
31
  MessageReceivedWebhookEvent,
@@ -0,0 +1,103 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from datetime import datetime, timezone
7
+
8
+ import pytest
9
+ import standardwebhooks
10
+
11
+ from linq import LinqAPIV3
12
+
13
+ base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
14
+
15
+
16
+ class TestWebhooks:
17
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
18
+
19
+ @pytest.mark.parametrize(
20
+ "client_opt,method_opt",
21
+ [
22
+ ("whsec_c2VjcmV0Cg==", None),
23
+ ("wrong", b"secret\n"),
24
+ ("wrong", "whsec_c2VjcmV0Cg=="),
25
+ (None, b"secret\n"),
26
+ (None, "whsec_c2VjcmV0Cg=="),
27
+ ],
28
+ )
29
+ def test_method_unwrap(self, client: LinqAPIV3, client_opt: str | None, method_opt: str | bytes | None) -> None:
30
+ hook = standardwebhooks.Webhook(b"secret\n")
31
+
32
+ client = client.with_options(webhook_secret=client_opt)
33
+
34
+ data = """{"api_version":"v3","created_at":"2025-11-23T17:30:00Z","data":{"id":"550e8400-e29b-41d4-a716-446655440001","chat":{"id":"550e8400-e29b-41d4-a716-446655440000","health_status":{"doc_url":"https://docs.linqapp.com/guides/chats/chat-health#at-risk","status":"AT_RISK","updated_at":"2026-05-01T18:28:25Z"},"is_group":true,"owner_handle":{"id":"550e8400-e29b-41d4-a716-446655440000","handle":"+15551234567","joined_at":"2025-05-21T15:30:00.000-05:00","service":"iMessage","is_me":false,"left_at":"2019-12-27T18:11:19.117Z","status":"active"}},"direction":"outbound","parts":[{"type":"text","value":"Hello!","text_decorations":[{"range":[0,5],"animation":"shake","style":"bold"}]}],"sender_handle":{"id":"550e8400-e29b-41d4-a716-446655440000","handle":"+15551234567","joined_at":"2025-05-21T15:30:00.000-05:00","service":"iMessage","is_me":false,"left_at":"2019-12-27T18:11:19.117Z","status":"active"},"service":"iMessage","delivered_at":"2026-01-30T20:49:20.352Z","effect":{"name":"gentle","type":"bubble"},"idempotency_key":"unique-key","preferred_service":"iMessage","read_at":null,"reply_to":{"message_id":"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e","part_index":0},"sent_at":"2026-01-30T20:49:19.704Z"},"event_id":"550e8400-e29b-41d4-a716-446655440000","event_type":"message.sent","partner_id":"partner_abc123","trace_id":"abc123def456","webhook_version":"2025-01-01"}"""
35
+ msg_id = "1"
36
+ timestamp = datetime.now(tz=timezone.utc)
37
+ sig = hook.sign(msg_id=msg_id, timestamp=timestamp, data=data)
38
+ headers = {
39
+ "webhook-id": msg_id,
40
+ "webhook-timestamp": str(int(timestamp.timestamp())),
41
+ "webhook-signature": sig,
42
+ }
43
+
44
+ try:
45
+ _ = client.webhooks.unwrap(data, headers=headers, key=method_opt)
46
+ except standardwebhooks.WebhookVerificationError as e:
47
+ raise AssertionError("Failed to unwrap valid webhook") from e
48
+
49
+ bad_headers = [
50
+ {**headers, "webhook-signature": hook.sign(msg_id=msg_id, timestamp=timestamp, data="xxx")},
51
+ {**headers, "webhook-id": "bad"},
52
+ {**headers, "webhook-timestamp": "0"},
53
+ ]
54
+ for bad_header in bad_headers:
55
+ with pytest.raises(standardwebhooks.WebhookVerificationError):
56
+ _ = client.webhooks.unwrap(data, headers=bad_header, key=method_opt)
57
+
58
+
59
+ class TestAsyncWebhooks:
60
+ parametrize = pytest.mark.parametrize(
61
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
62
+ )
63
+
64
+ @pytest.mark.parametrize(
65
+ "client_opt,method_opt",
66
+ [
67
+ ("whsec_c2VjcmV0Cg==", None),
68
+ ("wrong", b"secret\n"),
69
+ ("wrong", "whsec_c2VjcmV0Cg=="),
70
+ (None, b"secret\n"),
71
+ (None, "whsec_c2VjcmV0Cg=="),
72
+ ],
73
+ )
74
+ def test_method_unwrap(
75
+ self, async_client: LinqAPIV3, client_opt: str | None, method_opt: str | bytes | None
76
+ ) -> None:
77
+ hook = standardwebhooks.Webhook(b"secret\n")
78
+
79
+ async_client = async_client.with_options(webhook_secret=client_opt)
80
+
81
+ data = """{"api_version":"v3","created_at":"2025-11-23T17:30:00Z","data":{"id":"550e8400-e29b-41d4-a716-446655440001","chat":{"id":"550e8400-e29b-41d4-a716-446655440000","health_status":{"doc_url":"https://docs.linqapp.com/guides/chats/chat-health#at-risk","status":"AT_RISK","updated_at":"2026-05-01T18:28:25Z"},"is_group":true,"owner_handle":{"id":"550e8400-e29b-41d4-a716-446655440000","handle":"+15551234567","joined_at":"2025-05-21T15:30:00.000-05:00","service":"iMessage","is_me":false,"left_at":"2019-12-27T18:11:19.117Z","status":"active"}},"direction":"outbound","parts":[{"type":"text","value":"Hello!","text_decorations":[{"range":[0,5],"animation":"shake","style":"bold"}]}],"sender_handle":{"id":"550e8400-e29b-41d4-a716-446655440000","handle":"+15551234567","joined_at":"2025-05-21T15:30:00.000-05:00","service":"iMessage","is_me":false,"left_at":"2019-12-27T18:11:19.117Z","status":"active"},"service":"iMessage","delivered_at":"2026-01-30T20:49:20.352Z","effect":{"name":"gentle","type":"bubble"},"idempotency_key":"unique-key","preferred_service":"iMessage","read_at":null,"reply_to":{"message_id":"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e","part_index":0},"sent_at":"2026-01-30T20:49:19.704Z"},"event_id":"550e8400-e29b-41d4-a716-446655440000","event_type":"message.sent","partner_id":"partner_abc123","trace_id":"abc123def456","webhook_version":"2025-01-01"}"""
82
+ msg_id = "1"
83
+ timestamp = datetime.now(tz=timezone.utc)
84
+ sig = hook.sign(msg_id=msg_id, timestamp=timestamp, data=data)
85
+ headers = {
86
+ "webhook-id": msg_id,
87
+ "webhook-timestamp": str(int(timestamp.timestamp())),
88
+ "webhook-signature": sig,
89
+ }
90
+
91
+ try:
92
+ _ = async_client.webhooks.unwrap(data, headers=headers, key=method_opt)
93
+ except standardwebhooks.WebhookVerificationError as e:
94
+ raise AssertionError("Failed to unwrap valid webhook") from e
95
+
96
+ bad_headers = [
97
+ {**headers, "webhook-signature": hook.sign(msg_id=msg_id, timestamp=timestamp, data="xxx")},
98
+ {**headers, "webhook-id": "bad"},
99
+ {**headers, "webhook-timestamp": "0"},
100
+ ]
101
+ for bad_header in bad_headers:
102
+ with pytest.raises(standardwebhooks.WebhookVerificationError):
103
+ _ = async_client.webhooks.unwrap(data, headers=bad_header, key=method_opt)