<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-user-guide/messaging/weixin" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.10.2">
<title data-rh="true">Weixin (WeChat) | Hermes Agent</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://hermes-agent.nousresearch.com/docs/img/hermes-agent-banner.png"><meta data-rh="true" name="twitter:image" content="https://hermes-agent.nousresearch.com/docs/img/hermes-agent-banner.png"><meta data-rh="true" property="og:url" content="https://hermes-agent.nousresearch.com/docs/user-guide/messaging/weixin"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" property="og:locale:alternate" content="zh_Hans"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Weixin (WeChat) | Hermes Agent"><meta data-rh="true" name="description" content="Connect Hermes Agent to personal WeChat accounts via the iLink Bot API"><meta data-rh="true" property="og:description" content="Connect Hermes Agent to personal WeChat accounts via the iLink Bot API"><link data-rh="true" rel="icon" href="/docs/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://hermes-agent.nousresearch.com/docs/user-guide/messaging/weixin"><link data-rh="true" rel="alternate" href="https://hermes-agent.nousresearch.com/docs/user-guide/messaging/weixin" hreflang="en"><link data-rh="true" rel="alternate" href="https://hermes-agent.nousresearch.com/docs/zh-Hans/user-guide/messaging/weixin" hreflang="zh-Hans"><link data-rh="true" rel="alternate" href="https://hermes-agent.nousresearch.com/docs/user-guide/messaging/weixin" hreflang="x-default"><link data-rh="true" rel="preconnect" href="https://2JLBVEYZN5-dsn.algolia.net" crossorigin="anonymous"><script data-rh="true" type="application/ld+json">{"@context":"https://***@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Weixin (WeChat)","item":"https://hermes-agent.nousresearch.com/docs/user-guide/messaging/weixin"}]}</script><link rel="search" type="application/opensearchdescription+xml" title="Hermes Agent" href="/docs/opensearch.xml"><link rel="stylesheet" href="/docs/assets/css/styles.c765adef.css">
<script src="/docs/assets/js/runtime~main.af977a06.js" defer="defer"></script>
<script src="/docs/assets/js/main.e36c6506.js" defer="defer"></script>
</head>
<body>
<svg style="display: none;"><defs>
<symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol>
</defs></svg>
<script>!function(){var t=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();document.documentElement.setAttribute("data-theme",t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")),document.documentElement.setAttribute("data-theme-choice",t||"system")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><link rel="preload" as="image" href="/docs/img/logo.png"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="theme-layout-navbar navbar navbar--fixed-top"><div class="navbar__inner"><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/docs/"><div class="navbar__logo"><img src="/docs/img/logo.png" alt="Hermes Agent" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="/docs/img/logo.png" alt="Hermes Agent" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><b class="navbar__title text--truncate">Hermes Agent</b></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/user-stories">Docs</a><a class="navbar__item navbar__link" href="/docs/skills">Skills</a><a class="navbar__item navbar__link" href="/docs/plugins">Plugins</a><a href="https://hermes-agent.nousresearch.com/" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Download<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link"><svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" class="iconLanguage_nlXk"><path fill="currentColor" d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"></path></svg>English</a><ul class="dropdown__menu"><li><a href="/docs/user-guide/messaging/weixin" target="_self" rel="noopener noreferrer" class="dropdown__link dropdown__link--active" lang="en">English</a></li><li><a href="/docs/zh-Hans/user-guide/messaging/weixin" target="_self" rel="noopener noreferrer" class="dropdown__link" lang="zh-Hans">简体中文</a></li></ul></div><a href="https://hermes-agent.nousresearch.com" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Home<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><a href="https://github.com/NousResearch/hermes-agent" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><a href="https://discord.gg/NousResearch" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Discord<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="system mode" aria-label="Switch between dark and light mode (currently system mode)"><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP systemToggleIcon_QzmC"><path fill="currentColor" d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"></path></svg></button></div><div class="navbarSearchContainer_Bca1"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search (Meta+k)" aria-keyshortcuts="Meta+k"><span class="DocSearch-Button-Container"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="8" stroke="currentColor" fill="none" stroke-width="1.4"></circle><path d="m21 21-4.3-4.3" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"></span></button></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="theme-layout-main main-wrapper mainWrapper_z2l0"><div class="docsWrapper_hBAB"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docRoot_UBD9"><aside class="theme-doc-sidebar-container docSidebarContainer_YfHR"><div class="sidebarViewport_aRkj"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/docs/user-stories"><span class="linkLabel_WmDU">User Stories &amp; Use Cases</span></a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/getting-started/quickstart"><span class="categoryLinkLabel_W154">Getting Started</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/user-guide/cli"><span class="categoryLinkLabel_W154">Using Hermes</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/user-guide/features/overview"><span class="categoryLinkLabel_W154">Features</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" href="/docs/user-guide/messaging/"><span class="categoryLinkLabel_W154">Messaging Platforms</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/"><span class="linkLabel_WmDU">Messaging Gateway</span></a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" tabindex="0" href="/docs/user-guide/messaging/telegram"><span class="categoryLinkLabel_W154">Popular</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" tabindex="0" href="/docs/user-guide/messaging/teams"><span class="categoryLinkLabel_W154">Microsoft 365</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" tabindex="0" href="/docs/user-guide/messaging/dingtalk"><span class="categoryLinkLabel_W154">Chinese platforms</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/dingtalk"><span class="linkLabel_WmDU">DingTalk</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/feishu"><span class="linkLabel_WmDU">Feishu / Lark</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/wecom"><span class="linkLabel_WmDU">WeCom (Enterprise WeChat)</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/wecom-callback"><span class="linkLabel_WmDU">WeCom Callback (Self-Built App)</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/docs/user-guide/messaging/weixin"><span class="linkLabel_WmDU">Weixin (WeChat)</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/qqbot"><span class="linkLabel_WmDU">QQ Bot</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/user-guide/messaging/yuanbao"><span class="linkLabel_WmDU">Yuanbao</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" tabindex="0" href="/docs/user-guide/messaging/a2a"><span class="categoryLinkLabel_W154">Other</span></a></div></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/integrations/"><span class="categoryLinkLabel_W154">Integrations</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/guides/run-nemotron-3-ultra-free"><span class="categoryLinkLabel_W154">Guides &amp; Tutorials</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/developer-guide/contributing"><span class="categoryLinkLabel_W154">Developer Guide</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/reference/cli-commands"><span class="categoryLinkLabel_W154">Reference</span></a></div></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_PEFL"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_kv0_"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></div></aside><main class="docMainContainer_TBSr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="docItemContainer_Djhp"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="Breadcrumbs"><ul class="breadcrumbs"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/docs/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YNFT"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">Messaging Platforms</span></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">Chinese platforms</span></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">Weixin (WeChat)</span></li></ul></nav><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Weixin (WeChat)</h1></header>
<p>Connect Hermes to <a href="https://weixin.qq.com/" target="_blank" rel="noopener noreferrer" class="">WeChat</a> (微信), Tencent&#x27;s personal messaging platform. The adapter uses Tencent&#x27;s <strong>iLink Bot API</strong> for personal WeChat accounts — this is distinct from WeCom (Enterprise WeChat). Messages are delivered via long-polling, so no public endpoint or webhook is required.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>This adapter is for <strong>personal WeChat accounts</strong> (微信). If you need enterprise/corporate WeChat, see the <a class="" href="/docs/user-guide/messaging/wecom">WeCom adapter</a> instead.</p></div></div>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>iLink bot identity — ordinary WeChat groups may not work</div><div class="admonitionContent_BuS1"><p>QR login connects Hermes to an <strong>iLink bot identity</strong> (e.g. <code>a5ace6fd482e@im.bot</code>), <strong>not</strong> a fully scriptable ordinary personal WeChat account. Consequences:</p><ul>
<li class="">The iLink bot identity generally <strong>cannot be invited into ordinary WeChat groups</strong> the way a normal contact can.</li>
<li class="">iLink typically <strong>does not deliver ordinary WeChat group events</strong> (including <code>@</code>-mentions of the personal account used for QR login) to the gateway for most bot-type accounts.</li>
<li class=""><code>@</code>-mentioning the personal WeChat account used to scan the QR code is <strong>not</strong> the same as <code>@</code>-mentioning the iLink bot — the bot is a separate identity.</li>
<li class="">The <code>WEIXIN_GROUP_POLICY</code> / <code>WEIXIN_GROUP_ALLOWED_USERS</code> settings below only take effect when iLink actually returns group events for your account type. If it doesn&#x27;t, group messages will never reach Hermes regardless of policy.</li>
</ul><p>In practice, most deployments only get DMs to the iLink bot working reliably. If group delivery doesn&#x27;t work after configuration, the limitation is on the iLink side, not in Hermes. The gateway logs a <code>WARNING</code> at startup whenever <code>WEIXIN_GROUP_POLICY</code> is set to anything other than <code>disabled</code>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<ul>
<li class="">A personal WeChat account</li>
<li class="">Python packages: <code>aiohttp</code> and <code>cryptography</code></li>
<li class="">Terminal QR rendering is included when Hermes is installed with the <code>messaging</code> extra</li>
</ul>
<p>Install the required dependencies:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">pip </span><span class="token function" style="color:rgb(80, 250, 123)">install</span><span class="token plain"> aiohttp cryptography</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Optional: for terminal QR code display</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">cd</span><span class="token plain"> ~/.hermes/hermes-agent </span><span class="token operator">&amp;&amp;</span><span class="token plain"> uv pip </span><span class="token function" style="color:rgb(80, 250, 123)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-e</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;.[messaging]&quot;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="setup">Setup<a href="#setup" class="hash-link" aria-label="Direct link to Setup" title="Direct link to Setup" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-run-the-setup-wizard">1. Run the Setup Wizard<a href="#1-run-the-setup-wizard" class="hash-link" aria-label="Direct link to 1. Run the Setup Wizard" title="Direct link to 1. Run the Setup Wizard" translate="no">​</a></h3>
<p>The easiest way to connect your WeChat account is through the interactive setup:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">hermes gateway setup</span><br></div></code></pre></div></div>
<p>Select <strong>Weixin</strong> when prompted. The wizard will:</p>
<ol>
<li class="">Request a QR code from the iLink Bot API</li>
<li class="">Display the QR code in your terminal (or provide a URL)</li>
<li class="">Wait for you to scan the QR code with the WeChat mobile app</li>
<li class="">Prompt you to confirm the login on your phone</li>
<li class="">Save the account credentials automatically to <code>~/.hermes/weixin/accounts/</code></li>
</ol>
<p>Once confirmed, you&#x27;ll see a message like:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">微信连接成功，account_id=your-account-id</span><br></div></code></pre></div></div>
<p>The wizard stores the <code>account_id</code>, <code>token</code>, and <code>base_url</code> so you don&#x27;t need to configure them manually.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-configure-environment-variables">2. Configure Environment Variables<a href="#2-configure-environment-variables" class="hash-link" aria-label="Direct link to 2. Configure Environment Variables" title="Direct link to 2. Configure Environment Variables" translate="no">​</a></h3>
<p>After initial QR login, set at minimum the account ID in <code>~/.hermes/.env</code>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_ACCOUNT_ID</span><span class="token operator">=</span><span class="token plain">your-account-id</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Optional: override the token (normally auto-saved from QR login)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># WEIXIN_TOKEN=your-bot-token</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Optional: restrict access</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_DM_POLICY</span><span class="token operator">=</span><span class="token plain">open</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_ALLOWED_USERS</span><span class="token operator">=</span><span class="token plain">user_id_1,user_id_2</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Optional: restore legacy multiline splitting behavior</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># WEIXIN_SPLIT_MULTILINE_MESSAGES=true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Optional: home channel for cron/notifications</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_HOME_CHANNEL</span><span class="token operator">=</span><span class="token plain">chat_id</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_HOME_CHANNEL_NAME</span><span class="token operator">=</span><span class="token plain">Home</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-start-the-gateway">3. Start the Gateway<a href="#3-start-the-gateway" class="hash-link" aria-label="Direct link to 3. Start the Gateway" title="Direct link to 3. Start the Gateway" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">hermes gateway</span><br></div></code></pre></div></div>
<p>The adapter will restore saved credentials, connect to the iLink API, and begin long-polling for messages.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="features">Features<a href="#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h2>
<ul>
<li class=""><strong>Long-poll transport</strong> — no public endpoint, webhook, or WebSocket needed</li>
<li class=""><strong>QR code login</strong> — scan-to-connect setup via <code>hermes gateway setup</code></li>
<li class=""><strong>DM messaging</strong> — configurable access policies; group messaging depends on iLink actually delivering group events for the connected identity (often not the case for iLink bot accounts — see the warning above)</li>
<li class=""><strong>Media support</strong> — images, video, files, and voice messages</li>
<li class=""><strong>AES-128-ECB encrypted CDN</strong> — automatic encryption/decryption for all media transfers</li>
<li class=""><strong>Context token persistence</strong> — disk-backed reply continuity across restarts</li>
<li class=""><strong>Markdown formatting</strong> — preserves Markdown, including headers, tables, and code blocks, so WeChat clients that support Markdown can render it natively</li>
<li class=""><strong>Smart message chunking</strong> — messages stay as a single bubble when under the limit; only oversized payloads split at logical boundaries</li>
<li class=""><strong>Typing indicators</strong> — shows &quot;typing…&quot; status in the WeChat client while the agent processes</li>
<li class=""><strong>SSRF protection</strong> — outbound media URLs are validated before download</li>
<li class=""><strong>Message deduplication</strong> — 5-minute sliding window prevents double-processing</li>
<li class=""><strong>Automatic retry with backoff</strong> — recovers from transient API errors</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configuration-options">Configuration Options<a href="#configuration-options" class="hash-link" aria-label="Direct link to Configuration Options" title="Direct link to Configuration Options" translate="no">​</a></h2>
<p>Set these in <code>config.yaml</code> under <code>platforms.weixin.extra</code>:</p>
<table><thead><tr><th>Key</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>account_id</code></td><td>—</td><td>iLink Bot account ID (required)</td></tr><tr><td><code>token</code></td><td>—</td><td>iLink Bot token (required, auto-saved from QR login)</td></tr><tr><td><code>base_url</code></td><td><code>https://ilinkai.weixin.qq.com</code></td><td>iLink API base URL</td></tr><tr><td><code>cdn_base_url</code></td><td><code>https://novac2c.cdn.weixin.qq.com/c2c</code></td><td>CDN base URL for media transfer</td></tr><tr><td><code>dm_policy</code></td><td><code>open</code></td><td>DM access: <code>open</code>, <code>allowlist</code>, <code>disabled</code>, <code>pairing</code></td></tr><tr><td><code>group_policy</code></td><td><code>disabled</code></td><td>Group access: <code>open</code>, <code>allowlist</code>, <code>disabled</code></td></tr><tr><td><code>allow_from</code></td><td><code>[]</code></td><td>User IDs allowed for DMs (when dm_policy=allowlist)</td></tr><tr><td><code>group_allow_from</code></td><td><code>[]</code></td><td>Group IDs allowed (when group_policy=allowlist)</td></tr><tr><td><code>split_multiline_messages</code></td><td><code>false</code></td><td>When <code>true</code>, split multi-line replies into multiple chat messages (legacy behavior). When <code>false</code>, keep multi-line replies as one message unless they exceed the length limit.</td></tr><tr><td><code>text_batch_delay_seconds</code></td><td><code>3.0</code></td><td>Quiet period (seconds) before a buffered burst of rapid text messages is flushed as one combined request. iLink delivers messages individually, so this debounce avoids one agent invocation per fragment. Set <code>0</code> to dispatch each message immediately.</td></tr><tr><td><code>text_batch_split_delay_seconds</code></td><td><code>5.0</code></td><td>Extended flush delay used when the latest fragment is near the split threshold (long messages iLink may have chunked).</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="access-policies">Access Policies<a href="#access-policies" class="hash-link" aria-label="Direct link to Access Policies" title="Direct link to Access Policies" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="dm-policy">DM Policy<a href="#dm-policy" class="hash-link" aria-label="Direct link to DM Policy" title="Direct link to DM Policy" translate="no">​</a></h3>
<p>Controls who can send direct messages to the bot:</p>
<table><thead><tr><th>Value</th><th>Behavior</th></tr></thead><tbody><tr><td><code>open</code></td><td>Anyone can DM the bot (default)</td></tr><tr><td><code>allowlist</code></td><td>Only user IDs in <code>allow_from</code> can DM</td></tr><tr><td><code>disabled</code></td><td>All DMs are ignored</td></tr><tr><td><code>pairing</code></td><td>Pairing mode (for initial setup)</td></tr></tbody></table>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_DM_POLICY</span><span class="token operator">=</span><span class="token plain">allowlist</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_ALLOWED_USERS</span><span class="token operator">=</span><span class="token plain">user_id_1,user_id_2</span><br></div></code></pre></div></div>
<p><code>WEIXIN_ALLOWED_USERS</code> is an <strong>inbound filter</strong>, not an invitation system. QR
login connects one iLink bot identity to Hermes. Other people do not scan the
Hermes QR code with their own accounts; they must message the connected iLink
bot/contact through WeChat, and Hermes will process the DM only if the sender&#x27;s
Weixin user ID is present in <code>WEIXIN_ALLOWED_USERS</code>.</p>
<p>A practical setup flow is:</p>
<ol>
<li class="">Pair Hermes once with <code>hermes gateway setup</code> and note the connected iLink bot
account.</li>
<li class="">Have each allowed user send a direct message to that bot/contact.</li>
<li class="">Read the sender/user ID from the gateway logs or the inbound event payload.</li>
<li class="">Add those IDs to <code>WEIXIN_ALLOWED_USERS</code>, then restart the gateway.</li>
</ol>
<p>If only the account that scanned the QR code can talk to Hermes, verify that the
other users are messaging the iLink bot identity itself, not the personal WeChat
account that performed the QR login. The iLink bot is a separate identity, and
ordinary WeChat contact/group routing can be limited by Tencent&#x27;s iLink behavior.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="group-policy">Group Policy<a href="#group-policy" class="hash-link" aria-label="Direct link to Group Policy" title="Direct link to Group Policy" translate="no">​</a></h3>
<p>Controls which groups the bot responds in <strong>when iLink delivers group events for the connected identity</strong>. For QR-login iLink bot identities (e.g. <code>...@im.bot</code>), group events are typically not delivered at all, so this policy may have no effect — see the iLink bot limitation warning at the top of the page.</p>
<table><thead><tr><th>Value</th><th>Behavior</th></tr></thead><tbody><tr><td><code>open</code></td><td>Bot responds in all groups (if events are delivered)</td></tr><tr><td><code>allowlist</code></td><td>Bot only responds in group IDs listed in <code>group_allow_from</code> (if events are delivered)</td></tr><tr><td><code>disabled</code></td><td>All group messages are ignored (default)</td></tr></tbody></table>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_GROUP_POLICY</span><span class="token operator">=</span><span class="token plain">allowlist</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># NOTE: this is a comma-separated list of group chat IDs, NOT member user IDs,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># despite the variable name containing &quot;USERS&quot;. Keep this in mind when configuring.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(189, 147, 249);font-style:italic">WEIXIN_GROUP_ALLOWED_USERS</span><span class="token operator">=</span><span class="token plain">group_id_1,group_id_2</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>The default group policy is <code>disabled</code> for Weixin (unlike WeCom where it defaults to <code>open</code>). This is intentional — personal WeChat accounts may be in many groups, and iLink bot identities typically can&#x27;t receive ordinary WeChat group messages at all. The gateway logs a <code>WARNING</code> at startup if you set <code>WEIXIN_GROUP_POLICY</code> to anything other than <code>disabled</code>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="media-support">Media Support<a href="#media-support" class="hash-link" aria-label="Direct link to Media Support" title="Direct link to Media Support" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="inbound-receiving">Inbound (receiving)<a href="#inbound-receiving" class="hash-link" aria-label="Direct link to Inbound (receiving)" title="Direct link to Inbound (receiving)" translate="no">​</a></h3>
<p>The adapter receives media attachments from users, downloads them from the WeChat CDN, decrypts them, and caches them locally for agent processing:</p>
<table><thead><tr><th>Type</th><th>How it&#x27;s handled</th></tr></thead><tbody><tr><td><strong>Images</strong></td><td>Downloaded, AES-decrypted, and cached as JPEG.</td></tr><tr><td><strong>Video</strong></td><td>Downloaded, AES-decrypted, and cached as MP4.</td></tr><tr><td><strong>Files</strong></td><td>Downloaded, AES-decrypted, and cached. Original filename is preserved.</td></tr><tr><td><strong>Voice</strong></td><td>If a text transcription is available, it&#x27;s extracted as text. Otherwise the audio (SILK format) is downloaded and cached.</td></tr></tbody></table>
<p><strong>Quoted messages:</strong> Media from quoted (replied-to) messages is also extracted, so the agent has context about what the user is replying to.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="aes-128-ecb-encrypted-cdn">AES-128-ECB Encrypted CDN<a href="#aes-128-ecb-encrypted-cdn" class="hash-link" aria-label="Direct link to AES-128-ECB Encrypted CDN" title="Direct link to AES-128-ECB Encrypted CDN" translate="no">​</a></h3>
<p>WeChat media files are transferred through an encrypted CDN. The adapter handles this transparently:</p>
<ul>
<li class=""><strong>Inbound:</strong> Encrypted media is downloaded from the CDN using <code>encrypted_query_param</code> URLs, then decrypted with AES-128-ECB using the per-file key provided in the message payload.</li>
<li class=""><strong>Outbound:</strong> Files are encrypted locally with a random AES-128-ECB key, uploaded to the CDN, and the encrypted reference is included in the outbound message.</li>
<li class="">The AES key is 16 bytes (128-bit). Keys may arrive as raw base64 or hex-encoded — the adapter handles both formats.</li>
<li class="">This requires the <code>cryptography</code> Python package.</li>
</ul>
<p>No configuration is needed — encryption and decryption happen automatically.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="outbound-sending">Outbound (sending)<a href="#outbound-sending" class="hash-link" aria-label="Direct link to Outbound (sending)" title="Direct link to Outbound (sending)" translate="no">​</a></h3>
<table><thead><tr><th>Method</th><th>What it sends</th></tr></thead><tbody><tr><td><code>send</code></td><td>Text messages with Markdown formatting</td></tr><tr><td><code>send_image</code> / <code>send_image_file</code></td><td>Native image messages (via CDN upload)</td></tr><tr><td><code>send_document</code></td><td>File attachments (via CDN upload)</td></tr><tr><td><code>send_video</code></td><td>Video messages (via CDN upload)</td></tr></tbody></table>
<p>All outbound media goes through the encrypted CDN upload flow:</p>
<ol>
<li class="">Generate a random AES-128 key</li>
<li class="">Encrypt the file with AES-128-ECB + PKCS#7 padding</li>
<li class="">Request an upload URL from the iLink API (<code>getuploadurl</code>)</li>
<li class="">Upload the ciphertext to the CDN</li>
<li class="">Send the message with the encrypted media reference</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="context-token-persistence">Context Token Persistence<a href="#context-token-persistence" class="hash-link" aria-label="Direct link to Context Token Persistence" title="Direct link to Context Token Persistence" translate="no">​</a></h2>
<p>The iLink Bot API requires a <code>context_token</code> to be echoed back with each outbound message for a given peer. The adapter maintains a disk-backed context token store:</p>
<ul>
<li class="">Tokens are saved per account+peer to <code>~/.hermes/weixin/accounts/&lt;account_id&gt;.context-tokens.json</code></li>
<li class="">On startup, previously saved tokens are restored</li>
<li class="">Every inbound message updates the stored token for that sender</li>
<li class="">Outbound messages automatically include the latest context token</li>
</ul>
<p>This ensures reply continuity even after gateway restarts.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="markdown-formatting">Markdown Formatting<a href="#markdown-formatting" class="hash-link" aria-label="Direct link to Markdown Formatting" title="Direct link to Markdown Formatting" translate="no">​</a></h2>
<p>WeChat clients connected through the iLink Bot API can render Markdown directly, so the adapter preserves Markdown instead of rewriting it:</p>
<ul>
<li class=""><strong>Headers</strong> stay as Markdown headings (<code>#</code>, <code>##</code>, ...)</li>
<li class=""><strong>Tables</strong> stay as Markdown tables</li>
<li class=""><strong>Code fences</strong> stay as fenced code blocks</li>
<li class=""><strong>Excessive blank lines</strong> are collapsed to double newlines outside fenced code blocks</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="message-chunking">Message Chunking<a href="#message-chunking" class="hash-link" aria-label="Direct link to Message Chunking" title="Direct link to Message Chunking" translate="no">​</a></h2>
<p>Messages are delivered as a single chat message whenever they fit within the platform limit. Only oversized payloads are split for delivery:</p>
<ul>
<li class="">Maximum message length: <strong>4000 characters</strong></li>
<li class="">Messages under the limit stay intact even when they contain multiple paragraphs or line breaks</li>
<li class="">Oversized messages split at logical boundaries (paragraphs, blank lines, code fences)</li>
<li class="">Code fences are kept intact whenever possible (never split mid-block unless the fence itself exceeds the limit)</li>
<li class="">Oversized individual blocks fall back to the base adapter&#x27;s truncation logic</li>
<li class="">A 0.3 s inter-chunk delay prevents WeChat rate-limit drops when multiple chunks are sent</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="typing-indicators">Typing Indicators<a href="#typing-indicators" class="hash-link" aria-label="Direct link to Typing Indicators" title="Direct link to Typing Indicators" translate="no">​</a></h2>
<p>The adapter shows typing status in the WeChat client:</p>
<ol>
<li class="">When a message arrives, the adapter fetches a <code>typing_ticket</code> via the <code>getconfig</code> API</li>
<li class="">Typing tickets are cached for 10 minutes per user</li>
<li class=""><code>send_typing</code> sends a typing-start signal; <code>stop_typing</code> sends a typing-stop signal</li>
<li class="">The gateway automatically triggers typing indicators while the agent processes a message</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="long-poll-connection">Long-Poll Connection<a href="#long-poll-connection" class="hash-link" aria-label="Direct link to Long-Poll Connection" title="Direct link to Long-Poll Connection" translate="no">​</a></h2>
<p>The adapter uses HTTP long-polling (not WebSocket) to receive messages:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How It Works<a href="#how-it-works" class="hash-link" aria-label="Direct link to How It Works" title="Direct link to How It Works" translate="no">​</a></h3>
<ol>
<li class=""><strong>Connect:</strong> Validates credentials and starts the poll loop</li>
<li class=""><strong>Poll:</strong> Calls <code>getupdates</code> with a 35-second timeout; the server holds the request until messages arrive or the timeout expires</li>
<li class=""><strong>Dispatch:</strong> Inbound messages are dispatched concurrently via <code>asyncio.create_task</code></li>
<li class=""><strong>Sync buffer:</strong> A persistent sync cursor (<code>get_updates_buf</code>) is saved to disk so the adapter resumes from the correct position after restarts</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="retry-behavior">Retry Behavior<a href="#retry-behavior" class="hash-link" aria-label="Direct link to Retry Behavior" title="Direct link to Retry Behavior" translate="no">​</a></h3>
<p>On API errors, the adapter uses a simple retry strategy:</p>
<table><thead><tr><th>Condition</th><th>Behavior</th></tr></thead><tbody><tr><td>Transient error (1st–2nd)</td><td>Retry after 2 seconds</td></tr><tr><td>Repeated errors (3+)</td><td>Back off for 30 seconds, then reset counter</td></tr><tr><td>Session expired (<code>errcode=-14</code>)</td><td>Pause for 10 minutes (re-login may be needed)</td></tr><tr><td>Timeout</td><td>Immediately re-poll (normal long-poll behavior)</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="deduplication">Deduplication<a href="#deduplication" class="hash-link" aria-label="Direct link to Deduplication" title="Direct link to Deduplication" translate="no">​</a></h3>
<p>Inbound messages are deduplicated using message IDs with a 5-minute window. This prevents double-processing during network hiccups or overlapping poll responses.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="token-lock">Token Lock<a href="#token-lock" class="hash-link" aria-label="Direct link to Token Lock" title="Direct link to Token Lock" translate="no">​</a></h3>
<p>Only one Weixin gateway instance can use a given token at a time. The adapter acquires a scoped lock on startup and releases it on shutdown. If another gateway is already using the same token, startup fails with an informative error message.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="all-environment-variables">All Environment Variables<a href="#all-environment-variables" class="hash-link" aria-label="Direct link to All Environment Variables" title="Direct link to All Environment Variables" translate="no">​</a></h2>
<table><thead><tr><th>Variable</th><th>Required</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>WEIXIN_ACCOUNT_ID</code></td><td>✅</td><td>—</td><td>iLink Bot account ID (from QR login)</td></tr><tr><td><code>WEIXIN_TOKEN</code></td><td>✅</td><td>—</td><td>iLink Bot token (auto-saved from QR login)</td></tr><tr><td><code>WEIXIN_BASE_URL</code></td><td>—</td><td><code>https://ilinkai.weixin.qq.com</code></td><td>iLink API base URL</td></tr><tr><td><code>WEIXIN_CDN_BASE_URL</code></td><td>—</td><td><code>https://novac2c.cdn.weixin.qq.com/c2c</code></td><td>CDN base URL for media transfer</td></tr><tr><td><code>WEIXIN_DM_POLICY</code></td><td>—</td><td><code>open</code></td><td>DM access policy: <code>open</code>, <code>allowlist</code>, <code>disabled</code>, <code>pairing</code></td></tr><tr><td><code>WEIXIN_GROUP_POLICY</code></td><td>—</td><td><code>disabled</code></td><td>Group access policy: <code>open</code>, <code>allowlist</code>, <code>disabled</code></td></tr><tr><td><code>WEIXIN_ALLOWED_USERS</code></td><td>—</td><td><em>(empty)</em></td><td>Comma-separated user IDs for DM allowlist</td></tr><tr><td><code>WEIXIN_GROUP_ALLOWED_USERS</code></td><td>—</td><td><em>(empty)</em></td><td>Comma-separated <strong>group chat IDs</strong> (not member user IDs) for group allowlist. The variable name is legacy — it expects group IDs, not user IDs.</td></tr><tr><td><code>WEIXIN_HOME_CHANNEL</code></td><td>—</td><td>—</td><td>Chat ID for cron/notification output</td></tr><tr><td><code>WEIXIN_HOME_CHANNEL_NAME</code></td><td>—</td><td><code>Home</code></td><td>Display name for the home channel</td></tr><tr><td><code>WEIXIN_ALLOW_ALL_USERS</code></td><td>—</td><td>—</td><td>Gateway-level flag to allow all users (used by setup wizard)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="troubleshooting">Troubleshooting<a href="#troubleshooting" class="hash-link" aria-label="Direct link to Troubleshooting" title="Direct link to Troubleshooting" translate="no">​</a></h2>
<table><thead><tr><th>Problem</th><th>Fix</th></tr></thead><tbody><tr><td><code>Weixin startup failed: aiohttp and cryptography are required</code></td><td>Install both: <code>pip install aiohttp cryptography</code></td></tr><tr><td><code>Weixin startup failed: WEIXIN_TOKEN is required</code></td><td>Run <code>hermes gateway setup</code> to complete QR login, or set <code>WEIXIN_TOKEN</code> manually</td></tr><tr><td><code>Weixin startup failed: WEIXIN_ACCOUNT_ID is required</code></td><td>Set <code>WEIXIN_ACCOUNT_ID</code> in your <code>.env</code> or run <code>hermes gateway setup</code></td></tr><tr><td><code>Another local Hermes gateway is already using this Weixin token</code></td><td>Stop the other gateway instance first — only one poller per token is allowed</td></tr><tr><td>Session expired (<code>errcode=-14</code>)</td><td>Your login session has expired. Re-run <code>hermes gateway setup</code> to scan a new QR code</td></tr><tr><td>QR code expired during setup</td><td>The QR auto-refreshes up to 3 times. If it keeps expiring, check your network connection</td></tr><tr><td>Bot doesn&#x27;t respond to DMs</td><td>Check <code>WEIXIN_DM_POLICY</code> — if set to <code>allowlist</code>, the sender must be in <code>WEIXIN_ALLOWED_USERS</code></td></tr><tr><td>Bot ignores group messages</td><td>Group policy defaults to <code>disabled</code>. Set <code>WEIXIN_GROUP_POLICY=open</code> or <code>allowlist</code> — but note that QR-login iLink bot identities (<code>...@im.bot</code>) typically cannot receive ordinary WeChat group messages at all. If the gateway logs show no raw inbound events for group messages, the limitation is on the iLink side, not in Hermes.</td></tr><tr><td>Media download/upload fails</td><td>Ensure <code>cryptography</code> is installed. Check network access to <code>novac2c.cdn.weixin.qq.com</code></td></tr><tr><td><code>Blocked unsafe URL (SSRF protection)</code></td><td>The outbound media URL points to a private/internal address. Only public URLs are allowed</td></tr><tr><td>Voice messages show as text</td><td>If WeChat provides a transcription, the adapter uses the text. This is expected behavior</td></tr><tr><td>Messages appear duplicated</td><td>The adapter deduplicates by message ID. If you see duplicates, check if multiple gateway instances are running</td></tr><tr><td><code>iLink POST ... HTTP 4xx/5xx</code></td><td>API error from the iLink service. Check your token validity and network connectivity</td></tr><tr><td>Terminal QR code doesn&#x27;t render</td><td>Reinstall with the messaging extra: <code>cd ~/.hermes/hermes-agent &amp;&amp; uv pip install -e &quot;.[messaging]&quot;</code>. Alternatively, open the URL printed above the QR</td></tr></tbody></table></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="row margin-top--sm theme-doc-footer-edit-meta-row"><div class="col noPrint_WFHX"><a href="https://github.com/NousResearch/hermes-agent/edit/main/website/docs/user-guide/messaging/weixin.md" target="_blank" rel="noopener noreferrer" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_JAkA"></div></div></footer></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/docs/user-guide/messaging/wecom-callback"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">WeCom Callback (Self-Built App)</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/docs/user-guide/messaging/qqbot"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">QQ Bot</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#prerequisites" class="table-of-contents__link toc-highlight">Prerequisites</a></li><li><a href="#setup" class="table-of-contents__link toc-highlight">Setup</a><ul><li><a href="#1-run-the-setup-wizard" class="table-of-contents__link toc-highlight">1. Run the Setup Wizard</a></li><li><a href="#2-configure-environment-variables" class="table-of-contents__link toc-highlight">2. Configure Environment Variables</a></li><li><a href="#3-start-the-gateway" class="table-of-contents__link toc-highlight">3. Start the Gateway</a></li></ul></li><li><a href="#features" class="table-of-contents__link toc-highlight">Features</a></li><li><a href="#configuration-options" class="table-of-contents__link toc-highlight">Configuration Options</a></li><li><a href="#access-policies" class="table-of-contents__link toc-highlight">Access Policies</a><ul><li><a href="#dm-policy" class="table-of-contents__link toc-highlight">DM Policy</a></li><li><a href="#group-policy" class="table-of-contents__link toc-highlight">Group Policy</a></li></ul></li><li><a href="#media-support" class="table-of-contents__link toc-highlight">Media Support</a><ul><li><a href="#inbound-receiving" class="table-of-contents__link toc-highlight">Inbound (receiving)</a></li><li><a href="#aes-128-ecb-encrypted-cdn" class="table-of-contents__link toc-highlight">AES-128-ECB Encrypted CDN</a></li><li><a href="#outbound-sending" class="table-of-contents__link toc-highlight">Outbound (sending)</a></li></ul></li><li><a href="#context-token-persistence" class="table-of-contents__link toc-highlight">Context Token Persistence</a></li><li><a href="#markdown-formatting" class="table-of-contents__link toc-highlight">Markdown Formatting</a></li><li><a href="#message-chunking" class="table-of-contents__link toc-highlight">Message Chunking</a></li><li><a href="#typing-indicators" class="table-of-contents__link toc-highlight">Typing Indicators</a></li><li><a href="#long-poll-connection" class="table-of-contents__link toc-highlight">Long-Poll Connection</a><ul><li><a href="#how-it-works" class="table-of-contents__link toc-highlight">How It Works</a></li><li><a href="#retry-behavior" class="table-of-contents__link toc-highlight">Retry Behavior</a></li><li><a href="#deduplication" class="table-of-contents__link toc-highlight">Deduplication</a></li><li><a href="#token-lock" class="table-of-contents__link toc-highlight">Token Lock</a></li></ul></li><li><a href="#all-environment-variables" class="table-of-contents__link toc-highlight">All Environment Variables</a></li><li><a href="#troubleshooting" class="table-of-contents__link toc-highlight">Troubleshooting</a></li></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Docs</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/getting-started/quickstart">Getting Started</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/user-guide/cli">User Guide</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/developer-guide/architecture">Developer Guide</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/reference/cli-commands">Reference</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://discord.gg/NousResearch" target="_blank" rel="noopener noreferrer" class="footer__link-item">Discord<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://github.com/NousResearch/hermes-agent/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub Issues<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://agentskills.io" target="_blank" rel="noopener noreferrer" class="footer__link-item">Skills Hub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">More</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://hermes-agent.nousresearch.com/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Desktop Download<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://github.com/NousResearch/hermes-agent" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://nousresearch.com" target="_blank" rel="noopener noreferrer" class="footer__link-item">Nous Research<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Built by <a href="https://nousresearch.com">Nous Research</a> · MIT License · 2026</div></div></div></footer></div>
</body>
</html>
__HERMES_CWD_220e984c7dca__/opt/docmost__HERMES_CWD_220e984c7dca__
