regenerate from cloud 92604dd76f

This commit is contained in:
2026-08-27 20:41:31 -07:00
parent e31dd96f46
commit c0e89d2ad6
8 changed files with 492 additions and 20 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
ref=a48ddfb3159d3011469f41e5412e1340f2f083e5
sha256=7e3dbc6d34eb0bf0832ee7794496b74ceafc4906d783818592feb06b98a81662
ref=92604dd76f731c0ef713f50d067334628c173811
sha256=553af63847ae7c60ece8a184e09e57ae7bc9d60560b44f749a0146c5b1a19a84
repo=hanzo-inc/cloud
path=openapi.yaml
+9 -9
View File
@@ -294,7 +294,7 @@ class ChannelsApi:
@validate_call
def get_channels_allowlist(
self,
channel: Annotated[Optional[StrictStr], Field(description="Channel is the transport to read: discord, slack, teams or telegram. Required; an unknown value is a 404.")] = None,
channel: Annotated[Optional[StrictStr], Field(description="Channel is the transport to read: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.")] = None,
_request_timeout: Union[
None,
Annotated[StrictFloat, Field(gt=0)],
@@ -312,7 +312,7 @@ class ChannelsApi:
Returns the caller org's access policy for one channel: whether DMs are pairing-gated, allowlisted or open, whether group rooms are open, allowlisted or disabled, the config-managed DM and group allow entries, the senders approved through PAIRING (read-only here), and the org's named access groups. An unknown channel is a 404.
:param channel: Channel is the transport to read: discord, slack, teams or telegram. Required; an unknown value is a 404.
:param channel: Channel is the transport to read: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.
:type channel: str
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
@@ -361,7 +361,7 @@ class ChannelsApi:
@validate_call
def get_channels_allowlist_with_http_info(
self,
channel: Annotated[Optional[StrictStr], Field(description="Channel is the transport to read: discord, slack, teams or telegram. Required; an unknown value is a 404.")] = None,
channel: Annotated[Optional[StrictStr], Field(description="Channel is the transport to read: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.")] = None,
_request_timeout: Union[
None,
Annotated[StrictFloat, Field(gt=0)],
@@ -379,7 +379,7 @@ class ChannelsApi:
Returns the caller org's access policy for one channel: whether DMs are pairing-gated, allowlisted or open, whether group rooms are open, allowlisted or disabled, the config-managed DM and group allow entries, the senders approved through PAIRING (read-only here), and the org's named access groups. An unknown channel is a 404.
:param channel: Channel is the transport to read: discord, slack, teams or telegram. Required; an unknown value is a 404.
:param channel: Channel is the transport to read: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.
:type channel: str
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
@@ -428,7 +428,7 @@ class ChannelsApi:
@validate_call
def get_channels_allowlist_without_preload_content(
self,
channel: Annotated[Optional[StrictStr], Field(description="Channel is the transport to read: discord, slack, teams or telegram. Required; an unknown value is a 404.")] = None,
channel: Annotated[Optional[StrictStr], Field(description="Channel is the transport to read: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.")] = None,
_request_timeout: Union[
None,
Annotated[StrictFloat, Field(gt=0)],
@@ -446,7 +446,7 @@ class ChannelsApi:
Returns the caller org's access policy for one channel: whether DMs are pairing-gated, allowlisted or open, whether group rooms are open, allowlisted or disabled, the config-managed DM and group allow entries, the senders approved through PAIRING (read-only here), and the org's named access groups. An unknown channel is a 404.
:param channel: Channel is the transport to read: discord, slack, teams or telegram. Required; an unknown value is a 404.
:param channel: Channel is the transport to read: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.
:type channel: str
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
@@ -1099,7 +1099,7 @@ class ChannelsApi:
) -> None:
"""Send a message from your org's bot to one chat room
Delivers text, attachments and actions to one room on a connected chat transport — discord, slack, teams or telegram — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404. The body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment. Requires a validated principal; 403 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A transport that fails answers 502 carrying status and shape only, never a token. Sending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. All four transports currently render text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.
Delivers text, attachments and actions to one room on a connected chat transport — discord, slack, teams, telegram or whatsapp — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404. The body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment. Requires a validated principal; 403 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A route learned only so a pairing reply could be delivered lasts exactly as long as that pairing request does, so a room whose sender was never approved goes back to 409 within the hour. A transport that fails answers 502 carrying status and shape only, never a token. Sending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. Every transport currently renders text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.
:param channel: (required)
:type channel: str
@@ -1165,7 +1165,7 @@ class ChannelsApi:
) -> ApiResponse[None]:
"""Send a message from your org's bot to one chat room
Delivers text, attachments and actions to one room on a connected chat transport — discord, slack, teams or telegram — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404. The body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment. Requires a validated principal; 403 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A transport that fails answers 502 carrying status and shape only, never a token. Sending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. All four transports currently render text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.
Delivers text, attachments and actions to one room on a connected chat transport — discord, slack, teams, telegram or whatsapp — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404. The body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment. Requires a validated principal; 403 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A route learned only so a pairing reply could be delivered lasts exactly as long as that pairing request does, so a room whose sender was never approved goes back to 409 within the hour. A transport that fails answers 502 carrying status and shape only, never a token. Sending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. Every transport currently renders text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.
:param channel: (required)
:type channel: str
@@ -1231,7 +1231,7 @@ class ChannelsApi:
) -> RESTResponseType:
"""Send a message from your org's bot to one chat room
Delivers text, attachments and actions to one room on a connected chat transport — discord, slack, teams or telegram — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404. The body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment. Requires a validated principal; 403 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A transport that fails answers 502 carrying status and shape only, never a token. Sending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. All four transports currently render text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.
Delivers text, attachments and actions to one room on a connected chat transport — discord, slack, teams, telegram or whatsapp — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404. The body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment. Requires a validated principal; 403 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A route learned only so a pairing reply could be delivered lasts exactly as long as that pairing request does, so a room whose sender was never approved goes back to 409 within the hour. A transport that fails answers 502 carrying status and shape only, never a token. Sending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. Every transport currently renders text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.
:param channel: (required)
:type channel: str
+472
View File
@@ -6173,6 +6173,242 @@ class IntegrationsApi:
@validate_call
def get_integrations_whatsapp_webhook(
self,
_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,
) -> None:
"""WhatsApp Cloud API subscription challenge
Meta calls this once when the webhook is subscribed, carrying the verify token this deployment was configured with and a challenge to echo. The token is compared in constant time before the echo — answering the challenge without checking it would let anyone point their own app at this address and have it confirm the subscription.
: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._get_integrations_whatsapp_webhook_serialize(
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index
)
_response_types_map: Dict[str, Optional[str]] = {
}
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 get_integrations_whatsapp_webhook_with_http_info(
self,
_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[None]:
"""WhatsApp Cloud API subscription challenge
Meta calls this once when the webhook is subscribed, carrying the verify token this deployment was configured with and a challenge to echo. The token is compared in constant time before the echo — answering the challenge without checking it would let anyone point their own app at this address and have it confirm the subscription.
: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._get_integrations_whatsapp_webhook_serialize(
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index
)
_response_types_map: Dict[str, Optional[str]] = {
}
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 get_integrations_whatsapp_webhook_without_preload_content(
self,
_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:
"""WhatsApp Cloud API subscription challenge
Meta calls this once when the webhook is subscribed, carrying the verify token this deployment was configured with and a challenge to echo. The token is compared in constant time before the echo — answering the challenge without checking it would let anyone point their own app at this address and have it confirm the subscription.
: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._get_integrations_whatsapp_webhook_serialize(
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index
)
_response_types_map: Dict[str, Optional[str]] = {
}
response_data = self.api_client.call_api(
*_param,
_request_timeout=_request_timeout
)
return response_data.response
def _get_integrations_whatsapp_webhook_serialize(
self,
_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, List[str], List[bytes], List[Tuple[str, bytes]]]
] = {}
_body_params: Optional[bytes] = None
# process the path parameters
# process the query parameters
# process the header parameters
# process the form parameters
# process the body parameter
# authentication setting
_auth_settings: List[str] = [
'bearer'
]
return self.api_client.param_serialize(
method='GET',
resource_path='/v1/integrations/whatsapp/webhook',
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 post_integrations_by_provider_connect(
self,
@@ -11955,6 +12191,242 @@ class IntegrationsApi:
@validate_call
def post_integrations_whatsapp_webhook(
self,
_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,
) -> None:
"""WhatsApp Cloud API webhook
One delivery from Meta. Authenticity is the X-Hub-Signature-256 HMAC over the raw body, and it is the whole of it: a message accepted here creates the reply route that authorises this org to answer, so an unsigned delivery would let anyone hand an org a conversation to answer under its own number. Meta batches (entry × changes × messages) and sends status callbacks — sent/delivered/read — through this same address with no message at all. Those are acknowledged and dropped rather than refused, because a non-2xx is retried with backoff and eventually disables the subscription: the only refusals here are an unconfigured endpoint and a bad signature, which are ours to fix and not Meta's to retry. The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
: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._post_integrations_whatsapp_webhook_serialize(
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index
)
_response_types_map: Dict[str, Optional[str]] = {
}
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 post_integrations_whatsapp_webhook_with_http_info(
self,
_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[None]:
"""WhatsApp Cloud API webhook
One delivery from Meta. Authenticity is the X-Hub-Signature-256 HMAC over the raw body, and it is the whole of it: a message accepted here creates the reply route that authorises this org to answer, so an unsigned delivery would let anyone hand an org a conversation to answer under its own number. Meta batches (entry × changes × messages) and sends status callbacks — sent/delivered/read — through this same address with no message at all. Those are acknowledged and dropped rather than refused, because a non-2xx is retried with backoff and eventually disables the subscription: the only refusals here are an unconfigured endpoint and a bad signature, which are ours to fix and not Meta's to retry. The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
: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._post_integrations_whatsapp_webhook_serialize(
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index
)
_response_types_map: Dict[str, Optional[str]] = {
}
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 post_integrations_whatsapp_webhook_without_preload_content(
self,
_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:
"""WhatsApp Cloud API webhook
One delivery from Meta. Authenticity is the X-Hub-Signature-256 HMAC over the raw body, and it is the whole of it: a message accepted here creates the reply route that authorises this org to answer, so an unsigned delivery would let anyone hand an org a conversation to answer under its own number. Meta batches (entry × changes × messages) and sends status callbacks — sent/delivered/read — through this same address with no message at all. Those are acknowledged and dropped rather than refused, because a non-2xx is retried with backoff and eventually disables the subscription: the only refusals here are an unconfigured endpoint and a bad signature, which are ours to fix and not Meta's to retry. The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
: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._post_integrations_whatsapp_webhook_serialize(
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index
)
_response_types_map: Dict[str, Optional[str]] = {
}
response_data = self.api_client.call_api(
*_param,
_request_timeout=_request_timeout
)
return response_data.response
def _post_integrations_whatsapp_webhook_serialize(
self,
_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, List[str], List[bytes], List[Tuple[str, bytes]]]
] = {}
_body_params: Optional[bytes] = None
# process the path parameters
# process the query parameters
# process the header parameters
# process the form parameters
# process the body parameter
# authentication setting
_auth_settings: List[str] = [
'bearer'
]
return self.api_client.param_serialize(
method='POST',
resource_path='/v1/integrations/whatsapp/webhook',
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 put_integrations_github_repos_by_repo_pages(
self,
+1 -1
View File
@@ -27,7 +27,7 @@ class AllowlistPutIn(BaseModel):
AllowlistPutIn
""" # noqa: E501
access_groups: Optional[Dict[str, Dict[str, List[StrictStr]]]] = Field(default=None, description="AccessGroups REPLACES the org's named access groups, as group name -> channel -> entries. Absent or null leaves them alone.", alias="accessGroups")
channel: Optional[StrictStr] = Field(default=None, description="Channel is the transport to edit: discord, slack, teams or telegram. Required; an unknown value is a 404.")
channel: Optional[StrictStr] = Field(default=None, description="Channel is the transport to edit: discord, slack, teams, telegram or whatsapp. Required; an unknown value is a 404.")
dm: Optional[List[StrictStr]] = Field(default=None, description="DM REPLACES the config-managed DM allow entries. Absent or null leaves them alone; an empty list clears them. It never touches senders approved through pairing — a policy edit cannot revoke an approved pairing.")
dm_policy: Optional[StrictStr] = Field(default=None, description="DMPolicy sets how direct messages are admitted: \"pairing\" (a person must be approved first), \"allowlist\" (only listed senders) or \"open\". Empty leaves it unchanged.", alias="dmPolicy")
group: Optional[List[StrictStr]] = Field(default=None, description="Group REPLACES the config-managed group allow entries. Absent or null leaves them alone; an empty list clears them.")
+1 -1
View File
@@ -26,7 +26,7 @@ class AllowlistView(BaseModel):
"""
AllowlistView
""" # noqa: E501
access_groups: Optional[Dict[str, Dict[str, List[StrictStr]]]] = Field(default=None, description="AccessGroups is the org's named sender sets, as group name -> channel -> member entries, held once for the whole org. A DM or Group entry written `accessGroup:<name>` admits any sender listed under that name for THIS channel, or under the channel `*`, which is how one set covers all four transports. Replaced wholesale by the PUT.", alias="accessGroups")
access_groups: Optional[Dict[str, Dict[str, List[StrictStr]]]] = Field(default=None, description="AccessGroups is the org's named sender sets, as group name -> channel -> member entries, held once for the whole org. A DM or Group entry written `accessGroup:<name>` admits any sender listed under that name for THIS channel, or under the channel `*`, which is how one set covers every transport at once. Replaced wholesale by the PUT.", alias="accessGroups")
dm: Optional[List[StrictStr]] = Field(default=None, description="DM is the CONFIG-managed DM allow entries — the list PUT /v1/channels/allowlist owns and replaces wholesale. An entry matches a sender either EXACTLY, as the transport-native id inbox messages carry, or as `accessGroup:<name>` resolved through AccessGroups. A bare `*` admits everyone, but only while DMPolicy is \"open\": it is gate syntax, not an identity, so under \"allowlist\" it matches nobody.")
dm_policy: Optional[StrictStr] = Field(default=None, description="DMPolicy decides every inbound DIRECT message, defaulting to \"pairing\" when the org has never set one. \"pairing\": a sender with no entry is sent a pairing code and the message is DROPPED — it never reaches the inbox — and they are admitted only once an admin approves. \"allowlist\": only DM admits, and Paired senders are suspended, since a pairing grant counts under \"pairing\" alone. \"open\" is not unconditional either — it still requires `*` or a matching entry in DM.", alias="dmPolicy")
group: Optional[List[StrictStr]] = Field(default=None, description="Group is the CONFIG-managed group allow entries, consulted only while GroupPolicy is \"allowlist\". Entries match the same two ways as DM, and here a bare `*` admits every sender in the room.")
@@ -26,7 +26,7 @@ class ApprovePairingIn(BaseModel):
"""
ApprovePairingIn
""" # noqa: E501
channel: Optional[StrictStr] = Field(default=None, description="Channel is the transport the request came in on: discord, slack, teams or telegram.")
channel: Optional[StrictStr] = Field(default=None, description="Channel is the transport the request came in on: discord, slack, teams, telegram or whatsapp.")
code: Optional[StrictStr] = Field(default=None, description="Code is the pairing code from GET /v1/channels/pairing. It is a capability: holding it is what authorises the approval, alongside org admin.")
__properties: ClassVar[List[str]] = ["channel", "code"]
+5 -5
View File
@@ -26,11 +26,11 @@ class Capabilities(BaseModel):
"""
Capabilities
""" # noqa: E501
actions: Optional[StrictBool] = Field(default=None, description="Actions is whether the transport renders an INTERACTIVE control natively, and it is the flag to read before composing one. The vocabulary is a closed kind-tagged union (envelope.go), exactly four kinds, each carrying only its own field plus an optional label: command — a bot command to run (`command`), rendered as a button that invokes it. url — an external link (`url`), rendered as a link button. select — a menu (`options`, each a label and the value choosing it returns), rendered as a picker. approval — a reference to an approval request (`approval.id`), rendered as approve/deny controls bound to that id. False on all four transports this pass, and nothing refuses a send for it: actions are accepted, validated per kind, and flattened by renderText to one line each after the text — `[label] command`, `[label] url`, `[label] opt | opt`, `[label] approval requested: <id>`. So a caller that needs a real control must read this flag and degrade itself; a caller that only needs the choice communicated can send actions and take the text form.")
dm: Optional[StrictBool] = Field(default=None, description="DM is whether the transport carries a DIRECT message at all. True for slack, teams and telegram. False for discord, honestly: that ingress is guild-scoped slash commands — an interaction without a guild id is refused at the endpoint — so nothing ever arrives classified as a DM, no reply route is ever learned for one, and a send addressed at a Discord DM is refused 409.")
group: Optional[StrictBool] = Field(default=None, description="Group is whether the transport carries multi-person rooms — a Discord guild channel, a Slack channel, a Teams channel or group chat, a Telegram group or supergroup. True on all four.")
media: Optional[StrictBool] = Field(default=None, description="Media is whether the transport renders an ATTACHMENT natively. False on all four this pass, and a send is not refused for it: renderText flattens each attachment to one `kind: url (mime)` line after the text rather than dropping it.")
thread: Optional[StrictBool] = Field(default=None, description="Thread is whether a reply can be threaded UNDER a specific message. True for slack alone: it is the only transport whose ingress reports a thread (thread_ts, published as the envelope's replyTo) and whose send posts back into it. Discord's replyTo makes an inline reply rather than a thread, Telegram's answers one message id, and Teams carries no reply target at all — a replyTo sent to it is ignored.")
actions: Optional[StrictBool] = Field(default=None, description="Actions is whether the transport renders an INTERACTIVE control natively, and it is the flag to read before composing one. The vocabulary is a closed kind-tagged union (envelope.go), exactly four kinds, each carrying only its own field plus an optional label: command — a bot command to run (`command`), rendered as a button that invokes it. url — an external link (`url`), rendered as a link button. select — a menu (`options`, each a label and the value choosing it returns), rendered as a picker. approval — a reference to an approval request (`approval.id`), rendered as approve/deny controls bound to that id. False on every transport, and nothing refuses a send for it: actions are accepted, validated per kind, and flattened by renderText to one line each after the text — `[label] command`, `[label] url`, `[label] opt | opt`, `[label] approval requested: <id>`. So a caller that needs a real control must read this flag and degrade itself; a caller that only needs the choice communicated can send actions and take the text form.")
dm: Optional[StrictBool] = Field(default=None, description="DM is whether the transport carries a DIRECT message at all. True for slack, teams, telegram and whatsapp — whatsapp is nothing else, since the Cloud API addresses a person's number and there is no room a third party joins. False for discord, honestly: that ingress is guild-scoped slash commands — an interaction without a guild id is refused at the endpoint — so nothing ever arrives classified as a DM, no reply route is ever learned for one, and a send addressed at a Discord DM is refused 409.")
group: Optional[StrictBool] = Field(default=None, description="Group is whether the transport carries multi-person rooms — a Discord guild channel, a Slack channel, a Teams channel or group chat, a Telegram group or supergroup. False on whatsapp alone, which has no such room to carry.")
media: Optional[StrictBool] = Field(default=None, description="Media is whether the transport renders an ATTACHMENT natively. False everywhere, and a send is not refused for it: renderText flattens each attachment to one `kind: url (mime)` line after the text rather than dropping it. A transport whose egress hands its door the raw text would drop the attachment instead, and an attachment-only send would reach the platform with nothing to say — which is why the flag and the flattening are pinned together.")
thread: Optional[StrictBool] = Field(default=None, description="Thread is whether a reply can be threaded UNDER a specific message. True for slack alone: it is the only transport whose ingress reports a thread (thread_ts, published as the envelope's replyTo) and whose send posts back into it. Discord's replyTo makes an inline reply rather than a thread, Telegram's and WhatsApp's each quote one message, and Teams carries no reply target at all — a replyTo sent to it is ignored.")
__properties: ClassVar[List[str]] = ["actions", "dm", "group", "media", "thread"]
model_config = ConfigDict(
+1 -1
View File
@@ -33,7 +33,7 @@ class ChannelView(BaseModel):
connected: Optional[StrictBool] = Field(default=None, description="Connected is whether integrations holds a connection for (this org, this transport) — whether someone finished its connect flow. False leaves Account and AccountLabel empty, and a send is then refused downstream rather than here: by the transport's own binding check (403 for a Telegram chat this org has not bound, 409 for a Discord or Teams room with no inbound-learned route), or on Slack by the absent per-org bot token, which surfaces as 502.")
dm_policy: Optional[StrictStr] = Field(default=None, description="DMPolicy is how this org admits direct messages here: \"pairing\", \"allowlist\" or \"open\", defaulting to \"pairing\" when the org has never set one.", alias="dmPolicy")
group_policy: Optional[StrictStr] = Field(default=None, description="GroupPolicy is how this org admits group and thread rooms here: \"open\", \"allowlist\" or \"disabled\", defaulting to \"open\". Both policy fields come back EMPTY — rather than the listing failing — when the policy cannot be read; GET /v1/channels/allowlist carries the same two with the entries they consult.", alias="groupPolicy")
id: Optional[StrictStr] = Field(default=None, description="ID is the fixed transport identifier — discord, slack, teams or telegram — and the value every route on this surface names a channel by, including the `:channel` segment of the send path. The listing is always in that order.")
id: Optional[StrictStr] = Field(default=None, description="ID is the fixed transport identifier — discord, slack, teams, telegram or whatsapp — and the value every route on this surface names a channel by, including the `:channel` segment of the send path. The listing is always in that order.")
pending_pairing: Optional[StrictInt] = Field(default=None, description="PendingPairing counts the org's UNEXPIRED pairing requests on this channel: exactly the rows GET /v1/channels/pairing returns for it, one per person waiting on an admin. It never exceeds three — the pending cap per (org, channel) — and expired requests are not counted.", alias="pendingPairing")
__properties: ClassVar[List[str]] = ["account", "accountLabel", "capabilities", "connected", "dmPolicy", "groupPolicy", "id", "pendingPairing"]