import logging import httpx logger = logging.getLogger(__name__) MESSENGER_API_BASE = "https://graph.facebook.com/v22.0" class MessengerHandoverAPI: def __init__(self, page_id: str, access_token: str): self._page_id = page_id self._access_token = access_token async def pass_thread_control( self, psid: str, target_app_id: str, metadata: str = "", ) -> dict | None: url = f"{MESSENGER_API_BASE}/me/pass_thread_control" body = { "recipient": {"id": psid}, "target_app_id": target_app_id, } if metadata: body["metadata"] = metadata try: async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client: resp = await client.post( url, params={"access_token": self._access_token}, json=body, ) if resp.status_code == 200: return resp.json() logger.error(f"messenger pass_thread_control failed: {resp.status_code} {resp.text}") return None except Exception: logger.exception("messenger pass_thread_control error") return None async def take_thread_control( self, psid: str, metadata: str = "", ) -> dict | None: url = f"{MESSENGER_API_BASE}/me/take_thread_control" body = {"recipient": {"id": psid}} if metadata: body["metadata"] = metadata try: async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client: resp = await client.post( url, params={"access_token": self._access_token}, json=body, ) if resp.status_code == 200: return resp.json() logger.error(f"messenger take_thread_control failed: {resp.status_code} {resp.text}") return None except Exception: logger.exception("messenger take_thread_control error") return None async def request_thread_control( self, psid: str, metadata: str = "", ) -> dict | None: url = f"{MESSENGER_API_BASE}/me/request_thread_control" body = {"recipient": {"id": psid}} if metadata: body["metadata"] = metadata try: async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client: resp = await client.post( url, params={"access_token": self._access_token}, json=body, ) if resp.status_code == 200: return resp.json() logger.error(f"messenger request_thread_control failed: {resp.status_code} {resp.text}") return None except Exception: logger.exception("messenger request_thread_control error") return None async def get_secondary_receivers(self) -> list[dict] | None: url = f"{MESSENGER_API_BASE}/me/secondary_receivers" try: async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client: resp = await client.get( url, params={"access_token": self._access_token}, ) if resp.status_code == 200: data = resp.json() return data.get("data", []) logger.error(f"messenger get_secondary_receivers failed: {resp.status_code} {resp.text}") return None except Exception: logger.exception("messenger get_secondary_receivers error") return None async def get_thread_owner(self, psid: str) -> str | None: url = f"{MESSENGER_API_BASE}/me/thread_owner" try: async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client: resp = await client.get( url, params={"recipient": psid, "access_token": self._access_token}, ) if resp.status_code == 200: data = resp.json() return data.get("data", [{}])[0].get("owner_app_id") logger.error(f"messenger get_thread_owner failed: {resp.status_code} {resp.text}") return None except Exception: logger.exception("messenger get_thread_owner error") return None