Skip to main content
Glama
ag2-mcp-servers

WhatsApp Business API MCP Server

models.py30.3 kB
# generated by fastapi-codegen: # filename: openapi.yaml # timestamp: 2025-06-29T12:14:34+00:00 from __future__ import annotations from datetime import datetime from enum import Enum from typing import Any, Dict, List, Optional, Union from pydantic import BaseModel, Field, RootModel class Address(BaseModel): city: str = Field(..., description='City name') country: str = Field(..., description='Full country name') country_code: str = Field(..., description='Two-letter country abbreviation') state: str = Field(..., description='State abbreviation') street: str = Field(..., description='Street number and name') type: str = Field(..., description='Standard Values: HOME, WORK') zip: str = Field(..., description='ZIP code') class AudioById(BaseModel): id: str class BackupSettings(BaseModel): data: Optional[str] = Field( None, description='The data that has been backed up, encrypted for security.' ) class BackupSettingsRequestBody(BaseModel): password: str = Field(..., description='Used to encrypt backup data for security') class BackupSettingsResponse(BaseModel): settings: Optional[BackupSettings] = None class Basic(BaseModel): password: Optional[str] = None username: Optional[str] = None class BusinessProfile(BaseModel): address: str = Field( ..., description='Address of the business\nMaximum of 256 characters' ) description: str = Field( ..., description='Description of the business\nMaximum of 256 characters' ) email: str = Field( ..., description='Email address to contact the business\nMaximum of 128 characters', ) vertical: str = Field( ..., description='Industry of the business\nMaximum of 128 characters' ) websites: List[str] = Field( ..., description='URLs associated with business (e.g., website, Facebook page, Instagram)\nMaximum of 2 websites with a maximum of 256 characters each', ) class BusinessSettingsBusiness(BaseModel): profile: Optional[BusinessProfile] = None class Status(Enum): processing = 'processing' valid = 'valid' invalid = 'invalid' class CheckContact(BaseModel): input: Optional[str] = Field( None, description='The value you sent in the contacts field of the JSON request.', ) status: Optional[Status] = Field(None, description='Status of the user.') wa_id: Optional[str] = Field( None, description='WhatsApp user identifier that can be used in other API calls. Only returned if the status is valid.', ) class Blocking(Enum): no_wait = 'no_wait' wait = 'wait' class CheckContactRequestBody(BaseModel): blocking: Optional[Blocking] = Field( 'no_wait', description='Blocking determines whether the request should wait for the processing to complete (synchronous) or not (asynchronous).', ) contacts: List[str] = Field( ..., description='Array of contact phone numbers. The numbers can be in any standard telephone number format.', ) class ConfigBasic(BaseModel): basic: Optional[Basic] = None class ConfigBearer(BaseModel): bearer: str class CreateGroupRequestBody(BaseModel): subject: str class CreateUserRequestBody(BaseModel): password: str = Field(..., description='username') username: str = Field(..., description='password') class Currency(BaseModel): amount_1000: int currency_code: str class DayOfWeek(Enum): MONDAY = '1' TUESDAY = '2' WEDNESDAY = '3' THURSDAY = '4' FRIDAY = '5' SATURDAY = '6' SUNDAY = '7' class DateTimeComponent(BaseModel): day_of_month: Optional[int] = Field(None, description='The day of month') day_of_week: Optional[DayOfWeek] = Field( None, description='Both strings and numbers are accepted. If different from the value derived from the date (if specified), use the derived value.', ) hour: Optional[int] = Field(None, description='The hour') minute: Optional[int] = Field(None, description='The minute') month: Optional[int] = Field(None, description='The month') year: Optional[int] = Field(None, description='The year') class DateTimeUnixEpoch(BaseModel): timestamp: Optional[int] = Field(None, description='Epoch timestamp in seconds') class DocumentById(BaseModel): caption: str filename: str id: str class Email(BaseModel): email: str type: str class EnableTwoStepRequestBody(BaseModel): pin: str class Error(BaseModel): code: Optional[int] = Field( None, description='See the https://developers.facebook.com/docs/whatsapp/api/errors for more information.', ) details: Optional[str] = Field(None, description='error detail') href: Optional[str] = Field(None, description='location for error detail') title: Optional[str] = Field(None, description='error title') class Role(Enum): primary_master = 'primary_master' secondary_master = 'secondary_master' coreapp = 'coreapp' class GatewayNodeStatus(BaseModel): gateway_status: Optional[str] = None role: Optional[Role] = None class GatewayStatus(Enum): connected = 'connected' connecting = 'connecting' disconnected = 'disconnected' uninitialized = 'uninitialized' unregistered = 'unregistered' class Group(BaseModel): creation_time: Optional[int] = Field(None, description='timestamp') id: Optional[str] = None class GroupAdminRequestBody(BaseModel): wa_ids: List[str] = Field( ..., description='The WhatsApp IDs of the people to be added or removed as group admins', ) class GroupInfo(BaseModel): admins: Optional[List[str]] = Field( None, description='Group administrators\nLists IDs of the creator of the group and any administrators added', ) creation_time: Optional[int] = Field(None, description='Group creation time') creator: Optional[str] = Field(None, description='ID of the creator of this group') participants: Optional[List[str]] = Field( None, description='Participants of the group\nThis is an array of all the IDs of the participants in the group. Initially, this will be the creator of the group.', ) subject: Optional[str] = Field(None, description='Subject of the group') class GroupInvite(BaseModel): link: Optional[str] = None class ImageById(BaseModel): caption: str id: str class Policy(Enum): fallback = 'fallback' deterministic = 'deterministic' class Language(BaseModel): code: str = Field( ..., description='The code of the language or locale to use — Accepts both language and language_locale formats (e.g., en and en_US).', ) policy: Policy = Field( ..., description='The language policy the message should follow' ) class Location(BaseModel): address: str = Field( ..., description='Address of the location. Only displayed if name is present.' ) latitude: str = Field(..., description='Latitude of the location') longitude: str = Field(..., description='Longitude of the location') name: str = Field(..., description='Name of the location') class LoginAdminRequestBody(BaseModel): new_password: str class MarkMessageAsReadRequestBody(BaseModel): status: str class AutoDownloadEnum(Enum): audio = 'audio' document = 'document' voice = 'voice' video = 'video' image_ = 'image.' class Media(BaseModel): auto_download: List[AutoDownloadEnum] = Field( ..., description='An array specifying which types of media to automatically download.', ) class Message(BaseModel): id: Optional[str] = None class MessageContext(BaseModel): from_: Optional[str] = Field( None, alias='from', description='Sender Whatsapp id of context-message' ) group_id: Optional[str] = Field(None, description='GroupId of context message') id: Optional[str] = Field(None, description='message id') mentions: Optional[List[str]] = Field(None, description='Whats app ids') class MessageType(Enum): audio = 'audio' contacts = 'contacts' document = 'document' hsm = 'hsm' image = 'image' location = 'location' text = 'text' video = 'video' voice = 'voice' unknown = 'unknown' class ApiStatus(Enum): deprecated = 'deprecated' experimental = 'experimental' stable = 'stable' class Meta(BaseModel): api_status: Optional[ApiStatus] = None version: Optional[str] = None class Name(BaseModel): first_name: Optional[str] = Field(None, description='First name') formatted_name: str = Field(..., description='Full name as it normally appears') last_name: Optional[str] = Field(None, description='Last name') prefix: Optional[str] = Field(None, description='Name preffix') suffix: Optional[str] = Field(None, description='Name suffix') class Org(BaseModel): company: str = Field(..., description="Name of the contact's company") department: Optional[str] = Field( None, description="Name of the contact's department" ) title: Optional[str] = Field(None, description="Contact's business title") class Phone(BaseModel): phone: Optional[str] = None type: Optional[str] = Field( None, description='Standard Values: CELL, MAIN, IPHONE, HOME, WORK' ) wa_id: Optional[str] = Field(None, description='WhatsApp ID') class ProfileAbout(BaseModel): text: str = Field( ..., description="Text to display in your profile's About section\nThe max length for the string is 139 characters.", ) class ProfileAboutSettingsProfile(BaseModel): about: Optional[ProfileAbout] = None class Photo(BaseModel): link: Optional[str] = None class Profile(BaseModel): photo: Optional[Photo] = None class ProfilePhotoSettings(BaseModel): profile: Optional[Profile] = None class ProfilePhotoSettingsProfilePhoto(BaseModel): link: Optional[str] = None class Provider(BaseModel): name: str class RegisterAccountRequestBody(BaseModel): code: str class RemoveGroupParticipantRequestBody(BaseModel): wa_ids: List[str] = Field(..., description='') class RequestCodeAccount(BaseModel): vname: Optional[str] = None class Method(Enum): sms = 'sms' voice = 'voice' class RequestCodeRequestBody(BaseModel): cc: str = Field( ..., description='Numerical country code for the phone number you are registering', ) cert: str = Field(..., description='Base64-encoded Verified Name certificate') method: Method = Field( ..., description='Method of receiving your registration code' ) phone_number: str = Field( ..., description='Phone number you are registering, without the country code or plus symbol (+)', ) pin: Optional[str] = Field( None, description='Existing 6-digit PIN — This is only required when two-factor verification is enabled on this account.', ) class RequestCodeResponse(BaseModel): account: Optional[List[RequestCodeAccount]] = None class Response(BaseModel): errors: Optional[List[Error]] = Field( None, description='Only returned with a failed request. Contains an array of error objects that are present when there is an error. ', ) meta: Optional[Meta] = None class RestoreSettingsRequestBody(BaseModel): data: str = Field( ..., description='The data that was returned by the /v1/settings/backup API call', ) password: str = Field( ..., description='The password you used in the /v1/settings/backup API call to encrypt the backup data', ) class RecipientType(Enum): individual = 'individual' group = 'group' class Shards(Enum): field_1 = '1' field_2 = '2' field_4 = '4' field_8 = '8' field_16 = '16' field_32 = '32' class SetShardsRequestBody(BaseModel): cc: str phone_number: str pin: str shards: Shards class Text(BaseModel): body: str class UpdateGroupInfoRequestBody(BaseModel): subject: str class UpdateUserRequestBody(BaseModel): password: str = Field(..., description='password') class UploadMedia(BaseModel): id: Optional[str] = None class UploadMediaResponse(Response): media: Optional[List[UploadMedia]] = None class Url(BaseModel): type: Optional[str] = Field(None, description='Standard Values: HOME, WORK') url: Optional[str] = Field(None, description='URL') class UserLoginResponseItem(BaseModel): expires_after: Optional[datetime] = Field( None, description='Token expiration timestamp. By default, this is 7 days.' ) token: Optional[str] = Field( None, description='Authentication token to be used for all other WhatsApp Business API calls. The token must be sent in the authorization header in the format:\nAuthorization: Bearer <authentication-token>', ) class UserResponseItem(BaseModel): username: Optional[str] = None class UserRole(Enum): ROLE_ADMIN = 'ROLE_ADMIN' ROLE_USER = 'ROLE_USER' class VideoById(BaseModel): caption: str id: str class VideoByProvider(BaseModel): caption: str link: str provider: Provider class WebhookAudio(BaseModel): caption: Optional[str] = Field( None, description='Optional. Only present if specified.' ) file: Optional[str] = Field( None, description='Absolute filename and location on media volume. This parameter is deprecated.', ) filename: Optional[str] = Field( None, description="Filename on the sender's device. This will only be present in audio and document media messages.", ) id: Optional[str] = Field( None, description='ID of the media. Can be used to delete the media if stored locally on the client.', ) link: Optional[str] = None mime_type: Optional[str] = Field(None, description='Mime type of media') sha256: Optional[str] = Field(None, description='Checksum') class WebhookContactProfile(BaseModel): name: Optional[str] = Field( None, description="Optional. As of v2.21.4, contains the sender's profile name." ) class WebhookDocument(BaseModel): caption: Optional[str] = Field( None, description='Optional. Only present if specified.' ) file: Optional[str] = Field( None, description='Absolute filename and location on media volume. This parameter is deprecated.', ) filename: Optional[str] = Field( None, description="Filename on the sender's device. This will only be present in audio and document media messages.", ) id: Optional[str] = Field( None, description='ID of the media. Can be used to delete the media if stored locally on the client.', ) link: Optional[str] = None mime_type: Optional[str] = Field(None, description='Mime type of media') sha256: Optional[str] = Field(None, description='Checksum') class WebhookImage(BaseModel): caption: Optional[str] = Field( None, description='Optional. Only present if specified.' ) file: Optional[str] = Field( None, description='Absolute filename and location on media volume. This parameter is deprecated.', ) id: Optional[str] = Field( None, description='ID of the media. Can be used to delete the media if stored locally on the client.', ) link: Optional[str] = None mime_type: Optional[str] = Field(None, description='Mime type of media') sha256: Optional[str] = Field(None, description='Checksum') class WebhookLocation(BaseModel): address: Optional[str] = Field(None, description='Address of the location') latitude: Optional[float] = Field( None, description='Latitude of location being sent' ) longitude: Optional[float] = Field( None, description='Longitude of location being sent' ) name: Optional[str] = Field(None, description='Name of the location') url: Optional[str] = Field( None, description='URL for the website where the user downloaded the location information', ) class Status1(Enum): sent = 'sent' delivered = 'delivered' read = 'read' failed = 'failed' deleted = 'deleted' class WebhookStatus(BaseModel): errors: Optional[List[Error]] = None id: Optional[str] = Field(None, description='Message ID') recipient_id: Optional[str] = Field(None, description='WhatsApp ID of recipient') status: Optional[Status1] = Field(None, description='Status of message') timestamp: Optional[str] = Field( None, description='Timestamp of the status message' ) class Type(Enum): group_created = 'group_created' group_user_promoted = 'group_user_promoted' group_user_demoted = 'group_user_demoted' group_user_joined = 'group_user_joined' group_user_left = 'group_user_left' group_subject_changed = 'group_subject_changed' group_description_changed = 'group_description_changed' group_icon_changed = 'group_icon_changed' group_icon_deleted = 'group_icon_deleted' group_invite_link_revoked = 'group_invite_link_revoked' user_identity_changed = 'user_identity_changed' group_user_changed_number = 'group_user_changed_number' group_error_fetching_photo = 'group_error_fetching_photo' group_error_adding_users = 'group_error_adding_users' group_error_adding_user = 'group_error_adding_user' group_error_full_adding_users = 'group_error_full_adding_users' group_error_removing_user = 'group_error_removing_user' broadcast_list_created = 'broadcast_list_created' group_ended = 'group_ended' group_error_blocked_adding_user = 'group_error_blocked_adding_user' class WebhookSystem(BaseModel): body: Optional[str] = None type: Optional[Type] = Field(None, description='') class WebhookText(BaseModel): body: Optional[str] = Field(None, description='Message text') class WebhookVideo(BaseModel): caption: Optional[str] = Field( None, description='Optional. Only present if specified.' ) file: Optional[str] = Field( None, description='Absolute filename and location on media volume. This parameter is deprecated.', ) id: Optional[str] = Field( None, description='ID of the media. Can be used to delete the media if stored locally on the client.', ) link: Optional[str] = None mime_type: Optional[str] = Field(None, description='Mime type of media') sha256: Optional[str] = Field(None, description='Checksum') class WebhookVoice(BaseModel): caption: Optional[str] = Field( None, description='Optional. Only present if specified.' ) file: Optional[str] = Field( None, description='Absolute filename and location on media volume. This parameter is deprecated.', ) id: Optional[str] = Field( None, description='ID of the media. Can be used to delete the media if stored locally on the client.', ) link: Optional[str] = None mime_type: Optional[str] = Field(None, description='Mime type of media') sha256: Optional[str] = Field(None, description='Checksum') class MaxConcurrentRequests(Enum): field_6 = '6' field_12 = '12' field_18 = '18' field_24 = '24' class Webhooks(BaseModel): max_concurrent_requests: Optional[MaxConcurrentRequests] = Field( 6, description='Configures the maximum number of inflight callback requests that are sent out. Can be set to 6 (default), 12, 18, or 24.', ) url: Optional[str] = Field( None, description='Inbound and outbound notifications are routed to this URL. A HTTPS-based endpoint is required; HTTP will not work.', ) class GroupsGroupIdIconDeleteRequest(BaseModel): File: bytes class GroupsGroupIdIconPostRequest(BaseModel): File: bytes class MetricsGetResponse(BaseModel): pass class SettingsProfilePhotoPostRequest(BaseModel): File: bytes class StatsAppGetResponse(BaseModel): pass class StatsDbGetResponse(BaseModel): pass class SupportGetResponse(BaseModel): pass class ApplicationSettings(BaseModel): callback_backoff_delay_ms: Optional[str] = Field( '3000', description='Backoff delay for a failed callback in milliseconds\nThis setting is used to configure the amount of time the backoff delays before retrying a failed callback. The backoff delay increases linearly by this value each time a callback fails to get a HTTPS 200 OK response. The backoff delay is capped by the max_callback_backoff_delay_ms setting.', ) callback_persist: Optional[bool] = Field( True, description='Stores callbacks on disk until they are successfully acknowledged by the Webhook or not. Restart required.', ) heartbeat_interval: Optional[int] = Field( 5, description='Multiconnect: Interval of the Master node monitoring of Coreapp nodes in seconds', ) max_callback_backoff_delay_ms: Optional[str] = Field( '900000', description='Maximum delay for a failed callback in milliseconds' ) media: Optional[Media] = None on_call_pager: Optional[str] = Field( None, description='Set to valid WhatsApp Group with users who wish to see alerts for critical errors and messages.', ) pass_through: Optional[bool] = Field( True, description="When true, removes messages from the local database after they are delivered to or read by the recipient. When false, saves all messages on local storage until they are explicitly deleted.\nWhen messages are sent, they are stored in a local database. This database is used as the application's history. Since the business keeps its own history, you can specify whether you want message pass_through or not. Restart required.", ) sent_status: Optional[bool] = Field( False, description='Receive a notification that a message is sent to server. When true, you will receive a message indicating that a message has been sent. If false (default), you will not receive notification.', ) unhealthy_interval: Optional[int] = Field( 30, description='Multiconnect: Maximum amount of seconds a Master node waits for a Coreapp node to respond to a heartbeat before considering it unhealthy and starting the failover process.', ) webhooks: Optional[Webhooks] = None class AudioByProvider(BaseModel): link: str provider: Provider class BusinessSettings(BaseModel): business: Optional[BusinessSettingsBusiness] = None class CheckContactResponse(Response): contacts: Optional[List[CheckContact]] = None class CheckHealthResponse(BaseModel): health: Optional[Union[GatewayStatus, Dict[str, GatewayNodeStatus]]] = None class Config(RootModel[Union[ConfigBearer, ConfigBasic]]): root: Union[ConfigBearer, ConfigBasic] = Field(..., title='Config') class Contact(BaseModel): addresses: Optional[List[Address]] = Field( None, description='Full contact address(es)' ) birthday: Optional[str] = Field(None, description='YYYY-MM-DD formatted string') emails: Optional[List[Email]] = Field(None, description='Contact email address(es)') ims: Optional[List[str]] = Field(None, description='') name: Optional[Name] = None org: Optional[Org] = None phones: Optional[List[Phone]] = Field(None, description='Contact phone number(s)') urls: Optional[List[Url]] = Field(None, description='Contact URL(s)') class DateTimeObject(BaseModel): component: Optional[DateTimeComponent] = None unix_epoch: Optional[DateTimeUnixEpoch] = None class DetailedUserResponseItem(BaseModel): ROLES: Optional[UserRole] = None username: Optional[str] = None class DocumentByProvider(BaseModel): caption: str filename: str link: str provider: Provider class GetBusinessProfileResponse(Response): settings: Optional[BusinessSettings] = None class GetProfilePhotoResponse(BaseModel): settings: Optional[ProfilePhotoSettings] = None class GroupInviteResponse(Response): groups: Optional[List[GroupInvite]] = None class GroupResponse(Response): groups: Optional[List[GroupInfo]] = None class GroupsResponse(Response): groups: Optional[List[Group]] = None class ImageByProvider(BaseModel): caption: str link: str provider: Provider class LocalizableParam(BaseModel): currency: Optional[Currency] = None date_time: Optional[DateTimeObject] = None default: str = Field(..., description='Default text if localization fails') class MediaProvider(BaseModel): config: Optional[Config] = None name: Optional[str] = Field(None, description='The name for the provider') type: Optional[str] = Field(None, description='The type of provider') class MediaProviderSettingsApplicationMedia(BaseModel): providers: Optional[List[MediaProvider]] = None class MessageResponse(Response): messages: Optional[List[Message]] = None class ProfileAboutSettings(BaseModel): profile: Optional[ProfileAboutSettingsProfile] = None class ProfilePhotoSettingsProfile(BaseModel): photo: Optional[ProfilePhotoSettingsProfilePhoto] = None class UserLoginResponse(Response): users: Optional[List[UserLoginResponseItem]] = None class UserResponse(Response): users: Optional[List[UserResponseItem]] = None class Video(RootModel[Union[VideoById, VideoByProvider]]): root: Union[VideoById, VideoByProvider] = Field( ..., description='The media object containing a video', title='Video' ) class WebhookContact(BaseModel): profile: Optional[WebhookContactProfile] = None wa_id: Optional[str] = Field(None, description='The WhatsApp ID of the contact') class WebhookMessage(BaseModel): audio: Optional[WebhookAudio] = None contacts: Optional[List[Contact]] = None context: Optional[MessageContext] = None document: Optional[WebhookDocument] = None errors: Optional[List[Error]] = None from_: Optional[str] = Field( None, alias='from', description='WhatsApp ID of the sender' ) group_id: Optional[str] = Field(None, description='Optional. WhatsApp group ID') id: Optional[str] = Field(None, description='Message ID') image: Optional[WebhookImage] = None location: Optional[WebhookLocation] = None system: Optional[WebhookSystem] = None text: Optional[WebhookText] = None timestamp: Optional[str] = Field(None, description='Message received timestamp') type: Optional[MessageType] = 'text' video: Optional[WebhookVideo] = None voice: Optional[WebhookVoice] = None class SettingsApplicationMediaProvidersPostRequest(RootModel[List[MediaProvider]]): root: List[MediaProvider] = Field(..., description='') class Audio(RootModel[Union[AudioById, AudioByProvider]]): root: Union[AudioById, AudioByProvider] = Field( ..., description='The media object containing audio', title='Audio' ) class DetailedUserResponse(Response): users: Optional[List[DetailedUserResponseItem]] = None class Document(RootModel[Union[DocumentById, DocumentByProvider]]): root: Union[DocumentById, DocumentByProvider] = Field( ..., description='The media object containing a document', title='Document' ) class GetProfileAboutResponse(BaseModel): settings: Optional[ProfileAboutSettings] = None class Hsm(BaseModel): element_name: str = Field( ..., description='The element name that indicates which template to use within the namespace', ) language: Language localizable_params: List[LocalizableParam] = Field( ..., description='This field is an array of values to apply to variables in the template', ) namespace: str = Field(..., description='The namespace that will be used') class Image(RootModel[Union[ImageById, ImageByProvider]]): root: Union[ImageById, ImageByProvider] = Field( ..., description='The media object containing an image', title='Image' ) class MediaProviderSettingsApplication(BaseModel): media: Optional[MediaProviderSettingsApplicationMedia] = None class SendMessageRequestBody(BaseModel): audio: Optional[Audio] = None contacts: Optional[List[Contact]] = Field(None, description='') document: Optional[Document] = None hsm: Optional[Hsm] = None image: Optional[Image] = None location: Optional[Location] = None preview_url: Optional[bool] = Field( None, description='Specifying preview_url in the request is optional when not including a URL in your message.\nTo include a URL preview, set preview_url to true in the message body and make sure the URL begins with http:// or https://. For more information, see the Sending URLs in Text Messages section.', ) recipient_type: Optional[RecipientType] = Field( 'individual', description='Determines whether the recipient is an individual or a group\nSpecifying recipient_type in the request is optional when the value is individual.\nHowever, recipient_type is required when using group. If sending a text message to a group, see the Sending Group Messages documentation.', ) text: Optional[Text] = None to: str = Field( ..., description='When recipient_type is individual, this field is the WhatsApp ID (phone number) returned from contacts endpoint. When recipient_type is group, this field is the WhatsApp group ID.', ) ttl: Optional[Dict[str, Any]] = None type: Optional[MessageType] = 'text' video: Optional[Video] = None class WebhookEvent(BaseModel): contacts: Optional[List[WebhookContact]] = None errors: Optional[List[Error]] = None messages: Optional[List[WebhookMessage]] = None statuses: Optional[List[WebhookStatus]] = None class MediaProviderSettings(BaseModel): application: Optional[MediaProviderSettingsApplication] = None class GetMediaProvidersResponse(Response): settings: Optional[MediaProviderSettings] = None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ag2-mcp-servers/whatsapp-business-api'

If you have feedback or need assistance with the MCP directory API, please join our Discord server