diff --git a/CHANGELOG.md b/CHANGELOG.md index cb78d18..2ed8882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.15.0 + +Adds Push Notification dismissal. Pass a `notification_id` to `notifications.dismiss` to clear a Push Notification you already sent from the Lock Screen and Notification Center. History keeps it. Also adds `metrics.create` to create a Lock Screen Widget metric and set its label and format, such as currency or percent, and `devices.list` to list the iPhones and iPads paired to your account. + ## 1.14.0 Adds the ability to replace a Push Notification you already sent with a new one. diff --git a/activitysmith/client.py b/activitysmith/client.py index 4efd3ec..7983960 100644 --- a/activitysmith/client.py +++ b/activitysmith/client.py @@ -11,12 +11,13 @@ from activitysmith_openapi.api.metrics_api import MetricsApi from activitysmith_openapi.api.push_notifications_api import PushNotificationsApi from activitysmith_openapi.api.app_icon_badges_api import AppIconBadgesApi +from activitysmith_openapi.api.devices_api import DevicesApi from activitysmith_openapi.models.metric_value_update_request import MetricValueUpdateRequest from .normalization import normalize_live_activity_request, normalize_metric_request -SDK_VERSION = "1.14.0" +SDK_VERSION = "1.15.0" SDK_HEADER_NAME = "X-ActivitySmith-SDK" SDK_HEADER_VALUE = f"python-v{SDK_VERSION}" @@ -480,6 +481,17 @@ def replace_push_notification( ): return self.replace(notification_id, push_notification_replace_request, **fields) + def dismiss(self, notification_id: str): + """Clear a sent Push Notification from the Lock Screen and Notification Center. + + Pass the notification_id returned by send(). History keeps the notification. + """ + return self._api.dismiss_push_notification(notification_id=notification_id) + + # Generated-style alias. + def dismiss_push_notification(self, notification_id: str): + return self.dismiss(notification_id) + class LiveActivitiesResource: TYPE_SEGMENTED_PROGRESS = "segmented_progress" @@ -870,6 +882,33 @@ def update_metric_value(self, key: str, metric_value_update_request: Any): ) +class DevicesResource: + def __init__(self, api: DevicesApi) -> None: + self._api = api + + def list( + self, + limit: int | None = None, + offset: int | None = None, + include_inactive: bool | None = None, + ): + """List the iPhones and iPads paired to the account, active devices first.""" + return self._api.list_account_devices( + limit=limit, + offset=offset, + include_inactive=include_inactive, + ) + + # Generated-style alias. + def list_account_devices( + self, + limit: int | None = None, + offset: int | None = None, + include_inactive: bool | None = None, + ): + return self.list(limit=limit, offset=offset, include_inactive=include_inactive) + + @dataclass class ActivitySmith: api_key: str @@ -887,6 +926,7 @@ def __post_init__(self) -> None: self.notifications = NotificationsResource(PushNotificationsApi(api_client)) self.live_activities = LiveActivitiesResource(LiveActivitiesApi(api_client)) self.metrics = MetricsResource(MetricsApi(api_client)) + self.devices = DevicesResource(DevicesApi(api_client)) self._app_icon_badges = AppIconBadgesApi(api_client) def badge_count(self, value: int, *, channels: Any | None = None): diff --git a/activitysmith_openapi/__init__.py b/activitysmith_openapi/__init__.py index 56604b6..3533b9a 100644 --- a/activitysmith_openapi/__init__.py +++ b/activitysmith_openapi/__init__.py @@ -18,6 +18,7 @@ # import apis into sdk package from activitysmith_openapi.api.app_icon_badges_api import AppIconBadgesApi +from activitysmith_openapi.api.devices_api import DevicesApi from activitysmith_openapi.api.live_activities_api import LiveActivitiesApi from activitysmith_openapi.api.metrics_api import MetricsApi from activitysmith_openapi.api.push_notifications_api import PushNotificationsApi @@ -34,6 +35,9 @@ from activitysmith_openapi.exceptions import ApiException # import models into sdk package +from activitysmith_openapi.models.account_device import AccountDevice +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse +from activitysmith_openapi.models.account_device_list_response_meta import AccountDeviceListResponseMeta from activitysmith_openapi.models.activity_metric import ActivityMetric from activitysmith_openapi.models.activity_metric_value import ActivityMetricValue from activitysmith_openapi.models.alert_payload import AlertPayload @@ -79,6 +83,7 @@ from activitysmith_openapi.models.push_interruption_level import PushInterruptionLevel from activitysmith_openapi.models.push_notification_action import PushNotificationAction from activitysmith_openapi.models.push_notification_action_type import PushNotificationActionType +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse from activitysmith_openapi.models.push_notification_replace_request import PushNotificationReplaceRequest from activitysmith_openapi.models.push_notification_replace_response import PushNotificationReplaceResponse from activitysmith_openapi.models.push_notification_request import PushNotificationRequest diff --git a/activitysmith_openapi/api/__init__.py b/activitysmith_openapi/api/__init__.py index f70481e..4b47c17 100644 --- a/activitysmith_openapi/api/__init__.py +++ b/activitysmith_openapi/api/__init__.py @@ -2,6 +2,7 @@ # import apis into api package from activitysmith_openapi.api.app_icon_badges_api import AppIconBadgesApi +from activitysmith_openapi.api.devices_api import DevicesApi from activitysmith_openapi.api.live_activities_api import LiveActivitiesApi from activitysmith_openapi.api.metrics_api import MetricsApi from activitysmith_openapi.api.push_notifications_api import PushNotificationsApi diff --git a/activitysmith_openapi/api/devices_api.py b/activitysmith_openapi/api/devices_api.py new file mode 100644 index 0000000..d294278 --- /dev/null +++ b/activitysmith_openapi/api/devices_api.py @@ -0,0 +1,340 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + +import warnings +from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt +from typing import Any, Dict, List, Optional, Tuple, Union +from typing_extensions import Annotated + +from pydantic import Field, StrictBool +from typing import Optional +from typing_extensions import Annotated +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse + +from activitysmith_openapi.api_client import ApiClient, RequestSerialized +from activitysmith_openapi.api_response import ApiResponse +from activitysmith_openapi.rest import RESTResponseType + + +class DevicesApi: + """NOTE: This class is auto generated by OpenAPI Generator + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + def __init__(self, api_client=None) -> None: + if api_client is None: + api_client = ApiClient.get_default() + self.api_client = api_client + + + @validate_call + def list_account_devices( + self, + limit: Annotated[Optional[Annotated[int, Field(le=100, strict=True, ge=1)]], Field(description="Maximum devices to return, 1 to 100. Defaults to 100.")] = None, + offset: Annotated[Optional[Annotated[int, Field(strict=True, ge=0)]], Field(description="Devices to skip. Use meta.next_offset from the previous page.")] = None, + include_inactive: Annotated[Optional[StrictBool], Field(description="Include devices that can no longer receive deliveries, such as unpaired phones.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> AccountDeviceListResponse: + """List paired devices + + Lists the iPhones and iPads paired to the account, active devices first. Use it to check that a device is paired before you send, or to find device IDs for Channels. An empty list means no device is paired yet: install the ActivitySmith app from the App Store and sign in. Channel-scoped API keys cannot list devices. + + :param limit: Maximum devices to return, 1 to 100. Defaults to 100. + :type limit: int + :param offset: Devices to skip. Use meta.next_offset from the previous page. + :type offset: int + :param include_inactive: Include devices that can no longer receive deliveries, such as unpaired phones. + :type include_inactive: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._list_account_devices_serialize( + limit=limit, + offset=offset, + include_inactive=include_inactive, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "AccountDeviceListResponse", + '403': "ForbiddenError", + '429': "RateLimitError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def list_account_devices_with_http_info( + self, + limit: Annotated[Optional[Annotated[int, Field(le=100, strict=True, ge=1)]], Field(description="Maximum devices to return, 1 to 100. Defaults to 100.")] = None, + offset: Annotated[Optional[Annotated[int, Field(strict=True, ge=0)]], Field(description="Devices to skip. Use meta.next_offset from the previous page.")] = None, + include_inactive: Annotated[Optional[StrictBool], Field(description="Include devices that can no longer receive deliveries, such as unpaired phones.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[AccountDeviceListResponse]: + """List paired devices + + Lists the iPhones and iPads paired to the account, active devices first. Use it to check that a device is paired before you send, or to find device IDs for Channels. An empty list means no device is paired yet: install the ActivitySmith app from the App Store and sign in. Channel-scoped API keys cannot list devices. + + :param limit: Maximum devices to return, 1 to 100. Defaults to 100. + :type limit: int + :param offset: Devices to skip. Use meta.next_offset from the previous page. + :type offset: int + :param include_inactive: Include devices that can no longer receive deliveries, such as unpaired phones. + :type include_inactive: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._list_account_devices_serialize( + limit=limit, + offset=offset, + include_inactive=include_inactive, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "AccountDeviceListResponse", + '403': "ForbiddenError", + '429': "RateLimitError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def list_account_devices_without_preload_content( + self, + limit: Annotated[Optional[Annotated[int, Field(le=100, strict=True, ge=1)]], Field(description="Maximum devices to return, 1 to 100. Defaults to 100.")] = None, + offset: Annotated[Optional[Annotated[int, Field(strict=True, ge=0)]], Field(description="Devices to skip. Use meta.next_offset from the previous page.")] = None, + include_inactive: Annotated[Optional[StrictBool], Field(description="Include devices that can no longer receive deliveries, such as unpaired phones.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List paired devices + + Lists the iPhones and iPads paired to the account, active devices first. Use it to check that a device is paired before you send, or to find device IDs for Channels. An empty list means no device is paired yet: install the ActivitySmith app from the App Store and sign in. Channel-scoped API keys cannot list devices. + + :param limit: Maximum devices to return, 1 to 100. Defaults to 100. + :type limit: int + :param offset: Devices to skip. Use meta.next_offset from the previous page. + :type offset: int + :param include_inactive: Include devices that can no longer receive deliveries, such as unpaired phones. + :type include_inactive: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._list_account_devices_serialize( + limit=limit, + offset=offset, + include_inactive=include_inactive, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "AccountDeviceListResponse", + '403': "ForbiddenError", + '429': "RateLimitError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _list_account_devices_serialize( + self, + limit, + offset, + include_inactive, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if limit is not None: + + _query_params.append(('limit', limit)) + + if offset is not None: + + _query_params.append(('offset', offset)) + + if include_inactive is not None: + + _query_params.append(('include_inactive', include_inactive)) + + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'apiKeyAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/account/devices', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + diff --git a/activitysmith_openapi/api/live_activities_api.py b/activitysmith_openapi/api/live_activities_api.py index db54610..8b971ea 100644 --- a/activitysmith_openapi/api/live_activities_api.py +++ b/activitysmith_openapi/api/live_activities_api.py @@ -67,7 +67,7 @@ def end_live_activity( ) -> LiveActivityEndResponse: """End a Live Activity (legacy manual lifecycle) - Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. + Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. Ending a Live Activity that already ended returns 200 with ignored: true and sends nothing to devices, so retries are safe. :param live_activity_end_request: (required) :type live_activity_end_request: LiveActivityEndRequest @@ -136,7 +136,7 @@ def end_live_activity_with_http_info( ) -> ApiResponse[LiveActivityEndResponse]: """End a Live Activity (legacy manual lifecycle) - Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. + Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. Ending a Live Activity that already ended returns 200 with ignored: true and sends nothing to devices, so retries are safe. :param live_activity_end_request: (required) :type live_activity_end_request: LiveActivityEndRequest @@ -205,7 +205,7 @@ def end_live_activity_without_preload_content( ) -> RESTResponseType: """End a Live Activity (legacy manual lifecycle) - Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. + Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. Ending a Live Activity that already ended returns 200 with ignored: true and sends nothing to devices, so retries are safe. :param live_activity_end_request: (required) :type live_activity_end_request: LiveActivityEndRequest diff --git a/activitysmith_openapi/api/push_notifications_api.py b/activitysmith_openapi/api/push_notifications_api.py index 192d2e7..8a36095 100644 --- a/activitysmith_openapi/api/push_notifications_api.py +++ b/activitysmith_openapi/api/push_notifications_api.py @@ -18,6 +18,7 @@ from pydantic import Field from typing_extensions import Annotated +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse from activitysmith_openapi.models.push_notification_replace_request import PushNotificationReplaceRequest from activitysmith_openapi.models.push_notification_replace_response import PushNotificationReplaceResponse from activitysmith_openapi.models.push_notification_request import PushNotificationRequest @@ -41,6 +42,280 @@ def __init__(self, api_client=None) -> None: self.api_client = api_client + @validate_call + def dismiss_push_notification( + self, + notification_id: Annotated[str, Field(min_length=1, strict=True, description="The `notification_id` returned when the Push Notification was sent.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> PushNotificationDismissResponse: + """Dismiss a push notification + + Clears a Push Notification you already sent from the Lock Screen and Notification Center on every device it was sent to, using the `notification_id` from the send response. Notification history keeps it. Devices clear the notification in the background, which can take a moment or wait until the ActivitySmith app next opens. A successful response means the dismissal was recorded, not that every device has cleared it yet. Devices running an ActivitySmith app version before 1.17.0 show a silent notification titled \"Push Notification dismissed\" in its place until the user clears it. Calling this again for the same notification returns the same response and sends nothing. A dismissed notification cannot be replaced. + + :param notification_id: The `notification_id` returned when the Push Notification was sent. (required) + :type notification_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._dismiss_push_notification_serialize( + notification_id=notification_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "PushNotificationDismissResponse", + '402': "BillingBlockedError", + '403': "ForbiddenError", + '404': "NotFoundError", + '409': "NotFoundError", + '429': "SendPushNotification429Response", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def dismiss_push_notification_with_http_info( + self, + notification_id: Annotated[str, Field(min_length=1, strict=True, description="The `notification_id` returned when the Push Notification was sent.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[PushNotificationDismissResponse]: + """Dismiss a push notification + + Clears a Push Notification you already sent from the Lock Screen and Notification Center on every device it was sent to, using the `notification_id` from the send response. Notification history keeps it. Devices clear the notification in the background, which can take a moment or wait until the ActivitySmith app next opens. A successful response means the dismissal was recorded, not that every device has cleared it yet. Devices running an ActivitySmith app version before 1.17.0 show a silent notification titled \"Push Notification dismissed\" in its place until the user clears it. Calling this again for the same notification returns the same response and sends nothing. A dismissed notification cannot be replaced. + + :param notification_id: The `notification_id` returned when the Push Notification was sent. (required) + :type notification_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._dismiss_push_notification_serialize( + notification_id=notification_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "PushNotificationDismissResponse", + '402': "BillingBlockedError", + '403': "ForbiddenError", + '404': "NotFoundError", + '409': "NotFoundError", + '429': "SendPushNotification429Response", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def dismiss_push_notification_without_preload_content( + self, + notification_id: Annotated[str, Field(min_length=1, strict=True, description="The `notification_id` returned when the Push Notification was sent.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Dismiss a push notification + + Clears a Push Notification you already sent from the Lock Screen and Notification Center on every device it was sent to, using the `notification_id` from the send response. Notification history keeps it. Devices clear the notification in the background, which can take a moment or wait until the ActivitySmith app next opens. A successful response means the dismissal was recorded, not that every device has cleared it yet. Devices running an ActivitySmith app version before 1.17.0 show a silent notification titled \"Push Notification dismissed\" in its place until the user clears it. Calling this again for the same notification returns the same response and sends nothing. A dismissed notification cannot be replaced. + + :param notification_id: The `notification_id` returned when the Push Notification was sent. (required) + :type notification_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._dismiss_push_notification_serialize( + notification_id=notification_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "PushNotificationDismissResponse", + '402': "BillingBlockedError", + '403': "ForbiddenError", + '404': "NotFoundError", + '409': "NotFoundError", + '429': "SendPushNotification429Response", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _dismiss_push_notification_serialize( + self, + notification_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if notification_id is not None: + _path_params['notification_id'] = notification_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'apiKeyAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/push-notification/{notification_id}/dismiss', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def replace_push_notification( self, diff --git a/activitysmith_openapi/docs/AccountDevice.md b/activitysmith_openapi/docs/AccountDevice.md new file mode 100644 index 0000000..7f81013 --- /dev/null +++ b/activitysmith_openapi/docs/AccountDevice.md @@ -0,0 +1,40 @@ +# AccountDevice + +An iPhone or iPad paired to the account, one entry per device and owner. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**user_email** | **str** | Email of the account member who paired the device. | +**device_id** | **str** | Device ID. Use it to assign the device to Channels. | +**device_type** | **str** | Device platform, such as ios. iPhones and iPads both report ios; use system_name to tell them apart. | +**is_active** | **bool** | True when the device can receive Push Notifications or Live Activities. | +**token_status** | **Dict[str, bool]** | Whether each delivery token is active, keyed by token type (push, start_live_activity). | +**app_version** | **str** | ActivitySmith app version on the device. | +**device_name** | **str** | Device name set on the device. | +**system_name** | **str** | Operating system name, such as iOS or iPadOS. | +**system_version** | **str** | Operating system version. | +**created_at** | **datetime** | When the device was first paired. | +**updated_at** | **datetime** | When the device last updated its pairing. | + +## Example + +```python +from activitysmith_openapi.models.account_device import AccountDevice + +# TODO update the JSON string below +json = "{}" +# create an instance of AccountDevice from a JSON string +account_device_instance = AccountDevice.from_json(json) +# print the JSON string representation of the object +print(AccountDevice.to_json()) + +# convert the object into a dict +account_device_dict = account_device_instance.to_dict() +# create an instance of AccountDevice from a dict +account_device_from_dict = AccountDevice.from_dict(account_device_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/activitysmith_openapi/docs/AccountDeviceListResponse.md b/activitysmith_openapi/docs/AccountDeviceListResponse.md new file mode 100644 index 0000000..49a5dd2 --- /dev/null +++ b/activitysmith_openapi/docs/AccountDeviceListResponse.md @@ -0,0 +1,30 @@ +# AccountDeviceListResponse + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**devices** | [**List[AccountDevice]**](AccountDevice.md) | | +**meta** | [**AccountDeviceListResponseMeta**](AccountDeviceListResponseMeta.md) | | + +## Example + +```python +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse + +# TODO update the JSON string below +json = "{}" +# create an instance of AccountDeviceListResponse from a JSON string +account_device_list_response_instance = AccountDeviceListResponse.from_json(json) +# print the JSON string representation of the object +print(AccountDeviceListResponse.to_json()) + +# convert the object into a dict +account_device_list_response_dict = account_device_list_response_instance.to_dict() +# create an instance of AccountDeviceListResponse from a dict +account_device_list_response_from_dict = AccountDeviceListResponse.from_dict(account_device_list_response_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/activitysmith_openapi/docs/AccountDeviceListResponseMeta.md b/activitysmith_openapi/docs/AccountDeviceListResponseMeta.md new file mode 100644 index 0000000..38ed9dd --- /dev/null +++ b/activitysmith_openapi/docs/AccountDeviceListResponseMeta.md @@ -0,0 +1,34 @@ +# AccountDeviceListResponseMeta + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**total** | **int** | Devices matching the filter. | +**limit** | **int** | | +**offset** | **int** | | +**has_more** | **bool** | | +**next_offset** | **int** | Offset for the next page, or null on the last page. | +**include_inactive** | **bool** | | + +## Example + +```python +from activitysmith_openapi.models.account_device_list_response_meta import AccountDeviceListResponseMeta + +# TODO update the JSON string below +json = "{}" +# create an instance of AccountDeviceListResponseMeta from a JSON string +account_device_list_response_meta_instance = AccountDeviceListResponseMeta.from_json(json) +# print the JSON string representation of the object +print(AccountDeviceListResponseMeta.to_json()) + +# convert the object into a dict +account_device_list_response_meta_dict = account_device_list_response_meta_instance.to_dict() +# create an instance of AccountDeviceListResponseMeta from a dict +account_device_list_response_meta_from_dict = AccountDeviceListResponseMeta.from_dict(account_device_list_response_meta_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/activitysmith_openapi/docs/AppIconBadgesApi.md b/activitysmith_openapi/docs/AppIconBadgesApi.md index 8b10987..d302da9 100644 --- a/activitysmith_openapi/docs/AppIconBadgesApi.md +++ b/activitysmith_openapi/docs/AppIconBadgesApi.md @@ -82,13 +82,13 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | App Icon Badge updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| +**200** | App Icon Badge updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| **402** | Billing access required | - | -**403** | Forbidden | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**422** | No matching devices found, or a targeted device needs to reconnect | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| -**502** | App Icon Badge could not be updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| +**403** | Forbidden | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**422** | No matching devices found, or a targeted device needs to reconnect | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**502** | App Icon Badge could not be updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/activitysmith_openapi/docs/DevicesApi.md b/activitysmith_openapi/docs/DevicesApi.md new file mode 100644 index 0000000..1b188f2 --- /dev/null +++ b/activitysmith_openapi/docs/DevicesApi.md @@ -0,0 +1,93 @@ +# activitysmith_openapi.DevicesApi + +All URIs are relative to *https://activitysmith.com/api* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**list_account_devices**](DevicesApi.md#list_account_devices) | **GET** /account/devices | List paired devices + + +# **list_account_devices** +> AccountDeviceListResponse list_account_devices(limit=limit, offset=offset, include_inactive=include_inactive) + +List paired devices + +Lists the iPhones and iPads paired to the account, active devices first. Use it to check that a device is paired before you send, or to find device IDs for Channels. An empty list means no device is paired yet: install the ActivitySmith app from the App Store and sign in. Channel-scoped API keys cannot list devices. + +### Example + +* Bearer (API Key) Authentication (apiKeyAuth): + +```python +import activitysmith_openapi +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse +from activitysmith_openapi.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://activitysmith.com/api +# See configuration.py for a list of all supported configuration parameters. +configuration = activitysmith_openapi.Configuration( + host = "https://activitysmith.com/api" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure Bearer authorization (API Key): apiKeyAuth +configuration = activitysmith_openapi.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with activitysmith_openapi.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = activitysmith_openapi.DevicesApi(api_client) + limit = 100 # int | Maximum devices to return, 1 to 100. Defaults to 100. (optional) (default to 100) + offset = 0 # int | Devices to skip. Use meta.next_offset from the previous page. (optional) (default to 0) + include_inactive = False # bool | Include devices that can no longer receive deliveries, such as unpaired phones. (optional) (default to False) + + try: + # List paired devices + api_response = api_instance.list_account_devices(limit=limit, offset=offset, include_inactive=include_inactive) + print("The response of DevicesApi->list_account_devices:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling DevicesApi->list_account_devices: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **limit** | **int**| Maximum devices to return, 1 to 100. Defaults to 100. | [optional] [default to 100] + **offset** | **int**| Devices to skip. Use meta.next_offset from the previous page. | [optional] [default to 0] + **include_inactive** | **bool**| Include devices that can no longer receive deliveries, such as unpaired phones. | [optional] [default to False] + +### Return type + +[**AccountDeviceListResponse**](AccountDeviceListResponse.md) + +### Authorization + +[apiKeyAuth](../README.md#apiKeyAuth) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Paired devices | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**403** | The API key is limited to Channels | - | +**429** | Rate limit exceeded | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/activitysmith_openapi/docs/LiveActivitiesApi.md b/activitysmith_openapi/docs/LiveActivitiesApi.md index 6cc0b7f..32004df 100644 --- a/activitysmith_openapi/docs/LiveActivitiesApi.md +++ b/activitysmith_openapi/docs/LiveActivitiesApi.md @@ -16,7 +16,7 @@ Method | HTTP request | Description End a Live Activity (legacy manual lifecycle) -Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. +Legacy manual lifecycle endpoint. For new integrations, use DELETE /live-activity/stream/{stream_key} to end a managed Live Activity stream. This endpoint remains supported for existing integrations and advanced lifecycle control. Ends a Live Activity and archives its lifecycle. Supports segmented_progress, progress, metrics, stats, alert, timer, and value activity types. For segmented_progress activities, you can send the latest number_of_steps here if the workflow changed after start. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. Ending a Live Activity that already ended returns 200 with ignored: true and sends nothing to devices, so retries are safe. ### Example @@ -86,9 +86,9 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Live Activity ended | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**403** | Forbidden (activity not owned by this API key account) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**200** | Live Activity ended | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**403** | Forbidden (activity not owned by this API key account) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -169,10 +169,10 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Managed stream ended | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid stream_key or action) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**404** | Managed stream not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**200** | Managed stream ended | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid stream_key or action) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**404** | Managed stream not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -253,12 +253,12 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Stream reconciled | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid stream_key, payload, action, or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| +**200** | Stream reconciled | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid stream_key, payload, action, or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| **402** | Trial expired, trial allowance exhausted, or paid usage cap reached | - | -**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**422** | No paired devices on the account, or no devices matched the effective channel target | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**422** | No paired devices on the account, or no devices matched the effective channel target | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -337,12 +337,12 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Live Activity started | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid payload or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| +**200** | Live Activity started | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid payload or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| **402** | Billing access required | - | -**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**422** | No paired devices on the account, or no devices matched the effective channel target | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**422** | No paired devices on the account, or no devices matched the effective channel target | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -421,9 +421,9 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Live Activity updated (or queued) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**403** | Forbidden (activity not owned by this API key account) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**200** | Live Activity updated (or queued) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**403** | Forbidden (activity not owned by this API key account) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/activitysmith_openapi/docs/MetricsApi.md b/activitysmith_openapi/docs/MetricsApi.md index 930b6df..a76b437 100644 --- a/activitysmith_openapi/docs/MetricsApi.md +++ b/activitysmith_openapi/docs/MetricsApi.md @@ -85,11 +85,11 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Metric value updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid key or value) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**404** | Metric deleted or not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**409** | Metric limit reached | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**200** | Metric value updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid key or value) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**404** | Metric deleted or not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**409** | Metric limit reached | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -170,11 +170,11 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Metric updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**201** | Metric created | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid key or definition) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**409** | Metric limit reached | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**200** | Metric updated | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**201** | Metric created | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid key or definition) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**409** | Metric limit reached | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/activitysmith_openapi/docs/PushNotificationDismissResponse.md b/activitysmith_openapi/docs/PushNotificationDismissResponse.md new file mode 100644 index 0000000..6adfab5 --- /dev/null +++ b/activitysmith_openapi/docs/PushNotificationDismissResponse.md @@ -0,0 +1,32 @@ +# PushNotificationDismissResponse + +Dismissal result. Devices clear the notification after this response, so it does not confirm that any device has cleared it. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**success** | **bool** | True when the dismissal is recorded. | +**notification_id** | **str** | ID of the dismissed Push Notification. | +**dismissed_at** | **datetime** | When the notification was first dismissed. Repeat calls return the same time. | + +## Example + +```python +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse + +# TODO update the JSON string below +json = "{}" +# create an instance of PushNotificationDismissResponse from a JSON string +push_notification_dismiss_response_instance = PushNotificationDismissResponse.from_json(json) +# print the JSON string representation of the object +print(PushNotificationDismissResponse.to_json()) + +# convert the object into a dict +push_notification_dismiss_response_dict = push_notification_dismiss_response_instance.to_dict() +# create an instance of PushNotificationDismissResponse from a dict +push_notification_dismiss_response_from_dict = PushNotificationDismissResponse.from_dict(push_notification_dismiss_response_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/activitysmith_openapi/docs/PushNotificationsApi.md b/activitysmith_openapi/docs/PushNotificationsApi.md index b1452ec..5c481cf 100644 --- a/activitysmith_openapi/docs/PushNotificationsApi.md +++ b/activitysmith_openapi/docs/PushNotificationsApi.md @@ -4,10 +4,94 @@ All URIs are relative to *https://activitysmith.com/api* Method | HTTP request | Description ------------- | ------------- | ------------- +[**dismiss_push_notification**](PushNotificationsApi.md#dismiss_push_notification) | **POST** /push-notification/{notification_id}/dismiss | Dismiss a push notification [**replace_push_notification**](PushNotificationsApi.md#replace_push_notification) | **PUT** /push-notification/{notification_id} | Replace a push notification [**send_push_notification**](PushNotificationsApi.md#send_push_notification) | **POST** /push-notification | Send a push notification +# **dismiss_push_notification** +> PushNotificationDismissResponse dismiss_push_notification(notification_id) + +Dismiss a push notification + +Clears a Push Notification you already sent from the Lock Screen and Notification Center on every device it was sent to, using the `notification_id` from the send response. Notification history keeps it. Devices clear the notification in the background, which can take a moment or wait until the ActivitySmith app next opens. A successful response means the dismissal was recorded, not that every device has cleared it yet. Devices running an ActivitySmith app version before 1.17.0 show a silent notification titled \"Push Notification dismissed\" in its place until the user clears it. Calling this again for the same notification returns the same response and sends nothing. A dismissed notification cannot be replaced. + +### Example + +* Bearer (API Key) Authentication (apiKeyAuth): + +```python +import activitysmith_openapi +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse +from activitysmith_openapi.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://activitysmith.com/api +# See configuration.py for a list of all supported configuration parameters. +configuration = activitysmith_openapi.Configuration( + host = "https://activitysmith.com/api" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure Bearer authorization (API Key): apiKeyAuth +configuration = activitysmith_openapi.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with activitysmith_openapi.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = activitysmith_openapi.PushNotificationsApi(api_client) + notification_id = 'notification_id_example' # str | The `notification_id` returned when the Push Notification was sent. + + try: + # Dismiss a push notification + api_response = api_instance.dismiss_push_notification(notification_id) + print("The response of PushNotificationsApi->dismiss_push_notification:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling PushNotificationsApi->dismiss_push_notification: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **notification_id** | **str**| The `notification_id` returned when the Push Notification was sent. | + +### Return type + +[**PushNotificationDismissResponse**](PushNotificationDismissResponse.md) + +### Authorization + +[apiKeyAuth](../README.md#apiKeyAuth) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Push notification dismissal recorded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**402** | Billing access required | - | +**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**404** | Push notification not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**409** | Push notification was sent before dismissal support | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **replace_push_notification** > PushNotificationReplaceResponse replace_push_notification(notification_id, push_notification_replace_request) @@ -85,14 +169,14 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Push notification replaced | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid payload or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| +**200** | Push notification replaced | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid payload or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| **402** | Billing access required | - | -**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**404** | Push notification not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**409** | Push notification was sent before replacement support | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**422** | No recipients of the original Push Notification are still available | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**404** | Push notification not found | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**409** | Push notification cannot be replaced (sent before replacement support, or dismissed) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**422** | No recipients of the original Push Notification are still available | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -171,12 +255,12 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| -**200** | Push notification sent | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**400** | Bad request (invalid payload or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| +**200** | Push notification sent | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**400** | Bad request (invalid payload or channel targeting input) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| **402** | Billing access required | - | -**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**422** | No paired devices on the account, or no devices matched the effective channel target | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
| -**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Each feature has an independent IP limit of 600 requests per 60 seconds. Independent account limits per 60 seconds are: Push Notifications 60, badges 60, Live Activities 300, and metric updates 300.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| +**403** | Forbidden (API key scope or channel assignment violation) | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**422** | No paired devices on the account, or no devices matched the effective channel target | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
| +**429** | Rate limit exceeded | * RateLimit - Current request quotas using IETF draft-8 structured fields. Each named policy includes r (remaining requests) and t (seconds until reset). Multiple policies may apply.
* RateLimit-Policy - Each named policy includes q (request quota) and w (window in seconds). Listing devices has an IP limit of 600 requests and an account limit of 60 requests per 60 seconds.
* Retry-After - Seconds to wait before retrying after a request-rate 429. Live Activity capacity errors are separate and require freeing device capacity; they do not provide a timed retry guarantee.
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/activitysmith_openapi/models/__init__.py b/activitysmith_openapi/models/__init__.py index 7cbeb2a..8557384 100644 --- a/activitysmith_openapi/models/__init__.py +++ b/activitysmith_openapi/models/__init__.py @@ -14,6 +14,9 @@ # import models into model package +from activitysmith_openapi.models.account_device import AccountDevice +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse +from activitysmith_openapi.models.account_device_list_response_meta import AccountDeviceListResponseMeta from activitysmith_openapi.models.activity_metric import ActivityMetric from activitysmith_openapi.models.activity_metric_value import ActivityMetricValue from activitysmith_openapi.models.alert_payload import AlertPayload @@ -59,6 +62,7 @@ from activitysmith_openapi.models.push_interruption_level import PushInterruptionLevel from activitysmith_openapi.models.push_notification_action import PushNotificationAction from activitysmith_openapi.models.push_notification_action_type import PushNotificationActionType +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse from activitysmith_openapi.models.push_notification_replace_request import PushNotificationReplaceRequest from activitysmith_openapi.models.push_notification_replace_response import PushNotificationReplaceResponse from activitysmith_openapi.models.push_notification_request import PushNotificationRequest diff --git a/activitysmith_openapi/models/account_device.py b/activitysmith_openapi/models/account_device.py new file mode 100644 index 0000000..8fa971f --- /dev/null +++ b/activitysmith_openapi/models/account_device.py @@ -0,0 +1,143 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing import Optional, Set +from typing_extensions import Self + +class AccountDevice(BaseModel): + """ + An iPhone or iPad paired to the account, one entry per device and owner. + """ # noqa: E501 + user_email: StrictStr = Field(description="Email of the account member who paired the device.") + device_id: StrictStr = Field(description="Device ID. Use it to assign the device to Channels.") + device_type: Optional[StrictStr] = Field(description="Device platform, such as ios. iPhones and iPads both report ios; use system_name to tell them apart.") + is_active: StrictBool = Field(description="True when the device can receive Push Notifications or Live Activities.") + token_status: Dict[str, StrictBool] = Field(description="Whether each delivery token is active, keyed by token type (push, start_live_activity).") + app_version: Optional[StrictStr] = Field(description="ActivitySmith app version on the device.") + device_name: Optional[StrictStr] = Field(description="Device name set on the device.") + system_name: Optional[StrictStr] = Field(description="Operating system name, such as iOS or iPadOS.") + system_version: Optional[StrictStr] = Field(description="Operating system version.") + created_at: Optional[datetime] = Field(description="When the device was first paired.") + updated_at: Optional[datetime] = Field(description="When the device last updated its pairing.") + __properties: ClassVar[List[str]] = ["user_email", "device_id", "device_type", "is_active", "token_status", "app_version", "device_name", "system_name", "system_version", "created_at", "updated_at"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AccountDevice from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if device_type (nullable) is None + # and model_fields_set contains the field + if self.device_type is None and "device_type" in self.model_fields_set: + _dict['device_type'] = None + + # set to None if app_version (nullable) is None + # and model_fields_set contains the field + if self.app_version is None and "app_version" in self.model_fields_set: + _dict['app_version'] = None + + # set to None if device_name (nullable) is None + # and model_fields_set contains the field + if self.device_name is None and "device_name" in self.model_fields_set: + _dict['device_name'] = None + + # set to None if system_name (nullable) is None + # and model_fields_set contains the field + if self.system_name is None and "system_name" in self.model_fields_set: + _dict['system_name'] = None + + # set to None if system_version (nullable) is None + # and model_fields_set contains the field + if self.system_version is None and "system_version" in self.model_fields_set: + _dict['system_version'] = None + + # set to None if created_at (nullable) is None + # and model_fields_set contains the field + if self.created_at is None and "created_at" in self.model_fields_set: + _dict['created_at'] = None + + # set to None if updated_at (nullable) is None + # and model_fields_set contains the field + if self.updated_at is None and "updated_at" in self.model_fields_set: + _dict['updated_at'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AccountDevice from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "user_email": obj.get("user_email"), + "device_id": obj.get("device_id"), + "device_type": obj.get("device_type"), + "is_active": obj.get("is_active"), + "token_status": obj.get("token_status"), + "app_version": obj.get("app_version"), + "device_name": obj.get("device_name"), + "system_name": obj.get("system_name"), + "system_version": obj.get("system_version"), + "created_at": obj.get("created_at"), + "updated_at": obj.get("updated_at") + }) + return _obj + + diff --git a/activitysmith_openapi/models/account_device_list_response.py b/activitysmith_openapi/models/account_device_list_response.py new file mode 100644 index 0000000..0974244 --- /dev/null +++ b/activitysmith_openapi/models/account_device_list_response.py @@ -0,0 +1,101 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict +from typing import Any, ClassVar, Dict, List +from activitysmith_openapi.models.account_device import AccountDevice +from activitysmith_openapi.models.account_device_list_response_meta import AccountDeviceListResponseMeta +from typing import Optional, Set +from typing_extensions import Self + +class AccountDeviceListResponse(BaseModel): + """ + AccountDeviceListResponse + """ # noqa: E501 + devices: List[AccountDevice] + meta: AccountDeviceListResponseMeta + __properties: ClassVar[List[str]] = ["devices", "meta"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AccountDeviceListResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in devices (list) + _items = [] + if self.devices: + for _item in self.devices: + if _item: + _items.append(_item.to_dict()) + _dict['devices'] = _items + # override the default output from pydantic by calling `to_dict()` of meta + if self.meta: + _dict['meta'] = self.meta.to_dict() + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AccountDeviceListResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "devices": [AccountDevice.from_dict(_item) for _item in obj["devices"]] if obj.get("devices") is not None else None, + "meta": AccountDeviceListResponseMeta.from_dict(obj["meta"]) if obj.get("meta") is not None else None + }) + return _obj + + diff --git a/activitysmith_openapi/models/account_device_list_response_meta.py b/activitysmith_openapi/models/account_device_list_response_meta.py new file mode 100644 index 0000000..43525ee --- /dev/null +++ b/activitysmith_openapi/models/account_device_list_response_meta.py @@ -0,0 +1,102 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt +from typing import Any, ClassVar, Dict, List, Optional +from typing import Optional, Set +from typing_extensions import Self + +class AccountDeviceListResponseMeta(BaseModel): + """ + AccountDeviceListResponseMeta + """ # noqa: E501 + total: StrictInt = Field(description="Devices matching the filter.") + limit: StrictInt + offset: StrictInt + has_more: StrictBool + next_offset: Optional[StrictInt] = Field(description="Offset for the next page, or null on the last page.") + include_inactive: StrictBool + __properties: ClassVar[List[str]] = ["total", "limit", "offset", "has_more", "next_offset", "include_inactive"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AccountDeviceListResponseMeta from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if next_offset (nullable) is None + # and model_fields_set contains the field + if self.next_offset is None and "next_offset" in self.model_fields_set: + _dict['next_offset'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AccountDeviceListResponseMeta from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "total": obj.get("total"), + "limit": obj.get("limit"), + "offset": obj.get("offset"), + "has_more": obj.get("has_more"), + "next_offset": obj.get("next_offset"), + "include_inactive": obj.get("include_inactive") + }) + return _obj + + diff --git a/activitysmith_openapi/models/push_notification_dismiss_response.py b/activitysmith_openapi/models/push_notification_dismiss_response.py new file mode 100644 index 0000000..7576350 --- /dev/null +++ b/activitysmith_openapi/models/push_notification_dismiss_response.py @@ -0,0 +1,92 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class PushNotificationDismissResponse(BaseModel): + """ + Dismissal result. Devices clear the notification after this response, so it does not confirm that any device has cleared it. + """ # noqa: E501 + success: StrictBool = Field(description="True when the dismissal is recorded.") + notification_id: StrictStr = Field(description="ID of the dismissed Push Notification.") + dismissed_at: datetime = Field(description="When the notification was first dismissed. Repeat calls return the same time.") + __properties: ClassVar[List[str]] = ["success", "notification_id", "dismissed_at"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of PushNotificationDismissResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of PushNotificationDismissResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "success": obj.get("success"), + "notification_id": obj.get("notification_id"), + "dismissed_at": obj.get("dismissed_at") + }) + return _obj + + diff --git a/activitysmith_openapi/openapi-source.json b/activitysmith_openapi/openapi-source.json index 498433c..6f55ecd 100644 --- a/activitysmith_openapi/openapi-source.json +++ b/activitysmith_openapi/openapi-source.json @@ -1,6 +1,6 @@ { "repository": "ActivitySmithHQ/activitysmith-backend", - "commit": "7bf9c3d88459fe3f122810979a45da0a1e6fd2d6", + "commit": "278d980633d4b1fc735ca96948fdd8ff8fd27642", "path": "openapi.json", - "sha256": "6987f90b106e28a0ab8058f43309e7a9f045c7c54d27ce90bbdd5966c3f99f7a" + "sha256": "0dbbba13bf497eceea4de0759943481a6e085cdf9a9a5445a60cf2b27457de40" } diff --git a/activitysmith_openapi/test/test_account_device.py b/activitysmith_openapi/test/test_account_device.py new file mode 100644 index 0000000..ffa892d --- /dev/null +++ b/activitysmith_openapi/test/test_account_device.py @@ -0,0 +1,76 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from activitysmith_openapi.models.account_device import AccountDevice + +class TestAccountDevice(unittest.TestCase): + """AccountDevice unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> AccountDevice: + """Test AccountDevice + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `AccountDevice` + """ + model = AccountDevice() + if include_optional: + return AccountDevice( + user_email = '', + device_id = '', + device_type = '', + is_active = True, + token_status = { + 'key' : True + }, + app_version = '', + device_name = '', + system_name = '', + system_version = '', + created_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + updated_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f') + ) + else: + return AccountDevice( + user_email = '', + device_id = '', + device_type = '', + is_active = True, + token_status = { + 'key' : True + }, + app_version = '', + device_name = '', + system_name = '', + system_version = '', + created_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + updated_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + ) + """ + + def testAccountDevice(self): + """Test AccountDevice""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/activitysmith_openapi/test/test_account_device_list_response.py b/activitysmith_openapi/test/test_account_device_list_response.py new file mode 100644 index 0000000..dcc70ac --- /dev/null +++ b/activitysmith_openapi/test/test_account_device_list_response.py @@ -0,0 +1,96 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse + +class TestAccountDeviceListResponse(unittest.TestCase): + """AccountDeviceListResponse unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> AccountDeviceListResponse: + """Test AccountDeviceListResponse + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `AccountDeviceListResponse` + """ + model = AccountDeviceListResponse() + if include_optional: + return AccountDeviceListResponse( + devices = [ + activitysmith_openapi.models.account_device.AccountDevice( + user_email = '', + device_id = '', + device_type = '', + is_active = True, + token_status = { + 'key' : True + }, + app_version = '', + device_name = '', + system_name = '', + system_version = '', + created_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + updated_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), ) + ], + meta = activitysmith_openapi.models.account_device_list_response_meta.AccountDeviceListResponse_meta( + total = 56, + limit = 56, + offset = 56, + has_more = True, + next_offset = 56, + include_inactive = True, ) + ) + else: + return AccountDeviceListResponse( + devices = [ + activitysmith_openapi.models.account_device.AccountDevice( + user_email = '', + device_id = '', + device_type = '', + is_active = True, + token_status = { + 'key' : True + }, + app_version = '', + device_name = '', + system_name = '', + system_version = '', + created_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + updated_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), ) + ], + meta = activitysmith_openapi.models.account_device_list_response_meta.AccountDeviceListResponse_meta( + total = 56, + limit = 56, + offset = 56, + has_more = True, + next_offset = 56, + include_inactive = True, ), + ) + """ + + def testAccountDeviceListResponse(self): + """Test AccountDeviceListResponse""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/activitysmith_openapi/test/test_account_device_list_response_meta.py b/activitysmith_openapi/test/test_account_device_list_response_meta.py new file mode 100644 index 0000000..db3858e --- /dev/null +++ b/activitysmith_openapi/test/test_account_device_list_response_meta.py @@ -0,0 +1,62 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from activitysmith_openapi.models.account_device_list_response_meta import AccountDeviceListResponseMeta + +class TestAccountDeviceListResponseMeta(unittest.TestCase): + """AccountDeviceListResponseMeta unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> AccountDeviceListResponseMeta: + """Test AccountDeviceListResponseMeta + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `AccountDeviceListResponseMeta` + """ + model = AccountDeviceListResponseMeta() + if include_optional: + return AccountDeviceListResponseMeta( + total = 56, + limit = 56, + offset = 56, + has_more = True, + next_offset = 56, + include_inactive = True + ) + else: + return AccountDeviceListResponseMeta( + total = 56, + limit = 56, + offset = 56, + has_more = True, + next_offset = 56, + include_inactive = True, + ) + """ + + def testAccountDeviceListResponseMeta(self): + """Test AccountDeviceListResponseMeta""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/activitysmith_openapi/test/test_devices_api.py b/activitysmith_openapi/test/test_devices_api.py new file mode 100644 index 0000000..d6b0025 --- /dev/null +++ b/activitysmith_openapi/test/test_devices_api.py @@ -0,0 +1,38 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from activitysmith_openapi.api.devices_api import DevicesApi + + +class TestDevicesApi(unittest.TestCase): + """DevicesApi unit test stubs""" + + def setUp(self) -> None: + self.api = DevicesApi() + + def tearDown(self) -> None: + pass + + def test_list_account_devices(self) -> None: + """Test case for list_account_devices + + List paired devices + """ + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/activitysmith_openapi/test/test_push_notification_dismiss_response.py b/activitysmith_openapi/test/test_push_notification_dismiss_response.py new file mode 100644 index 0000000..e7a4340 --- /dev/null +++ b/activitysmith_openapi/test/test_push_notification_dismiss_response.py @@ -0,0 +1,56 @@ +# coding: utf-8 + +""" + ActivitySmith API + + Send push notifications and Live Activities to your own devices via a single API key. + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse + +class TestPushNotificationDismissResponse(unittest.TestCase): + """PushNotificationDismissResponse unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> PushNotificationDismissResponse: + """Test PushNotificationDismissResponse + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `PushNotificationDismissResponse` + """ + model = PushNotificationDismissResponse() + if include_optional: + return PushNotificationDismissResponse( + success = True, + notification_id = '', + dismissed_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f') + ) + else: + return PushNotificationDismissResponse( + success = True, + notification_id = '', + dismissed_at = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + ) + """ + + def testPushNotificationDismissResponse(self): + """Test PushNotificationDismissResponse""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/activitysmith_openapi/test/test_push_notifications_api.py b/activitysmith_openapi/test/test_push_notifications_api.py index dea2be8..8df1841 100644 --- a/activitysmith_openapi/test/test_push_notifications_api.py +++ b/activitysmith_openapi/test/test_push_notifications_api.py @@ -26,6 +26,13 @@ def setUp(self) -> None: def tearDown(self) -> None: pass + def test_dismiss_push_notification(self) -> None: + """Test case for dismiss_push_notification + + Dismiss a push notification + """ + pass + def test_replace_push_notification(self) -> None: """Test case for replace_push_notification diff --git a/pyproject.toml b/pyproject.toml index 4061457..a5799fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "activitysmith" -version = "1.14.0" +version = "1.15.0" description = "Official ActivitySmith Python SDK" readme = "README.md" requires-python = ">=3.9" diff --git a/tests/test_resources.py b/tests/test_resources.py index 98a9a30..e35823c 100644 --- a/tests/test_resources.py +++ b/tests/test_resources.py @@ -18,6 +18,20 @@ def replace_push_notification(self, **kwargs): self.calls.append(kwargs) return kwargs + def dismiss_push_notification(self, **kwargs): + self.calls.append(kwargs) + return kwargs + + +class FakeDevicesApi: + def __init__(self, _api_client): + self._api_client = _api_client + self.calls = [] + + def list_account_devices(self, **kwargs): + self.calls.append(kwargs) + return kwargs + class FakeLiveActivitiesApi: def __init__(self, _api_client): @@ -860,6 +874,37 @@ def test_notifications_replace_and_alias(monkeypatch): } +def test_notifications_dismiss_and_alias(monkeypatch): + monkeypatch.setattr(client_module, "PushNotificationsApi", FakePushNotificationsApi) + + client = ActivitySmith(api_key="x") + + short = client.notifications.dismiss("pn1") + legacy = client.notifications.dismiss_push_notification("pn1") + + assert short == {"notification_id": "pn1"} + assert legacy == {"notification_id": "pn1"} + assert client.notifications._api.calls == [{"notification_id": "pn1"}, {"notification_id": "pn1"}] + + +def test_devices_list_and_alias(monkeypatch): + monkeypatch.setattr(client_module, "DevicesApi", FakeDevicesApi) + + client = ActivitySmith(api_key="x") + + client.devices.list() + client.devices.list(include_inactive=True, limit=10) + client.devices.list(10, 20, True) + client.devices.list_account_devices(offset=5) + + assert client.devices._api.calls == [ + {"limit": None, "offset": None, "include_inactive": None}, + {"limit": 10, "offset": None, "include_inactive": True}, + {"limit": 10, "offset": 20, "include_inactive": True}, + {"limit": None, "offset": 5, "include_inactive": None}, + ] + + def test_notifications_replace_rejects_media_and_actions(monkeypatch): monkeypatch.setattr(client_module, "PushNotificationsApi", FakePushNotificationsApi) client = ActivitySmith(api_key="x") diff --git a/tests/test_value_serialization.py b/tests/test_value_serialization.py index cb01daa..fc108fa 100644 --- a/tests/test_value_serialization.py +++ b/tests/test_value_serialization.py @@ -1,10 +1,15 @@ +import json from copy import deepcopy +from urllib.parse import parse_qs, urlsplit import pytest from activitysmith import ActivitySmith from activitysmith.client import content_state, metric from activitysmith_openapi.api_client import ApiClient +from activitysmith_openapi.models.account_device_list_response import AccountDeviceListResponse +from activitysmith_openapi.models.push_notification_dismiss_response import PushNotificationDismissResponse +from activitysmith_openapi.rest import RESTClientObject, RESTResponse from activitysmith_openapi.models.activity_metric_value import ActivityMetricValue from activitysmith_openapi.models.metric_value_update_request_value import MetricValueUpdateRequestValue from activitysmith_openapi.models.metric_value_update_request import MetricValueUpdateRequest @@ -263,3 +268,185 @@ def capture(self, method, url, header_params=None, body=None, post_params=None, assert captured[0][2] == {"label": "MRR", "format": "currency", "currency_code": "USD"} assert captured[1][2] == {"format": "unit", "unit": "ms", "unit_spacing": "space"} assert captured[2][2] is None + + +class FakeHTTPResponse: + def __init__(self, status, body): + self.status = status + self.reason = "OK" + self.data = json.dumps(body).encode("utf-8") + self.headers = {"content-type": "application/json; charset=utf-8"} + + +DEVICE = { + "user_email": "owner@example.com", + "device_id": "dev_1", + "device_type": "ios", + "is_active": True, + "token_status": {"push": True, "start_live_activity": True}, + "app_version": "1.17.0", + "device_name": "Work iPhone", + "system_name": "iOS", + "system_version": "27.0", + "created_at": "2026-10-01T09:00:00Z", + "updated_at": "2026-11-07T09:00:00Z", +} +INACTIVE_DEVICE = dict( + DEVICE, + device_id="dev_2", + is_active=False, + token_status={"push": False, "start_live_activity": False}, + device_name="Old iPad", + system_name="iPadOS", +) + + +def _fake_api_response(method, path, query): + if method == "POST" and path == "/push-notification": + return { + "success": True, + "notification_id": "Xk3pQ8mV2nR7tL9wB4yZ", + "devices_notified": 1, + "timestamp": "2026-11-07T09:00:00Z", + } + if method == "POST" and path.startswith("/push-notification/") and path.endswith("/dismiss"): + return { + "success": True, + "notification_id": path.split("/")[2], + "dismissed_at": "2026-11-07T09:01:00Z", + } + if method == "GET" and path == "/account/devices": + include_inactive = query.get("include_inactive") == ["true"] + devices = [DEVICE, INACTIVE_DEVICE] if include_inactive else [DEVICE] + return { + "devices": devices, + "meta": { + "total": len(devices), + "limit": int(query.get("limit", ["100"])[0]), + "offset": 0, + "has_more": False, + "next_offset": None, + "include_inactive": include_inactive, + }, + } + if method == "PUT" and path.startswith("/metrics/"): + return { + "metric": { + "public_id": "met_1", + "key": path.split("/")[2], + "label": "MRR", + "format": "currency", + "currency_code": "USD", + "unit": None, + "unit_spacing": "none", + "latest_value": None, + "latest_value_at": None, + "created_at": "2026-11-07T09:00:00Z", + "updated_at": "2026-11-07T09:00:00Z", + } + } + if method == "POST" and path.startswith("/metrics/") and path.endswith("/value"): + return {"success": True} + raise AssertionError(f"unexpected request {method} {path}") + + +@pytest.fixture +def transport(monkeypatch): + """Mock the HTTP layer below the generated client, so nothing reaches the network.""" + sent = [] + + def request(self, method, url, headers=None, body=None, post_params=None, _request_timeout=None): + parsed = urlsplit(url) + path = parsed.path.split("/api", 1)[1] + query = parse_qs(parsed.query) + sent.append({"method": method, "path": path, "query": query, "raw_query": parsed.query, "body": body}) + return RESTResponse(FakeHTTPResponse(200, _fake_api_response(method, path, query))) + + monkeypatch.setattr(RESTClientObject, "request", request) + return sent + + +def test_push_dismiss_sends_post_and_returns_parsed_body(transport): + activitysmith = ActivitySmith(api_key="test") + + result = activitysmith.notifications.dismiss("Xk3pQ8mV2nR7tL9wB4yZ") + alias = activitysmith.notifications.dismiss_push_notification("Xk3pQ8mV2nR7tL9wB4yZ") + + assert [(r["method"], r["path"], r["body"]) for r in transport] == [ + ("POST", "/push-notification/Xk3pQ8mV2nR7tL9wB4yZ/dismiss", None), + ("POST", "/push-notification/Xk3pQ8mV2nR7tL9wB4yZ/dismiss", None), + ] + assert isinstance(result, PushNotificationDismissResponse) + assert result.success is True + assert result.notification_id == "Xk3pQ8mV2nR7tL9wB4yZ" + assert result.dismissed_at.isoformat() == "2026-11-07T09:01:00+00:00" + assert alias == result + + +def test_push_dismiss_rejects_empty_notification_id(transport): + activitysmith = ActivitySmith(api_key="test") + with pytest.raises(ValueError): + activitysmith.notifications.dismiss("") + assert transport == [] + + +def test_devices_list_sends_get_without_query(transport): + activitysmith = ActivitySmith(api_key="test") + + result = activitysmith.devices.list() + + assert [(r["method"], r["path"], r["raw_query"], r["body"]) for r in transport] == [ + ("GET", "/account/devices", "", None), + ] + assert isinstance(result, AccountDeviceListResponse) + assert [device.device_id for device in result.devices] == ["dev_1"] + assert result.devices[0].token_status == {"push": True, "start_live_activity": True} + assert result.meta.next_offset is None + + +def test_devices_list_sends_query_params(transport): + activitysmith = ActivitySmith(api_key="test") + + result = activitysmith.devices.list(include_inactive=True, limit=10) + activitysmith.devices.list_account_devices(limit=5, offset=10, include_inactive=False) + + assert transport[0]["method"] == "GET" + assert transport[0]["path"] == "/account/devices" + assert transport[0]["query"] == {"limit": ["10"], "include_inactive": ["true"]} + assert transport[1]["query"] == {"limit": ["5"], "offset": ["10"], "include_inactive": ["false"]} + assert [device.is_active for device in result.devices] == [True, False] + assert result.meta.include_inactive is True + + +@pytest.mark.parametrize("fields", [{"limit": 0}, {"limit": 101}, {"offset": -1}, {"include_inactive": "yes"}]) +def test_devices_list_rejects_invalid_query_before_transport(transport, fields): + activitysmith = ActivitySmith(api_key="test") + with pytest.raises(ValueError): + activitysmith.devices.list(**fields) + assert transport == [] + + +def test_release_doc_examples_run_as_written(transport, capsys): + activitysmith = ActivitySmith(api_key="test") + + sent = activitysmith.notifications.send(title="🙋 Agent needs your input", message="Approve the database migration?") + activitysmith.notifications.dismiss(sent.notification_id) + result = activitysmith.devices.list() + for device in result.devices: + print(device.device_name, device.system_name, device.is_active) + activitysmith.devices.list(include_inactive=True) + activitysmith.metrics.create("mrr", label="MRR", format="currency", currency_code="USD") + activitysmith.metrics.update("mrr", 12450) + + assert [(r["method"], r["path"], r["raw_query"]) for r in transport] == [ + ("POST", "/push-notification", ""), + ("POST", "/push-notification/Xk3pQ8mV2nR7tL9wB4yZ/dismiss", ""), + ("GET", "/account/devices", ""), + ("GET", "/account/devices", "include_inactive=true"), + ("PUT", "/metrics/mrr", ""), + ("POST", "/metrics/mrr/value", ""), + ] + assert transport[0]["body"] == {"title": "🙋 Agent needs your input", "message": "Approve the database migration?"} + assert transport[4]["body"] == {"label": "MRR", "format": "currency", "currency_code": "USD"} + assert transport[5]["body"] == {"value": 12450} + assert capsys.readouterr().out == "Work iPhone iOS True\n"