diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a713055..d52d2b9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.12.0" + ".": "0.13.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 2a2bfcd..76f728e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 37 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zavu%2Fzavudev-064fa598a02a9f8529186ca4292253201abbc550c98ed1d2c44dd637e4977cba.yml -openapi_spec_hash: 76468e579e64c10eda3ce647c38482a6 -config_hash: 2c81a5597d0125c8a91faaddaadb8b9e +configured_endpoints: 40 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zavu%2Fzavudev-632d79d39ef49ea571930f3e1c71d63145b23905126df2957d4eb61a309e9054.yml +openapi_spec_hash: 74d14877ffe27741c222a83646071717 +config_hash: ab9d47848e436f9b6b787afd062ff9a7 diff --git a/CHANGELOG.md b/CHANGELOG.md index ba04902..8a230e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.13.0 (2025-12-17) + +Full Changelog: [v0.12.0...v0.13.0](https://github.com/zavudev/sdk-python/compare/v0.12.0...v0.13.0) + +### Features + +* **api:** api update ([1f7ee8c](https://github.com/zavudev/sdk-python/commit/1f7ee8ce8cf2a6a3cb662bdddba1279ca916d1d1)) +* **api:** whatsapp profile ([beb8348](https://github.com/zavudev/sdk-python/commit/beb834894c1b86c9bfe69783ad4ebb0648e3b7d6)) + ## 0.12.0 (2025-12-16) Full Changelog: [v0.11.0...v0.12.0](https://github.com/zavudev/sdk-python/compare/v0.11.0...v0.12.0) diff --git a/api.md b/api.md index 632c0c8..6052289 100644 --- a/api.md +++ b/api.md @@ -41,7 +41,17 @@ Methods: Types: ```python -from zavudev.types import Sender, SenderWebhook, WebhookEvent, WebhookSecretResponse +from zavudev.types import ( + Sender, + SenderWebhook, + WebhookEvent, + WebhookSecretResponse, + WhatsappBusinessProfile, + WhatsappBusinessProfileResponse, + WhatsappBusinessProfileVertical, + SenderUpdateProfileResponse, + SenderUploadProfilePictureResponse, +) ``` Methods: @@ -51,7 +61,10 @@ Methods: - client.senders.update(sender_id, \*\*params) -> Sender - client.senders.list(\*\*params) -> SyncCursor[Sender] - client.senders.delete(sender_id) -> None +- client.senders.get_profile(sender_id) -> WhatsappBusinessProfileResponse - client.senders.regenerate_webhook_secret(sender_id) -> WebhookSecretResponse +- client.senders.update_profile(sender_id, \*\*params) -> SenderUpdateProfileResponse +- client.senders.upload_profile_picture(sender_id, \*\*params) -> SenderUploadProfilePictureResponse # Contacts diff --git a/pyproject.toml b/pyproject.toml index 2524838..73a7d11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "zavudev" -version = "0.12.0" +version = "0.13.0" description = "The official Python library for the zavudev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/zavudev/_version.py b/src/zavudev/_version.py index 06e8856..646a67a 100644 --- a/src/zavudev/_version.py +++ b/src/zavudev/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "zavudev" -__version__ = "0.12.0" # x-release-please-version +__version__ = "0.13.0" # x-release-please-version diff --git a/src/zavudev/resources/senders.py b/src/zavudev/resources/senders.py index 10d881a..227c0ab 100644 --- a/src/zavudev/resources/senders.py +++ b/src/zavudev/resources/senders.py @@ -3,11 +3,19 @@ from __future__ import annotations from typing import List, Optional +from typing_extensions import Literal import httpx -from ..types import sender_list_params, sender_create_params, sender_update_params -from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..types import ( + WhatsappBusinessProfileVertical, + sender_list_params, + sender_create_params, + sender_update_params, + sender_update_profile_params, + sender_upload_profile_picture_params, +) +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -22,6 +30,10 @@ from ..types.sender import Sender from ..types.webhook_event import WebhookEvent from ..types.webhook_secret_response import WebhookSecretResponse +from ..types.sender_update_profile_response import SenderUpdateProfileResponse +from ..types.whatsapp_business_profile_response import WhatsappBusinessProfileResponse +from ..types.whatsapp_business_profile_vertical import WhatsappBusinessProfileVertical +from ..types.sender_upload_profile_picture_response import SenderUploadProfilePictureResponse __all__ = ["SendersResource", "AsyncSendersResource"] @@ -259,6 +271,41 @@ def delete( cast_to=NoneType, ) + def get_profile( + self, + sender_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WhatsappBusinessProfileResponse: + """Get the WhatsApp Business profile for a sender. + + The sender must have a WhatsApp + Business Account connected. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not sender_id: + raise ValueError(f"Expected a non-empty value for `sender_id` but received {sender_id!r}") + return self._get( + f"/v1/senders/{sender_id}/profile", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WhatsappBusinessProfileResponse, + ) + def regenerate_webhook_secret( self, sender_id: str, @@ -294,6 +341,118 @@ def regenerate_webhook_secret( cast_to=WebhookSecretResponse, ) + def update_profile( + self, + sender_id: str, + *, + about: str | Omit = omit, + address: str | Omit = omit, + description: str | Omit = omit, + email: str | Omit = omit, + vertical: WhatsappBusinessProfileVertical | Omit = omit, + websites: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SenderUpdateProfileResponse: + """Update the WhatsApp Business profile for a sender. + + The sender must have a + WhatsApp Business Account connected. + + Args: + about: Short description of the business (max 139 characters). + + address: Physical address of the business (max 256 characters). + + description: Extended description of the business (max 512 characters). + + email: Business email address. + + vertical: Business category for WhatsApp Business profile. + + websites: Business website URLs (maximum 2). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not sender_id: + raise ValueError(f"Expected a non-empty value for `sender_id` but received {sender_id!r}") + return self._patch( + f"/v1/senders/{sender_id}/profile", + body=maybe_transform( + { + "about": about, + "address": address, + "description": description, + "email": email, + "vertical": vertical, + "websites": websites, + }, + sender_update_profile_params.SenderUpdateProfileParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SenderUpdateProfileResponse, + ) + + def upload_profile_picture( + self, + sender_id: str, + *, + image_url: str, + mime_type: Literal["image/jpeg", "image/png"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SenderUploadProfilePictureResponse: + """Upload a new profile picture for the WhatsApp Business profile. + + The image will + be uploaded to Meta and set as the profile picture. + + Args: + image_url: URL of the image to upload. + + mime_type: MIME type of the image. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not sender_id: + raise ValueError(f"Expected a non-empty value for `sender_id` but received {sender_id!r}") + return self._post( + f"/v1/senders/{sender_id}/profile/picture", + body=maybe_transform( + { + "image_url": image_url, + "mime_type": mime_type, + }, + sender_upload_profile_picture_params.SenderUploadProfilePictureParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SenderUploadProfilePictureResponse, + ) + class AsyncSendersResource(AsyncAPIResource): @cached_property @@ -528,6 +687,41 @@ async def delete( cast_to=NoneType, ) + async def get_profile( + self, + sender_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WhatsappBusinessProfileResponse: + """Get the WhatsApp Business profile for a sender. + + The sender must have a WhatsApp + Business Account connected. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not sender_id: + raise ValueError(f"Expected a non-empty value for `sender_id` but received {sender_id!r}") + return await self._get( + f"/v1/senders/{sender_id}/profile", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WhatsappBusinessProfileResponse, + ) + async def regenerate_webhook_secret( self, sender_id: str, @@ -563,6 +757,118 @@ async def regenerate_webhook_secret( cast_to=WebhookSecretResponse, ) + async def update_profile( + self, + sender_id: str, + *, + about: str | Omit = omit, + address: str | Omit = omit, + description: str | Omit = omit, + email: str | Omit = omit, + vertical: WhatsappBusinessProfileVertical | Omit = omit, + websites: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SenderUpdateProfileResponse: + """Update the WhatsApp Business profile for a sender. + + The sender must have a + WhatsApp Business Account connected. + + Args: + about: Short description of the business (max 139 characters). + + address: Physical address of the business (max 256 characters). + + description: Extended description of the business (max 512 characters). + + email: Business email address. + + vertical: Business category for WhatsApp Business profile. + + websites: Business website URLs (maximum 2). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not sender_id: + raise ValueError(f"Expected a non-empty value for `sender_id` but received {sender_id!r}") + return await self._patch( + f"/v1/senders/{sender_id}/profile", + body=await async_maybe_transform( + { + "about": about, + "address": address, + "description": description, + "email": email, + "vertical": vertical, + "websites": websites, + }, + sender_update_profile_params.SenderUpdateProfileParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SenderUpdateProfileResponse, + ) + + async def upload_profile_picture( + self, + sender_id: str, + *, + image_url: str, + mime_type: Literal["image/jpeg", "image/png"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SenderUploadProfilePictureResponse: + """Upload a new profile picture for the WhatsApp Business profile. + + The image will + be uploaded to Meta and set as the profile picture. + + Args: + image_url: URL of the image to upload. + + mime_type: MIME type of the image. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not sender_id: + raise ValueError(f"Expected a non-empty value for `sender_id` but received {sender_id!r}") + return await self._post( + f"/v1/senders/{sender_id}/profile/picture", + body=await async_maybe_transform( + { + "image_url": image_url, + "mime_type": mime_type, + }, + sender_upload_profile_picture_params.SenderUploadProfilePictureParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SenderUploadProfilePictureResponse, + ) + class SendersResourceWithRawResponse: def __init__(self, senders: SendersResource) -> None: @@ -583,9 +889,18 @@ def __init__(self, senders: SendersResource) -> None: self.delete = to_raw_response_wrapper( senders.delete, ) + self.get_profile = to_raw_response_wrapper( + senders.get_profile, + ) self.regenerate_webhook_secret = to_raw_response_wrapper( senders.regenerate_webhook_secret, ) + self.update_profile = to_raw_response_wrapper( + senders.update_profile, + ) + self.upload_profile_picture = to_raw_response_wrapper( + senders.upload_profile_picture, + ) class AsyncSendersResourceWithRawResponse: @@ -607,9 +922,18 @@ def __init__(self, senders: AsyncSendersResource) -> None: self.delete = async_to_raw_response_wrapper( senders.delete, ) + self.get_profile = async_to_raw_response_wrapper( + senders.get_profile, + ) self.regenerate_webhook_secret = async_to_raw_response_wrapper( senders.regenerate_webhook_secret, ) + self.update_profile = async_to_raw_response_wrapper( + senders.update_profile, + ) + self.upload_profile_picture = async_to_raw_response_wrapper( + senders.upload_profile_picture, + ) class SendersResourceWithStreamingResponse: @@ -631,9 +955,18 @@ def __init__(self, senders: SendersResource) -> None: self.delete = to_streamed_response_wrapper( senders.delete, ) + self.get_profile = to_streamed_response_wrapper( + senders.get_profile, + ) self.regenerate_webhook_secret = to_streamed_response_wrapper( senders.regenerate_webhook_secret, ) + self.update_profile = to_streamed_response_wrapper( + senders.update_profile, + ) + self.upload_profile_picture = to_streamed_response_wrapper( + senders.upload_profile_picture, + ) class AsyncSendersResourceWithStreamingResponse: @@ -655,6 +988,15 @@ def __init__(self, senders: AsyncSendersResource) -> None: self.delete = async_to_streamed_response_wrapper( senders.delete, ) + self.get_profile = async_to_streamed_response_wrapper( + senders.get_profile, + ) self.regenerate_webhook_secret = async_to_streamed_response_wrapper( senders.regenerate_webhook_secret, ) + self.update_profile = async_to_streamed_response_wrapper( + senders.update_profile, + ) + self.upload_profile_picture = async_to_streamed_response_wrapper( + senders.upload_profile_picture, + ) diff --git a/src/zavudev/types/__init__.py b/src/zavudev/types/__init__.py index 619a18a..7585c0e 100644 --- a/src/zavudev/types/__init__.py +++ b/src/zavudev/types/__init__.py @@ -52,16 +52,25 @@ from .broadcast_create_response import BroadcastCreateResponse as BroadcastCreateResponse from .broadcast_update_response import BroadcastUpdateResponse as BroadcastUpdateResponse from .phone_number_capabilities import PhoneNumberCapabilities as PhoneNumberCapabilities +from .whatsapp_business_profile import WhatsappBusinessProfile as WhatsappBusinessProfile from .owned_phone_number_pricing import OwnedPhoneNumberPricing as OwnedPhoneNumberPricing from .phone_number_update_params import PhoneNumberUpdateParams as PhoneNumberUpdateParams from .broadcast_retrieve_response import BroadcastRetrieveResponse as BroadcastRetrieveResponse from .phone_number_purchase_params import PhoneNumberPurchaseParams as PhoneNumberPurchaseParams from .phone_number_update_response import PhoneNumberUpdateResponse as PhoneNumberUpdateResponse +from .sender_update_profile_params import SenderUpdateProfileParams as SenderUpdateProfileParams from .phone_number_purchase_response import PhoneNumberPurchaseResponse as PhoneNumberPurchaseResponse from .phone_number_retrieve_response import PhoneNumberRetrieveResponse as PhoneNumberRetrieveResponse +from .sender_update_profile_response import SenderUpdateProfileResponse as SenderUpdateProfileResponse from .introspect_validate_phone_params import IntrospectValidatePhoneParams as IntrospectValidatePhoneParams from .introspect_validate_phone_response import IntrospectValidatePhoneResponse as IntrospectValidatePhoneResponse +from .whatsapp_business_profile_response import WhatsappBusinessProfileResponse as WhatsappBusinessProfileResponse +from .whatsapp_business_profile_vertical import WhatsappBusinessProfileVertical as WhatsappBusinessProfileVertical from .phone_number_search_available_params import PhoneNumberSearchAvailableParams as PhoneNumberSearchAvailableParams +from .sender_upload_profile_picture_params import SenderUploadProfilePictureParams as SenderUploadProfilePictureParams from .phone_number_search_available_response import ( PhoneNumberSearchAvailableResponse as PhoneNumberSearchAvailableResponse, ) +from .sender_upload_profile_picture_response import ( + SenderUploadProfilePictureResponse as SenderUploadProfilePictureResponse, +) diff --git a/src/zavudev/types/sender.py b/src/zavudev/types/sender.py index 8dd927e..4863684 100644 --- a/src/zavudev/types/sender.py +++ b/src/zavudev/types/sender.py @@ -8,7 +8,36 @@ from .._models import BaseModel from .sender_webhook import SenderWebhook -__all__ = ["Sender"] +__all__ = ["Sender", "Whatsapp", "WhatsappPaymentStatus"] + + +class WhatsappPaymentStatus(BaseModel): + """Payment configuration status from Meta.""" + + can_send_templates: Optional[bool] = FieldInfo(alias="canSendTemplates", default=None) + """Whether template messages can be sent. + + Requires setupStatus=COMPLETE and methodStatus=VALID. + """ + + method_status: Optional[str] = FieldInfo(alias="methodStatus", default=None) + """Payment method status (VALID, NONE, etc.).""" + + setup_status: Optional[str] = FieldInfo(alias="setupStatus", default=None) + """Payment setup status (COMPLETE, NOT_STARTED, etc.).""" + + +class Whatsapp(BaseModel): + """WhatsApp Business Account information. Only present if a WABA is connected.""" + + display_phone_number: Optional[str] = FieldInfo(alias="displayPhoneNumber", default=None) + """Display phone number.""" + + payment_status: Optional[WhatsappPaymentStatus] = FieldInfo(alias="paymentStatus", default=None) + """Payment configuration status from Meta.""" + + phone_number_id: Optional[str] = FieldInfo(alias="phoneNumberId", default=None) + """WhatsApp phone number ID from Meta.""" class Sender(BaseModel): @@ -28,3 +57,6 @@ class Sender(BaseModel): webhook: Optional[SenderWebhook] = None """Webhook configuration for the sender.""" + + whatsapp: Optional[Whatsapp] = None + """WhatsApp Business Account information. Only present if a WABA is connected.""" diff --git a/src/zavudev/types/sender_update_profile_params.py b/src/zavudev/types/sender_update_profile_params.py new file mode 100644 index 0000000..30f344f --- /dev/null +++ b/src/zavudev/types/sender_update_profile_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .._types import SequenceNotStr +from .whatsapp_business_profile_vertical import WhatsappBusinessProfileVertical + +__all__ = ["SenderUpdateProfileParams"] + + +class SenderUpdateProfileParams(TypedDict, total=False): + about: str + """Short description of the business (max 139 characters).""" + + address: str + """Physical address of the business (max 256 characters).""" + + description: str + """Extended description of the business (max 512 characters).""" + + email: str + """Business email address.""" + + vertical: WhatsappBusinessProfileVertical + """Business category for WhatsApp Business profile.""" + + websites: SequenceNotStr[str] + """Business website URLs (maximum 2).""" diff --git a/src/zavudev/types/sender_update_profile_response.py b/src/zavudev/types/sender_update_profile_response.py new file mode 100644 index 0000000..7af0b04 --- /dev/null +++ b/src/zavudev/types/sender_update_profile_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .whatsapp_business_profile import WhatsappBusinessProfile + +__all__ = ["SenderUpdateProfileResponse"] + + +class SenderUpdateProfileResponse(BaseModel): + profile: WhatsappBusinessProfile + """WhatsApp Business profile information.""" + + success: bool diff --git a/src/zavudev/types/sender_upload_profile_picture_params.py b/src/zavudev/types/sender_upload_profile_picture_params.py new file mode 100644 index 0000000..a32dc0b --- /dev/null +++ b/src/zavudev/types/sender_upload_profile_picture_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["SenderUploadProfilePictureParams"] + + +class SenderUploadProfilePictureParams(TypedDict, total=False): + image_url: Required[Annotated[str, PropertyInfo(alias="imageUrl")]] + """URL of the image to upload.""" + + mime_type: Required[Annotated[Literal["image/jpeg", "image/png"], PropertyInfo(alias="mimeType")]] + """MIME type of the image.""" diff --git a/src/zavudev/types/sender_upload_profile_picture_response.py b/src/zavudev/types/sender_upload_profile_picture_response.py new file mode 100644 index 0000000..bc30cf7 --- /dev/null +++ b/src/zavudev/types/sender_upload_profile_picture_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .whatsapp_business_profile import WhatsappBusinessProfile + +__all__ = ["SenderUploadProfilePictureResponse"] + + +class SenderUploadProfilePictureResponse(BaseModel): + profile: WhatsappBusinessProfile + """WhatsApp Business profile information.""" + + success: bool diff --git a/src/zavudev/types/whatsapp_business_profile.py b/src/zavudev/types/whatsapp_business_profile.py new file mode 100644 index 0000000..cfe7b49 --- /dev/null +++ b/src/zavudev/types/whatsapp_business_profile.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .whatsapp_business_profile_vertical import WhatsappBusinessProfileVertical + +__all__ = ["WhatsappBusinessProfile"] + + +class WhatsappBusinessProfile(BaseModel): + """WhatsApp Business profile information.""" + + about: Optional[str] = None + """Short description of the business (max 139 characters).""" + + address: Optional[str] = None + """Physical address of the business (max 256 characters).""" + + description: Optional[str] = None + """Extended description of the business (max 512 characters).""" + + email: Optional[str] = None + """Business email address.""" + + profile_picture_url: Optional[str] = FieldInfo(alias="profilePictureUrl", default=None) + """URL of the business profile picture.""" + + vertical: Optional[WhatsappBusinessProfileVertical] = None + """Business category for WhatsApp Business profile.""" + + websites: Optional[List[str]] = None + """Business website URLs (maximum 2).""" diff --git a/src/zavudev/types/whatsapp_business_profile_response.py b/src/zavudev/types/whatsapp_business_profile_response.py new file mode 100644 index 0000000..40a2aae --- /dev/null +++ b/src/zavudev/types/whatsapp_business_profile_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .whatsapp_business_profile import WhatsappBusinessProfile + +__all__ = ["WhatsappBusinessProfileResponse"] + + +class WhatsappBusinessProfileResponse(BaseModel): + profile: WhatsappBusinessProfile + """WhatsApp Business profile information.""" diff --git a/src/zavudev/types/whatsapp_business_profile_vertical.py b/src/zavudev/types/whatsapp_business_profile_vertical.py new file mode 100644 index 0000000..61a6478 --- /dev/null +++ b/src/zavudev/types/whatsapp_business_profile_vertical.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["WhatsappBusinessProfileVertical"] + +WhatsappBusinessProfileVertical: TypeAlias = Literal[ + "UNDEFINED", + "OTHER", + "AUTO", + "BEAUTY", + "APPAREL", + "EDU", + "ENTERTAIN", + "EVENT_PLAN", + "FINANCE", + "GROCERY", + "GOVT", + "HOTEL", + "HEALTH", + "NONPROFIT", + "PROF_SERVICES", + "RETAIL", + "TRAVEL", + "RESTAURANT", + "NOT_A_BIZ", +] diff --git a/tests/api_resources/test_senders.py b/tests/api_resources/test_senders.py index 5811de8..2e0e3cb 100644 --- a/tests/api_resources/test_senders.py +++ b/tests/api_resources/test_senders.py @@ -9,7 +9,13 @@ from zavudev import Zavudev, AsyncZavudev from tests.utils import assert_matches_type -from zavudev.types import Sender, WebhookSecretResponse +from zavudev.types import ( + Sender, + WebhookSecretResponse, + SenderUpdateProfileResponse, + WhatsappBusinessProfileResponse, + SenderUploadProfilePictureResponse, +) from zavudev.pagination import SyncCursor, AsyncCursor base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -243,6 +249,48 @@ def test_path_params_delete(self, client: Zavudev) -> None: "", ) + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_get_profile(self, client: Zavudev) -> None: + sender = client.senders.get_profile( + "senderId", + ) + assert_matches_type(WhatsappBusinessProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_get_profile(self, client: Zavudev) -> None: + response = client.senders.with_raw_response.get_profile( + "senderId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sender = response.parse() + assert_matches_type(WhatsappBusinessProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_get_profile(self, client: Zavudev) -> None: + with client.senders.with_streaming_response.get_profile( + "senderId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sender = response.parse() + assert_matches_type(WhatsappBusinessProfileResponse, sender, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_get_profile(self, client: Zavudev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sender_id` but received ''"): + client.senders.with_raw_response.get_profile( + "", + ) + @pytest.mark.skip(reason="Prism tests are disabled") @parametrize def test_method_regenerate_webhook_secret(self, client: Zavudev) -> None: @@ -285,6 +333,112 @@ def test_path_params_regenerate_webhook_secret(self, client: Zavudev) -> None: "", ) + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_update_profile(self, client: Zavudev) -> None: + sender = client.senders.update_profile( + sender_id="senderId", + ) + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_update_profile_with_all_params(self, client: Zavudev) -> None: + sender = client.senders.update_profile( + sender_id="senderId", + about="Succulent specialists!", + address="address", + description="We specialize in providing high-quality succulents.", + email="contact@example.com", + vertical="RETAIL", + websites=["https://www.example.com"], + ) + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_update_profile(self, client: Zavudev) -> None: + response = client.senders.with_raw_response.update_profile( + sender_id="senderId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sender = response.parse() + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_update_profile(self, client: Zavudev) -> None: + with client.senders.with_streaming_response.update_profile( + sender_id="senderId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sender = response.parse() + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_update_profile(self, client: Zavudev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sender_id` but received ''"): + client.senders.with_raw_response.update_profile( + sender_id="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_upload_profile_picture(self, client: Zavudev) -> None: + sender = client.senders.upload_profile_picture( + sender_id="senderId", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) + assert_matches_type(SenderUploadProfilePictureResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_upload_profile_picture(self, client: Zavudev) -> None: + response = client.senders.with_raw_response.upload_profile_picture( + sender_id="senderId", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sender = response.parse() + assert_matches_type(SenderUploadProfilePictureResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_upload_profile_picture(self, client: Zavudev) -> None: + with client.senders.with_streaming_response.upload_profile_picture( + sender_id="senderId", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sender = response.parse() + assert_matches_type(SenderUploadProfilePictureResponse, sender, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_upload_profile_picture(self, client: Zavudev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sender_id` but received ''"): + client.senders.with_raw_response.upload_profile_picture( + sender_id="", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) + class TestAsyncSenders: parametrize = pytest.mark.parametrize( @@ -516,6 +670,48 @@ async def test_path_params_delete(self, async_client: AsyncZavudev) -> None: "", ) + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_get_profile(self, async_client: AsyncZavudev) -> None: + sender = await async_client.senders.get_profile( + "senderId", + ) + assert_matches_type(WhatsappBusinessProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_get_profile(self, async_client: AsyncZavudev) -> None: + response = await async_client.senders.with_raw_response.get_profile( + "senderId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sender = await response.parse() + assert_matches_type(WhatsappBusinessProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_get_profile(self, async_client: AsyncZavudev) -> None: + async with async_client.senders.with_streaming_response.get_profile( + "senderId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sender = await response.parse() + assert_matches_type(WhatsappBusinessProfileResponse, sender, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_get_profile(self, async_client: AsyncZavudev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sender_id` but received ''"): + await async_client.senders.with_raw_response.get_profile( + "", + ) + @pytest.mark.skip(reason="Prism tests are disabled") @parametrize async def test_method_regenerate_webhook_secret(self, async_client: AsyncZavudev) -> None: @@ -557,3 +753,109 @@ async def test_path_params_regenerate_webhook_secret(self, async_client: AsyncZa await async_client.senders.with_raw_response.regenerate_webhook_secret( "", ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_update_profile(self, async_client: AsyncZavudev) -> None: + sender = await async_client.senders.update_profile( + sender_id="senderId", + ) + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_update_profile_with_all_params(self, async_client: AsyncZavudev) -> None: + sender = await async_client.senders.update_profile( + sender_id="senderId", + about="Succulent specialists!", + address="address", + description="We specialize in providing high-quality succulents.", + email="contact@example.com", + vertical="RETAIL", + websites=["https://www.example.com"], + ) + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_update_profile(self, async_client: AsyncZavudev) -> None: + response = await async_client.senders.with_raw_response.update_profile( + sender_id="senderId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sender = await response.parse() + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_update_profile(self, async_client: AsyncZavudev) -> None: + async with async_client.senders.with_streaming_response.update_profile( + sender_id="senderId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sender = await response.parse() + assert_matches_type(SenderUpdateProfileResponse, sender, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_update_profile(self, async_client: AsyncZavudev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sender_id` but received ''"): + await async_client.senders.with_raw_response.update_profile( + sender_id="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_upload_profile_picture(self, async_client: AsyncZavudev) -> None: + sender = await async_client.senders.upload_profile_picture( + sender_id="senderId", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) + assert_matches_type(SenderUploadProfilePictureResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_upload_profile_picture(self, async_client: AsyncZavudev) -> None: + response = await async_client.senders.with_raw_response.upload_profile_picture( + sender_id="senderId", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sender = await response.parse() + assert_matches_type(SenderUploadProfilePictureResponse, sender, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_upload_profile_picture(self, async_client: AsyncZavudev) -> None: + async with async_client.senders.with_streaming_response.upload_profile_picture( + sender_id="senderId", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sender = await response.parse() + assert_matches_type(SenderUploadProfilePictureResponse, sender, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_upload_profile_picture(self, async_client: AsyncZavudev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sender_id` but received ''"): + await async_client.senders.with_raw_response.upload_profile_picture( + sender_id="", + image_url="https://example.com/profile.jpg", + mime_type="image/jpeg", + )