{"id":279753,"date":"2026-08-13T15:45:25","date_gmt":"2026-08-13T13:45:25","guid":{"rendered":"https:\/\/www.unipile.com\/?p=279753"},"modified":"2026-08-18T10:54:18","modified_gmt":"2026-08-18T08:54:18","slug":"whatsapp-api-python","status":"publish","type":"post","link":"https:\/\/www.unipile.com\/br\/whatsapp-api-python\/","title":{"rendered":"WhatsApp API with Python: Send, Receive and Automate Messages"},"content":{"rendered":"\n[et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;4.27.3&#8243; background_color=&#8221;transparent&#8221; custom_padding=&#8221;0px|0px|0px|0px|false|false&#8221; global_colors_info=&#8221;{}&#8221;]\n[et_pb_row _builder_version=&#8221;4.27.3&#8243; background_color=&#8221;transparent&#8221; custom_padding=&#8221;0px|0px|0px|0px|false|false&#8221; global_colors_info=&#8221;{}&#8221;]\n[et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;4.27.3&#8243; global_colors_info=&#8221;{}&#8221;]\n[et_pb_code _builder_version=&#8221;4.27.3&#8243; global_colors_info=&#8221;{}&#8221;]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#unipile-toc,#unipile-toc *,#unipile-toc *::before,#unipile-toc *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;float:none !important;}#unipile-toc br{display:none !important;}#unipile-toc p{display:contents !important;}#unipile-toc{all:initial !important;display:block !important;max-width:1100px !important;margin:0 auto !important;padding:0 !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;}#unipile-toc .utc-card{background:#ffffff !important;border-radius:16px !important;border:1px solid #e5e7eb !important;padding:32px !important;box-shadow:0 2px 12px rgba(15,39,54,0.04) !important;}#unipile-toc .utc-header{display:flex !important;align-items:center !important;justify-content:space-between !important;gap:12px !important;margin-bottom:24px !important;padding-bottom:20px !important;border-bottom:1px solid #e5e7eb !important;}#unipile-toc .utc-header-left{display:flex !important;align-items:center !important;gap:12px !important;}#unipile-toc .utc-icon-box{width:36px !important;height:36px !important;background:rgba(59,185,139,0.12) !important;border-radius:8px !important;display:flex !important;align-items:center !important;justify-content:center !important;flex-shrink:0 !important;}#unipile-toc .utc-icon-box svg{width:18px !important;height:18px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2.2 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}#unipile-toc .utc-title{font-family:'Poppins',sans-serif !important;font-size:15px !important;font-weight:700 !important;color:#0f2736 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;}#unipile-toc .utc-toggle{display:none !important;align-items:center !important;gap:6px !important;background:transparent !important;cursor:pointer !important;font-size:13px !important;font-weight:600 !important;color:#3BB98B !important;padding:6px 10px !important;border-radius:6px !important;transition:background 0.2s ease !important;}#unipile-toc .utc-toggle svg{width:14px !important;height:14px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;transition:transform 0.3s ease !important;}#unipile-toc.utc-collapsed .utc-toggle svg{transform:rotate(-90deg) !important;}#unipile-toc .utc-grid{display:grid !important;grid-template-columns:repeat(4,1fr) !important;gap:0 !important;}#unipile-toc .utc-col{padding:0 24px !important;border-left:1px solid #e5e7eb !important;}#unipile-toc .utc-col:first-child{padding-left:0 !important;border-left:none !important;}#unipile-toc .utc-col:last-child{padding-right:0 !important;}#unipile-toc .utc-col-label{font-size:11px !important;font-weight:700 !important;color:#94a3b8 !important;text-transform:uppercase !important;letter-spacing:0.8px !important;margin-bottom:14px !important;display:block !important;}#unipile-toc .utc-link-list{display:flex !important;flex-direction:column !important;gap:10px !important;}#unipile-toc .utc-link{display:flex !important;align-items:flex-start !important;gap:10px !important;cursor:pointer !important;transition:all 0.2s ease !important;text-decoration:none !important;padding:4px 0 !important;}#unipile-toc .utc-num{width:18px !important;height:18px !important;flex-shrink:0 !important;background:#f4f5f7 !important;border-radius:4px !important;display:flex !important;align-items:center !important;justify-content:center !important;font-size:10px !important;font-weight:700 !important;color:#94a3b8 !important;transition:all 0.2s ease !important;margin-top:1px !important;}#unipile-toc .utc-num.utc-num-faq{font-size:8px !important;letter-spacing:0.2px !important;}#unipile-toc .utc-link-text{font-size:13px !important;font-weight:500 !important;color:#383838 !important;line-height:1.45 !important;transition:color 0.2s ease !important;flex:1 !important;}#unipile-toc .utc-link:hover .utc-num{background:rgba(59,185,139,0.15) !important;color:#3BB98B !important;}#unipile-toc .utc-link:hover .utc-link-text{color:#0f2736 !important;}#unipile-toc .utc-link.utc-active .utc-num{background:#3BB98B !important;color:#ffffff !important;}#unipile-toc .utc-link.utc-active .utc-link-text{color:#0f2736 !important;font-weight:600 !important;}#unipile-toc .utc-link.utc-read .utc-num{background:rgba(59,185,139,0.15) !important;color:#3BB98B !important;}#unipile-toc .utc-tag-best{display:inline-block !important;font-size:9px !important;font-weight:700 !important;color:#ffffff !important;background:#3BB98B !important;padding:2px 6px !important;border-radius:4px !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-left:6px !important;vertical-align:middle !important;}@media (max-width:1000px){#unipile-toc .utc-grid{grid-template-columns:repeat(2,1fr) !important;gap:24px 0 !important;}#unipile-toc .utc-col{padding:0 20px !important;}#unipile-toc .utc-col:nth-child(2n+1){padding-left:0 !important;border-left:none !important;}#unipile-toc .utc-col:nth-child(2n){padding-right:0 !important;}}@media (max-width:700px){#unipile-toc .utc-card{padding:22px !important;}#unipile-toc .utc-header{margin-bottom:0 !important;padding-bottom:0 !important;border-bottom:none !important;}#unipile-toc .utc-toggle{display:flex !important;}#unipile-toc .utc-grid{grid-template-columns:1fr !important;gap:22px !important;max-height:2000px !important;overflow:hidden !important;transition:max-height 0.4s ease,margin-top 0.3s ease,padding-top 0.3s ease !important;margin-top:22px !important;padding-top:22px !important;border-top:1px solid #e5e7eb !important;}#unipile-toc.utc-collapsed .utc-grid{max-height:0 !important;margin-top:0 !important;padding-top:0 !important;border-top:none !important;}#unipile-toc .utc-col{padding:0 !important;border-left:none !important;border-top:1px solid #e5e7eb !important;padding-top:18px !important;}#unipile-toc .utc-col:first-child{border-top:none !important;padding-top:0 !important;}}<\/style>\n\n<div id=\"unipile-toc\">\n  <div class=\"utc-card\">\n    <div class=\"utc-header\">\n      <div class=\"utc-header-left\">\n        <div class=\"utc-icon-box\">\n          <svg viewBox=\"0 0 24 24\">\n            <line x1=\"8\" y1=\"6\" x2=\"21\" y2=\"6\"\/>\n            <line x1=\"8\" y1=\"12\" x2=\"21\" y2=\"12\"\/>\n            <line x1=\"8\" y1=\"18\" x2=\"21\" y2=\"18\"\/>\n            <line x1=\"3\" y1=\"6\" x2=\"3.01\" y2=\"6\"\/>\n            <line x1=\"3\" y1=\"12\" x2=\"3.01\" y2=\"12\"\/>\n            <line x1=\"3\" y1=\"18\" x2=\"3.01\" y2=\"18\"\/>\n          <\/svg>\n        <\/div>\n        <span class=\"utc-title\">Table of Contents<\/span>\n      <\/div>\n      <button type=\"button\" class=\"utc-toggle\" aria-label=\"Toggle table of contents\">\n        <span class=\"utc-toggle-label\">Hide<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"6 9 12 15 18 9\"\/><\/svg>\n      <\/button>\n    <\/div>\n\n    <div class=\"utc-grid\">\n      <div class=\"utc-col\">\n        <span class=\"utc-col-label\">Getting Started<\/span>\n        <div class=\"utc-link-list\">\n          <a class=\"utc-link\" href=\"#wpy-what\">\n            <span class=\"utc-num\">01<\/span>\n            <span class=\"utc-link-text\">What is the WhatsApp API in Python?<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-libs\">\n            <span class=\"utc-num\">02<\/span>\n            <span class=\"utc-link-text\">Which Python library should you use?<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-prereq\">\n            <span class=\"utc-num\">03<\/span>\n            <span class=\"utc-link-text\">What do you need before you start?<\/span>\n          <\/a>\n        <\/div>\n      <\/div>\n\n      <div class=\"utc-col\">\n        <span class=\"utc-col-label\">Connect &amp; Send<\/span>\n        <div class=\"utc-link-list\">\n          <a class=\"utc-link\" href=\"#wpy-connect\">\n            <span class=\"utc-num\">04<\/span>\n            <span class=\"utc-link-text\">Connect a WhatsApp account in Python<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-send\">\n            <span class=\"utc-num\">05<\/span>\n            <span class=\"utc-link-text\">Send a WhatsApp message with Python<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-async\">\n            <span class=\"utc-num\">06<\/span>\n            <span class=\"utc-link-text\">Send messages asynchronously with httpx<\/span>\n          <\/a>\n        <\/div>\n      <\/div>\n\n      <div class=\"utc-col\">\n        <span class=\"utc-col-label\">Receive &amp; Automate<\/span>\n        <div class=\"utc-link-list\">\n          <a class=\"utc-link\" href=\"#wpy-webhook\">\n            <span class=\"utc-num\">07<\/span>\n            <span class=\"utc-link-text\">Receive messages with a FastAPI webhook<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-history\">\n            <span class=\"utc-num\">08<\/span>\n            <span class=\"utc-link-text\">Retrieve chats and message history<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-agent\">\n            <span class=\"utc-num\">09<\/span>\n            <span class=\"utc-link-text\">Build a WhatsApp bot or AI agent<\/span>\n          <\/a>\n        <\/div>\n      <\/div>\n\n      <div class=\"utc-col\">\n        <span class=\"utc-col-label\">Go Further<\/span>\n        <div class=\"utc-link-list\">\n          <a class=\"utc-link\" href=\"#wpy-retry\">\n            <span class=\"utc-num\">10<\/span>\n            <span class=\"utc-link-text\">Handle rate limits and retries<\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#wpy-sdk\">\n            <span class=\"utc-num\">11<\/span>\n            <span class=\"utc-link-text\">Official Unipile Python SDK<span class=\"utc-tag-best\">Best<\/span><\/span>\n          <\/a>\n          <a class=\"utc-link\" href=\"#faq-wpy\">\n            <span class=\"utc-num utc-num-faq\">FAQ<\/span>\n            <span class=\"utc-link-text\">Frequently Asked Questions<\/span>\n          <\/a>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  var toc = document.getElementById('unipile-toc');\n  if (!toc) return;\n\n  var toggleBtn = toc.querySelector('.utc-toggle');\n  var toggleLabel = toc.querySelector('.utc-toggle-label');\n  if (toggleBtn) {\n    toggleBtn.addEventListener('click', function(){\n      var isCollapsed = toc.classList.toggle('utc-collapsed');\n      if (toggleLabel) toggleLabel.textContent = isCollapsed ? 'Show' : 'Hide';\n    });\n    if (window.innerWidth <= 700) {\n      toc.classList.add('utc-collapsed');\n      if (toggleLabel) toggleLabel.textContent = 'Show';\n    }\n  }\n\n  var links = toc.querySelectorAll('.utc-link');\n  links.forEach(function(link){\n    link.addEventListener('click', function(e){\n      var href = link.getAttribute('href');\n      if (!href || href.charAt(0) !== '#') return;\n      var target = document.getElementById(href.substring(1));\n      if (target) {\n        e.preventDefault();\n        var offset = 80;\n        var top = target.getBoundingClientRect().top + window.pageYOffset - offset;\n        window.scrollTo({ top: top, behavior: 'smooth' });\n      }\n    });\n  });\n\n  var sectionIds = [];\n  links.forEach(function(link){\n    var href = link.getAttribute('href');\n    if (href &#038;&#038; href.charAt(0) === '#') sectionIds.push(href.substring(1));\n  });\n\n  function updateActive(){\n    var scrollY = window.pageYOffset + 120;\n    var activeId = null;\n    var readIds = [];\n    sectionIds.forEach(function(id){\n      var el = document.getElementById(id);\n      if (el) {\n        var top = el.getBoundingClientRect().top + window.pageYOffset;\n        if (top <= scrollY) {\n          activeId = id;\n          readIds.push(id);\n        }\n      }\n    });\n    links.forEach(function(link){\n      var href = link.getAttribute('href');\n      var id = href ? href.substring(1) : '';\n      link.classList.remove('utc-active', 'utc-read');\n      if (id === activeId) {\n        link.classList.add('utc-active');\n      } else if (readIds.indexOf(id) !== -1) {\n        link.classList.add('utc-read');\n      }\n    });\n  }\n\n  if ('IntersectionObserver' in window) {\n    var observer = new IntersectionObserver(function(){\n      updateActive();\n    }, { rootMargin: '-120px 0px -60% 0px' });\n    sectionIds.forEach(function(id){\n      var el = document.getElementById(id);\n      if (el) observer.observe(el);\n    });\n  }\n  window.addEventListener('scroll', updateActive, { passive: true });\n  updateActive();\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-hero,#upl-wpy-hero *,#upl-wpy-hero *::before,#upl-wpy-hero *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-hero br{display:none !important;}#upl-wpy-hero p{display:contents !important;}#upl-wpy-hero{display:block !important;background:#0f2736 !important;border-radius:20px !important;padding:64px 56px !important;max-width:min(1160px,100vw) !important;width:100% !important;margin:0 auto !important;overflow-x:hidden !important;overflow-y:visible !important;position:relative !important;}#upl-wpy-hero .wph-grid{display:grid !important;grid-template-columns:1.05fr 0.95fr !important;gap:56px !important;align-items:center !important;position:relative !important;z-index:2 !important;}#upl-wpy-hero .wph-badge{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.14) !important;padding:7px 14px !important;border-radius:20px !important;margin-bottom:22px !important;width:fit-content !important;}#upl-wpy-hero .wph-badge .wph-dot{width:7px !important;height:7px !important;background:#3BB98B !important;border-radius:50% !important;flex-shrink:0 !important;}#upl-wpy-hero .wph-badge img{width:16px !important;height:16px !important;display:block !important;flex-shrink:0 !important;}#upl-wpy-hero .wph-badge span{font-size:12px !important;font-weight:700 !important;color:#6fe3ba !important;text-transform:uppercase !important;letter-spacing:0.6px !important;}#upl-wpy-hero h1{font-family:'Poppins',sans-serif !important;font-size:44px !important;font-weight:700 !important;line-height:1.18 !important;color:#ffffff !important;margin-bottom:20px !important;}#upl-wpy-hero h1 .wph-accent{color:#3BB98B !important;}#upl-wpy-hero .wph-desc{font-size:17px !important;line-height:1.75 !important;color:rgba(255,255,255,0.82) !important;margin-bottom:32px !important;max-width:540px !important;}#upl-wpy-hero .wph-desc code{font-family:'SF Mono',Monaco,monospace !important;background:rgba(255,255,255,0.1) !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#a5d6ff !important;}#upl-wpy-hero .wph-actions{display:flex !important;align-items:center !important;gap:14px !important;flex-wrap:wrap !important;margin-bottom:26px !important;}#upl-wpy-hero .wph-cta-primary{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:14px 26px !important;border-radius:8px !important;font-size:0.95rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;white-space:nowrap !important;}#upl-wpy-hero .wph-cta-primary:hover{transform:translateY(-5px) !important;}#upl-wpy-hero .wph-cta-primary svg{width:16px !important;height:16px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}#upl-wpy-hero .wph-cta-secondary{display:inline-flex !important;align-items:center !important;gap:8px !important;background:transparent !important;color:#ffffff !important;padding:12px 24px !important;border-radius:8px !important;border:2px solid rgba(255,255,255,0.28) !important;font-size:0.95rem !important;font-weight:600 !important;transition:all 0.3s ease !important;cursor:pointer !important;white-space:nowrap !important;}#upl-wpy-hero .wph-cta-secondary:hover{transform:translateY(-5px) !important;border-color:#3BB98B !important;}#upl-wpy-hero .wph-note{display:flex !important;align-items:center !important;gap:8px !important;font-size:0.85rem !important;color:rgba(255,255,255,0.6) !important;}#upl-wpy-hero .wph-note svg{width:16px !important;height:16px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2 !important;stroke-linecap:round !important;stroke-linejoin:round !important;flex-shrink:0 !important;}#upl-wpy-hero .wph-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;border:1px solid rgba(255,255,255,0.08) !important;}#upl-wpy-hero .wph-editor-bar{background:#161b22 !important;padding:12px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-hero .wph-dot2{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-hero .wph-dot-r{background:#ff5f57 !important;}#upl-wpy-hero .wph-dot-y{background:#febc2e !important;}#upl-wpy-hero .wph-dot-g{background:#28c840 !important;}#upl-wpy-hero .wph-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-hero .wph-pre{padding:22px 22px !important;font-size:12.8px !important;line-height:1.75 !important;overflow-x:auto !important;background:#0d1117 !important;}#upl-wpy-hero .wph-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-hero .wph-pre .wph-c{color:#8b949e !important;}#upl-wpy-hero .wph-ok{background:rgba(59,185,139,0.12) !important;border-top:1px solid rgba(59,185,139,0.25) !important;color:#6fe3ba !important;padding:11px 22px !important;font-size:12px !important;font-family:'SF Mono',Monaco,monospace !important;display:flex !important;align-items:center !important;gap:8px !important;}#upl-wpy-hero .wph-ok svg{width:13px !important;height:13px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2.5 !important;flex-shrink:0 !important;}@media (max-width:900px){#upl-wpy-hero{padding:48px 28px !important;border-radius:0 !important;}#upl-wpy-hero .wph-grid{grid-template-columns:1fr !important;gap:36px !important;}#upl-wpy-hero h1{font-size:34px !important;}#upl-wpy-hero .wph-desc{max-width:100% !important;}}@media (max-width:600px){#upl-wpy-hero{padding:40px 18px !important;}#upl-wpy-hero h1{font-size:28px !important;}#upl-wpy-hero .wph-desc{font-size:15.5px !important;}#upl-wpy-hero .wph-actions{flex-direction:column !important;align-items:stretch !important;width:100% !important;}#upl-wpy-hero .wph-cta-primary,#upl-wpy-hero .wph-cta-secondary{justify-content:center !important;width:100% !important;}#upl-wpy-hero .wph-pre{font-size:11.5px !important;padding:16px !important;}}@media (max-width:400px){#upl-wpy-hero h1{font-size:25px !important;}}<\/style>\n\n<div id=\"upl-wpy-hero\">\n  <div class=\"wph-grid\">\n    <div class=\"wph-content\">\n      <div class=\"wph-badge\"><img decoding=\"async\" src=\"https:\/\/www.unipile.com\/wp-content\/uploads\/2025\/09\/whatsapp-1.svg\" alt=\"WhatsApp API in Python\" width=\"16\" height=\"16\"><span>Python + WhatsApp API<\/span><\/div>\n      <h1>WhatsApp API with <span class=\"wph-accent\">Python<\/span>: Send, Receive and Automate Messages<\/h1>\n      <div class=\"wph-desc\">Everything you need to use the <strong>WhatsApp API in Python<\/strong>: which library to pick, how to connect a linked account with a QR code, how to send and receive messages with <code>requests<\/code> and <code>httpx<\/code>, and how to wire a FastAPI webhook for a bot or an AI agent.<\/div>\n      <div class=\"wph-actions\">\n        <a class=\"wph-cta-primary\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n          <span>Build with Python<\/span>\n          <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n        <\/a>\n        <a class=\"wph-cta-secondary\" data-upl-link=\"https:\/\/developer.unipile.com\/docs\/getting-started\" data-upl-target=\"_blank\" href=\"https:\/\/developer.unipile.com\/docs\/getting-started\">\n          <span>View the API reference<\/span>\n        <\/a>\n      <\/div>\n      <div class=\"wph-note\">\n        <svg viewBox=\"0 0 24 24\"><path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"\/><polyline points=\"22 4 12 14.01 9 11.01\"\/><\/svg>\n        <span>REST API today, no Meta Business verification needed<\/span>\n      <\/div>\n    <\/div>\n    <div class=\"wph-visual\">\n      <div class=\"wph-code-wrapper\">\n        <div class=\"wph-editor-bar\">\n          <span class=\"wph-dot2 wph-dot-r\"><\/span><span class=\"wph-dot2 wph-dot-y\"><\/span><span class=\"wph-dot2 wph-dot-g\"><\/span>\n          <span class=\"wph-filename\">send_whatsapp.py<\/span>\n        <\/div>\n        <div class=\"wph-pre\"><code class=\"wph-code-hero\">import requests&#10;&#10;BASE_URL = \"https:\/\/{YOUR_DSN}\/api\/v1\"&#10;HEADERS = {\"X-API-KEY\": \"YOUR_ACCESS_TOKEN\"}&#10;&#10;def send_whatsapp(chat_id: str, text: str) -&gt; dict:&#10;    response = requests.post(&#10;        f\"{BASE_URL}\/chats\/{chat_id}\/messages\",&#10;        headers=HEADERS,&#10;        data={\"text\": text},&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()&#10;&#10;send_whatsapp(\"9f9uio56sopa456s\", \"Hello from Python!\")<\/code><\/div>\n        <div class=\"wph-ok\"><svg viewBox=\"0 0 24 24\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg><span>200 OK, message sent<\/span><\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-hero');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-orient,#upl-wpy-orient *,#upl-wpy-orient *::before,#upl-wpy-orient *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-orient br{display:none !important;}#upl-wpy-orient p{display:contents !important;}#upl-wpy-orient{display:block !important;background:transparent !important;padding:70px 20px 40px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-orient .wor-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-orient .wor-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-orient h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-orient .wor-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:28px !important;display:block !important;width:100% !important;}#upl-wpy-orient .wor-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-orient .wor-lede code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-orient .wor-chips{display:grid !important;grid-template-columns:repeat(3,1fr) !important;gap:14px !important;margin-bottom:32px !important;}#upl-wpy-orient .wor-chip{display:flex !important;align-items:flex-start !important;gap:12px !important;padding:18px !important;background:#f8fafc !important;border-radius:12px !important;border:1px solid #e5e7eb !important;}#upl-wpy-orient .wor-chip-icon{width:32px !important;height:32px !important;min-width:32px !important;background:rgba(59,185,139,0.12) !important;border-radius:8px !important;display:flex !important;align-items:center !important;justify-content:center !important;}#upl-wpy-orient .wor-chip-icon svg{width:16px !important;height:16px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}#upl-wpy-orient .wor-chip-text{font-size:0.85rem !important;line-height:1.5 !important;color:#1e293b !important;font-weight:500 !important;padding-top:4px !important;}#upl-wpy-orient .wor-aside{display:flex !important;align-items:center !important;justify-content:space-between !important;gap:16px !important;flex-wrap:wrap !important;background:#f4f5f7 !important;border-radius:12px !important;border:1px solid #e5e7eb !important;padding:18px 24px !important;margin-bottom:46px !important;}#upl-wpy-orient .wor-aside-text{display:flex !important;align-items:center !important;gap:12px !important;font-size:0.92rem !important;color:#383838 !important;}#upl-wpy-orient .wor-aside-text svg{width:20px !important;height:20px !important;stroke:#64748b !important;fill:none !important;stroke-width:2 !important;flex-shrink:0 !important;}#upl-wpy-orient .wor-aside-link{display:inline-flex !important;align-items:center !important;gap:6px !important;font-size:0.88rem !important;font-weight:600 !important;color:#0f2736 !important;text-decoration:underline !important;white-space:nowrap !important;}#upl-wpy-orient .wor-aside-link svg{width:14px !important;height:14px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;}#upl-wpy-orient .wor-sub{margin-top:8px !important;}#upl-wpy-orient .wor-cards{display:grid !important;grid-template-columns:repeat(4,1fr) !important;gap:16px !important;margin-bottom:34px !important;margin-top:26px !important;}#upl-wpy-orient .wor-card{padding:22px 18px !important;background:#ffffff !important;border-radius:12px !important;border:1px solid #e5e7eb !important;transition:all 0.3s ease !important;}#upl-wpy-orient .wor-card:hover{border-color:#3BB98B !important;box-shadow:0 4px 16px rgba(59,185,139,0.1) !important;}#upl-wpy-orient .wor-card-icon{width:36px !important;height:36px !important;background:rgba(221,223,76,0.18) !important;border-radius:8px !important;display:flex !important;align-items:center !important;justify-content:center !important;margin-bottom:14px !important;}#upl-wpy-orient .wor-card-icon svg{width:18px !important;height:18px !important;stroke:#8a8c2e !important;fill:none !important;stroke-width:2 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}#upl-wpy-orient .wor-card-title{font-size:0.95rem !important;font-weight:700 !important;color:#0f2736 !important;margin-bottom:6px !important;line-height:1.4 !important;}#upl-wpy-orient .wor-card-desc{font-size:0.82rem !important;color:#64748b !important;line-height:1.55 !important;}#upl-wpy-orient .wor-card-desc code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:1px 5px !important;border-radius:3px !important;font-size:0.92em !important;color:#0f2736 !important;}#upl-wpy-orient .wor-card-desc a{color:#0f2736 !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-orient .wor-cta-row{display:flex !important;align-items:center !important;gap:16px !important;margin-top:12px !important;}#upl-wpy-orient .wor-cta{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:13px 24px !important;border-radius:8px !important;font-size:0.9rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;}#upl-wpy-orient .wor-cta:hover{transform:translateY(-5px) !important;}#upl-wpy-orient .wor-cta svg{width:15px !important;height:15px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}@media (max-width:900px){#upl-wpy-orient h2{font-size:28px !important;}#upl-wpy-orient .wor-chips{grid-template-columns:1fr !important;}#upl-wpy-orient .wor-cards{grid-template-columns:repeat(2,1fr) !important;}}@media (max-width:600px){#upl-wpy-orient{padding:50px 16px 30px !important;}#upl-wpy-orient h2{font-size:26px !important;}#upl-wpy-orient .wor-lede{font-size:15.5px !important;}#upl-wpy-orient .wor-aside{flex-direction:column !important;align-items:flex-start !important;}#upl-wpy-orient .wor-cards{grid-template-columns:1fr !important;}#upl-wpy-orient .wor-cta-row{width:100% !important;}#upl-wpy-orient .wor-cta{width:100% !important;justify-content:center !important;}}<\/style>\n\n<div id=\"upl-wpy-orient\">\n  <div class=\"wor-container\">\n    <span id=\"wpy-what\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wor-eyebrow\">Definition<\/div>\n    <h2>What is the WhatsApp API in Python?<\/h2>\n    <div class=\"wor-lede\">The <strong>WhatsApp API in Python<\/strong> means calling WhatsApp Business messaging from Python code instead of clicking through WhatsApp Web. A Python script or backend service sends an HTTP request, usually with <code>requests<\/code> or <code>httpx<\/code>, to a REST API that exposes chats, messages and webhooks, either Meta's Cloud API directly or a unified provider like Unipile that connects WhatsApp alongside LinkedIn, Instagram and Telegram behind one interface. Meta does not publish an official all-in-one WhatsApp Python SDK, which is why almost every Python integration in this guide, and most of what you will find on the rest of the web, talks to the REST endpoints directly.<\/div>\n\n    <div class=\"wor-chips\">\n      <div class=\"wor-chip\">\n        <div class=\"wor-chip-icon\"><svg viewBox=\"0 0 24 24\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/><\/svg><\/div>\n        <div class=\"wor-chip-text\"><span>One REST API for WhatsApp, LinkedIn, Instagram and Telegram<\/span><\/div>\n      <\/div>\n      <div class=\"wor-chip\">\n        <div class=\"wor-chip-icon\"><svg viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"\/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"\/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"\/><line x1=\"14\" y1=\"14\" x2=\"14\" y2=\"21\"\/><line x1=\"21\" y1=\"14\" x2=\"21\" y2=\"21\"\/><\/svg><\/div>\n        <div class=\"wor-chip-text\"><span>Linked with a QR code or a pairing code, no Meta Business verification<\/span><\/div>\n      <\/div>\n      <div class=\"wor-chip\">\n        <div class=\"wor-chip-icon\"><svg viewBox=\"0 0 24 24\"><polyline points=\"16 18 22 12 16 6\"\/><polyline points=\"8 6 2 12 8 18\"\/><\/svg><\/div>\n        <div class=\"wor-chip-text\"><span><code>requests<\/code> for simple scripts, <code>httpx<\/code> for async at scale<\/span><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"wor-aside\">\n      <div class=\"wor-aside-text\">\n        <svg viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"\/><line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"\/><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"\/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"\/><\/svg>\n        <span>For the orientation layer, access, cost and limits, start with the <a href=\"https:\/\/www.unipile.com\/whatsapp-api-a-complete-guide-to-integration\/\" style=\"color:#0f2736;text-decoration:underline;font-weight:600;\">WhatsApp API access, cost and limits guide<\/a>. Building in PHP instead of Python?<\/span>\n      <\/div>\n      <a class=\"wor-aside-link\" href=\"https:\/\/www.unipile.com\/whatsapp-api-php\/\">\n        <span>Read the same integration in PHP<\/span>\n        <svg viewBox=\"0 0 24 24\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><polyline points=\"12 5 19 12 12 19\"\/><\/svg>\n      <\/a>\n    <\/div>\n\n    <span id=\"wpy-prereq\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wor-eyebrow wor-sub\">Before you build<\/div>\n    <h2>What do you need before you start?<\/h2>\n    <div class=\"wor-lede\">You do not need a Meta Business account or a WhatsApp Business Platform approval to start sending and receiving messages from Python. You need a working Python environment, an HTTP client, a place to receive webhooks, and a Unipile account.<\/div>\n\n    <div class=\"wor-cards\">\n      <div class=\"wor-card\">\n        <div class=\"wor-card-icon\"><svg viewBox=\"0 0 24 24\"><polyline points=\"16 18 22 12 16 6\"\/><polyline points=\"8 6 2 12 8 18\"\/><\/svg><\/div>\n        <div class=\"wor-card-title\">Python 3.9+<\/div>\n        <div class=\"wor-card-desc\">Matches the minimum version required by the Unipile Python SDK's own <code>pydantic<\/code> dependency, and by modern <code>httpx<\/code> and FastAPI releases.<\/div>\n      <\/div>\n      <div class=\"wor-card\">\n        <div class=\"wor-card-icon\"><svg viewBox=\"0 0 24 24\"><path d=\"M4 17l6-6-6-6\"\/><path d=\"M12 19h8\"\/><\/svg><\/div>\n        <div class=\"wor-card-title\">requests or httpx<\/div>\n        <div class=\"wor-card-desc\"><code>pip install requests<\/code> for synchronous calls, or <code>pip install httpx<\/code> if you plan to send messages concurrently. See the <a href=\"https:\/\/docs.python-requests.org\" target=\"_blank\" rel=\"noopener\" style=\"color:#0f2736;text-decoration:underline;\">requests<\/a> and <a href=\"https:\/\/www.python-httpx.org\" target=\"_blank\" rel=\"noopener\" style=\"color:#0f2736;text-decoration:underline;\">httpx<\/a> documentation.<\/div>\n      <\/div>\n      <div class=\"wor-card\">\n        <div class=\"wor-card-icon\"><svg viewBox=\"0 0 24 24\"><path d=\"M4 4h16v16H4z\"\/><path d=\"M4 9h16\"\/><path d=\"M9 4v16\"\/><\/svg><\/div>\n        <div class=\"wor-card-title\">A local tunnel<\/div>\n        <div class=\"wor-card-desc\">A tool like <code>ngrok<\/code> or <code>cloudflared<\/code> to expose your FastAPI webhook route on a public HTTPS URL while you develop.<\/div>\n      <\/div>\n      <div class=\"wor-card\">\n        <div class=\"wor-card-icon\"><svg viewBox=\"0 0 24 24\"><path d=\"M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z\"\/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"\/><\/svg><\/div>\n        <div class=\"wor-card-title\">Access Token and DSN<\/div>\n        <div class=\"wor-card-desc\">Both come from the Unipile dashboard. The DSN is the host you call, the Access Token goes in the <code>X-API-KEY<\/code> header of every request.<\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"wor-cta-row\">\n      <a class=\"wor-cta\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n        <span>Build your first WhatsApp integration<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n      <\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-orient');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-libs,#upl-wpy-libs *,#upl-wpy-libs *::before,#upl-wpy-libs *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-libs br{display:none !important;}#upl-wpy-libs p{display:contents !important;}#upl-wpy-libs{display:block !important;background:transparent !important;padding:40px 20px 70px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-libs .wlb-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-libs .wlb-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(221,223,76,0.18) !important;color:#8a8c2e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-libs h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-libs .wlb-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:34px !important;display:block !important;width:100% !important;}#upl-wpy-libs .wlb-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-libs .wlb-lede code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-libs .wlb-table{display:block !important;background:#ffffff !important;border-radius:16px !important;border:1px solid #e5e7eb !important;overflow:hidden !important;}#upl-wpy-libs .wlb-row{display:grid !important;grid-template-columns:1.3fr 1.5fr 1.1fr 0.9fr 1.5fr !important;}#upl-wpy-libs .wlb-row + .wlb-row{border-top:1px solid #e5e7eb !important;}#upl-wpy-libs .wlb-head{background:#0f2736 !important;}#upl-wpy-libs .wlb-head .wlb-cell{color:rgba(255,255,255,0.92) !important;font-weight:700 !important;font-size:0.76rem !important;text-transform:uppercase !important;letter-spacing:0.4px !important;}#upl-wpy-libs .wlb-cell{padding:16px 18px !important;font-size:0.83rem !important;line-height:1.5 !important;color:#1e293b !important;display:flex !important;align-items:center !important;}#upl-wpy-libs .wlb-row.wlb-highlight{background:rgba(59,185,139,0.05) !important;}#upl-wpy-libs .wlb-row.wlb-highlight .wlb-cell:first-child{color:#0f2736 !important;font-weight:700 !important;}#upl-wpy-libs .wlb-cell:first-child{font-weight:600 !important;color:#0f2736 !important;font-family:'SF Mono',Monaco,monospace !important;font-size:0.8rem !important;}#upl-wpy-libs .wlb-tag{display:inline-flex !important;align-items:center !important;gap:5px !important;padding:3px 9px !important;border-radius:20px !important;font-size:0.72rem !important;font-weight:600 !important;}#upl-wpy-libs .wlb-tag.wlb-no{background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;}#upl-wpy-libs .wlb-tag.wlb-yes{background:rgba(239,68,68,0.1) !important;color:#dc2626 !important;}#upl-wpy-libs .wlb-tag.wlb-na{background:#f1f5f9 !important;color:#64748b !important;}#upl-wpy-libs .wlb-cards{display:none !important;}#upl-wpy-libs .wlb-foot{font-size:15px !important;line-height:1.75 !important;color:#64748b !important;margin-top:22px !important;}#upl-wpy-libs .wlb-foot a{color:#0f2736 !important;text-decoration:underline !important;}@media (max-width:900px){#upl-wpy-libs h2{font-size:28px !important;}#upl-wpy-libs .wlb-table{display:none !important;}#upl-wpy-libs .wlb-cards{display:flex !important;flex-direction:column !important;gap:14px !important;}#upl-wpy-libs .wlb-card{background:#ffffff !important;border:1px solid #e5e7eb !important;border-radius:14px !important;padding:20px !important;}#upl-wpy-libs .wlb-card.wlb-highlight{border-color:#3BB98B !important;background:rgba(59,185,139,0.04) !important;}#upl-wpy-libs .wlb-card-title{font-family:'SF Mono',Monaco,monospace !important;font-size:0.95rem !important;font-weight:700 !important;color:#0f2736 !important;margin-bottom:14px !important;padding-bottom:12px !important;border-bottom:1px solid #e5e7eb !important;}#upl-wpy-libs .wlb-card-row{display:flex !important;justify-content:space-between !important;align-items:flex-start !important;gap:12px !important;padding:7px 0 !important;}#upl-wpy-libs .wlb-card-label{font-size:0.7rem !important;font-weight:700 !important;color:#94a3b8 !important;text-transform:uppercase !important;letter-spacing:0.4px !important;white-space:nowrap !important;padding-top:2px !important;}#upl-wpy-libs .wlb-card-value{font-size:0.83rem !important;color:#1e293b !important;text-align:right !important;line-height:1.5 !important;}}@media (max-width:600px){#upl-wpy-libs{padding:30px 16px 50px !important;}#upl-wpy-libs h2{font-size:26px !important;}#upl-wpy-libs .wlb-lede{font-size:15.5px !important;}#upl-wpy-libs .wlb-card-row{flex-direction:column !important;gap:4px !important;}#upl-wpy-libs .wlb-card-value{text-align:left !important;}}<\/style>\n\n<div id=\"upl-wpy-libs\">\n  <div class=\"wlb-container\">\n    <span id=\"wpy-libs\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wlb-eyebrow\">Library Comparison<\/div>\n    <h2>Which Python library should you use for WhatsApp?<\/h2>\n    <div class=\"wlb-lede\">There is no single, obvious answer, and most blog posts on this topic push whichever package their author maintains. Here is a factual comparison of the five ways Python developers actually call WhatsApp today, from browser automation to a unified provider, so you can pick based on what each option really does, not on marketing.<\/div>\n\n    <div class=\"wlb-table\">\n      <div class=\"wlb-row wlb-head\">\n        <div class=\"wlb-cell\">Library \/ approach<\/div>\n        <div class=\"wlb-cell\">What it actually calls<\/div>\n        <div class=\"wlb-cell\">Meta Business verification<\/div>\n        <div class=\"wlb-cell\">Maintained<\/div>\n        <div class=\"wlb-cell\">Best for<\/div>\n      <\/div>\n      <div class=\"wlb-row\">\n        <div class=\"wlb-cell\">pywhatkit<\/div>\n        <div class=\"wlb-cell\">Drives WhatsApp Web in a browser tab (keyboard automation), not a server-side API<\/div>\n        <div class=\"wlb-cell\"><span class=\"wlb-tag wlb-na\">N\/A, no API<\/span><\/div>\n        <div class=\"wlb-cell\">Community, sporadic<\/div>\n        <div class=\"wlb-cell\">One-off scripts and demos on a machine with a screen, not production sending<\/div>\n      <\/div>\n      <div class=\"wlb-row\">\n        <div class=\"wlb-cell\">whatsapp-cloud-api<\/div>\n        <div class=\"wlb-cell\">Thin Python wrapper around Meta's own WhatsApp Cloud API endpoints<\/div>\n        <div class=\"wlb-cell\"><span class=\"wlb-tag wlb-yes\">Required<\/span><\/div>\n        <div class=\"wlb-cell\">Community wrapper<\/div>\n        <div class=\"wlb-cell\">Teams already approved on the Cloud API who want a Pythonic client<\/div>\n      <\/div>\n      <div class=\"wlb-row\">\n        <div class=\"wlb-cell\">whatsapp-api-client-python<\/div>\n        <div class=\"wlb-cell\">Calls the green-api SaaS, which in turn holds the WhatsApp session<\/div>\n        <div class=\"wlb-cell\"><span class=\"wlb-tag wlb-no\">Not required<\/span><\/div>\n        <div class=\"wlb-cell\">Vendor-maintained<\/div>\n        <div class=\"wlb-cell\">Teams comfortable depending on a second, single-purpose SaaS vendor<\/div>\n      <\/div>\n      <div class=\"wlb-row\">\n        <div class=\"wlb-cell\">requests, direct to Meta<\/div>\n        <div class=\"wlb-cell\">Meta's Cloud API endpoints, no wrapper at all<\/div>\n        <div class=\"wlb-cell\"><span class=\"wlb-tag wlb-yes\">Required<\/span><\/div>\n        <div class=\"wlb-cell\">You own it (DIY)<\/div>\n        <div class=\"wlb-cell\">Teams already cleared for Meta Business verification who want full control<\/div>\n      <\/div>\n      <div class=\"wlb-row wlb-highlight\">\n        <div class=\"wlb-cell\">Unipile, requests or httpx<\/div>\n        <div class=\"wlb-cell\">Unipile's unified messaging API, WhatsApp alongside LinkedIn, Instagram and Telegram<\/div>\n        <div class=\"wlb-cell\"><span class=\"wlb-tag wlb-no\">Not required<\/span><\/div>\n        <div class=\"wlb-cell\">Actively maintained, Python SDK in beta<\/div>\n        <div class=\"wlb-cell\">SaaS products connecting many end-user WhatsApp accounts on behalf of each user<\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"wlb-cards\">\n      <div class=\"wlb-card\">\n        <div class=\"wlb-card-title\">pywhatkit<\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Calls<\/span><span class=\"wlb-card-value\">Drives WhatsApp Web in a browser tab, not a server-side API<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Meta verification<\/span><span class=\"wlb-card-value\"><span class=\"wlb-tag wlb-na\">N\/A, no API<\/span><\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Maintained<\/span><span class=\"wlb-card-value\">Community, sporadic<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Best for<\/span><span class=\"wlb-card-value\">One-off scripts and demos, not production sending<\/span><\/div>\n      <\/div>\n      <div class=\"wlb-card\">\n        <div class=\"wlb-card-title\">whatsapp-cloud-api<\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Calls<\/span><span class=\"wlb-card-value\">Thin wrapper around Meta's own Cloud API endpoints<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Meta verification<\/span><span class=\"wlb-card-value\"><span class=\"wlb-tag wlb-yes\">Required<\/span><\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Maintained<\/span><span class=\"wlb-card-value\">Community wrapper<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Best for<\/span><span class=\"wlb-card-value\">Teams already approved on the Cloud API<\/span><\/div>\n      <\/div>\n      <div class=\"wlb-card\">\n        <div class=\"wlb-card-title\">whatsapp-api-client-python<\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Calls<\/span><span class=\"wlb-card-value\">The green-api SaaS, which holds the WhatsApp session<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Meta verification<\/span><span class=\"wlb-card-value\"><span class=\"wlb-tag wlb-no\">Not required<\/span><\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Maintained<\/span><span class=\"wlb-card-value\">Vendor-maintained<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Best for<\/span><span class=\"wlb-card-value\">Teams comfortable with a second SaaS vendor<\/span><\/div>\n      <\/div>\n      <div class=\"wlb-card\">\n        <div class=\"wlb-card-title\">requests, direct to Meta<\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Calls<\/span><span class=\"wlb-card-value\">Meta's Cloud API endpoints, no wrapper<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Meta verification<\/span><span class=\"wlb-card-value\"><span class=\"wlb-tag wlb-yes\">Required<\/span><\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Maintained<\/span><span class=\"wlb-card-value\">You own it (DIY)<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Best for<\/span><span class=\"wlb-card-value\">Teams already cleared for Meta Business verification<\/span><\/div>\n      <\/div>\n      <div class=\"wlb-card wlb-highlight\">\n        <div class=\"wlb-card-title\">Unipile, requests or httpx<\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Calls<\/span><span class=\"wlb-card-value\">Unified messaging API, WhatsApp with LinkedIn, Instagram, Telegram<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Meta verification<\/span><span class=\"wlb-card-value\"><span class=\"wlb-tag wlb-no\">Not required<\/span><\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Maintained<\/span><span class=\"wlb-card-value\">Actively maintained, Python SDK in beta<\/span><\/div>\n        <div class=\"wlb-card-row\"><span class=\"wlb-card-label\">Best for<\/span><span class=\"wlb-card-value\">SaaS products connecting many end-user accounts<\/span><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"wlb-foot\">Every option that keeps <strong>Meta Business verification required<\/strong> ultimately talks to Meta's own WhatsApp Cloud API (see <a href=\"https:\/\/developers.facebook.com\/docs\/whatsapp\" target=\"_blank\" rel=\"noopener\">Meta's WhatsApp Business Platform documentation<\/a>), which is the right call if you already run a verified Business number. If you are connecting WhatsApp accounts on behalf of many different end users instead, a QR code or pairing code flow removes that verification step entirely, which is the model the rest of this guide uses.<\/div>\n  <\/div>\n<\/div>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-connect,#upl-wpy-connect *,#upl-wpy-connect *::before,#upl-wpy-connect *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-connect br{display:none !important;}#upl-wpy-connect p{display:contents !important;}#upl-wpy-connect{display:block !important;background:transparent !important;padding:70px 20px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-connect .wcn-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-connect .wcn-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-connect h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-connect .wcn-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:30px !important;display:block !important;width:100% !important;}#upl-wpy-connect .wcn-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-connect .wcn-lede code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-connect .wcn-h3{font-family:'Poppins',sans-serif !important;font-size:1.2rem !important;font-weight:700 !important;color:#0f2736 !important;margin:32px 0 12px !important;display:block !important;}#upl-wpy-connect .wcn-p{font-size:15.5px !important;line-height:1.75 !important;color:#475569 !important;margin-bottom:16px !important;display:block !important;}#upl-wpy-connect .wcn-p code,#upl-wpy-connect li code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-connect .wcn-p strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-connect .wcn-p a{color:#0f2736 !important;text-decoration:underline !important;}#upl-wpy-connect .wcn-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;margin:18px 0 !important;}#upl-wpy-connect .wcn-editor-bar{background:#161b22 !important;padding:11px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-connect .wcn-dot{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-connect .wcn-dot-r{background:#ff5f57 !important;}#upl-wpy-connect .wcn-dot-y{background:#febc2e !important;}#upl-wpy-connect .wcn-dot-g{background:#28c840 !important;}#upl-wpy-connect .wcn-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-connect .wcn-pre{padding:20px 22px !important;font-size:13px !important;line-height:1.75 !important;overflow-x:auto !important;background:#0d1117 !important;max-width:100% !important;}#upl-wpy-connect .wcn-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-connect .wcn-pre .wcn-c{color:#8b949e !important;}#upl-wpy-connect .wcn-grid2{display:grid !important;grid-template-columns:1fr 1fr !important;gap:24px !important;margin-top:10px !important;}#upl-wpy-connect .wcn-box{background:#f8fafc !important;border:1px solid #e5e7eb !important;border-radius:12px !important;padding:20px !important;}#upl-wpy-connect .wcn-box-title{display:flex !important;align-items:center !important;gap:10px !important;font-size:0.92rem !important;font-weight:700 !important;color:#0f2736 !important;margin-bottom:8px !important;}#upl-wpy-connect .wcn-box-title svg{width:18px !important;height:18px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2 !important;flex-shrink:0 !important;}#upl-wpy-connect .wcn-box-desc{font-size:0.85rem !important;line-height:1.6 !important;color:#64748b !important;}#upl-wpy-connect .wcn-cta-row{display:flex !important;align-items:center !important;gap:16px !important;margin-top:34px !important;}#upl-wpy-connect .wcn-cta{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:13px 24px !important;border-radius:8px !important;font-size:0.9rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;}#upl-wpy-connect .wcn-cta:hover{transform:translateY(-5px) !important;}#upl-wpy-connect .wcn-cta svg{width:15px !important;height:15px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}@media (max-width:900px){#upl-wpy-connect h2{font-size:28px !important;}#upl-wpy-connect .wcn-grid2{grid-template-columns:1fr !important;}}@media (max-width:600px){#upl-wpy-connect{padding:50px 16px !important;}#upl-wpy-connect h2{font-size:26px !important;}#upl-wpy-connect .wcn-lede{font-size:15.5px !important;}#upl-wpy-connect .wcn-pre{font-size:11.5px !important;padding:14px !important;}#upl-wpy-connect .wcn-cta-row{width:100% !important;}#upl-wpy-connect .wcn-cta{width:100% !important;justify-content:center !important;}}<\/style>\n\n<div id=\"upl-wpy-connect\">\n  <div class=\"wcn-container\">\n    <span id=\"wpy-connect\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wcn-eyebrow\">Account Connection<\/div>\n    <h2>How do you connect a WhatsApp account in Python?<\/h2>\n    <div class=\"wcn-lede\">Every call in this guide runs <strong>on behalf of an authenticated user<\/strong> who linked their own WhatsApp account. There is no Meta Business verification step: from Python, you send a single <code>POST \/api\/v1\/accounts<\/code> request with <code>provider<\/code> set to <code>WHATSAPP<\/code>, and the user confirms the link either by scanning a QR code or by typing a pairing code into their phone.<\/div>\n\n    <div class=\"wcn-h3\">Option A: QR code (default)<\/div>\n    <div class=\"wcn-p\">Leave <code>pairing_phone_number<\/code> out of the request body and Unipile returns a checkpoint carrying the QR code payload. Render it with a library such as <code>qrcode<\/code> and display it for the user to scan from WhatsApp &gt; Linked Devices.<\/div>\n    <div class=\"wcn-code-wrapper\">\n      <div class=\"wcn-editor-bar\"><span class=\"wcn-dot wcn-dot-r\"><\/span><span class=\"wcn-dot wcn-dot-y\"><\/span><span class=\"wcn-dot wcn-dot-g\"><\/span><span class=\"wcn-filename\">connect_qr.py<\/span><\/div>\n      <div class=\"wcn-pre\"><code class=\"wcn-code-1\">import requests&#10;&#10;BASE_URL = \"https:\/\/{YOUR_DSN}\/api\/v1\"&#10;HEADERS = {\"X-API-KEY\": \"YOUR_ACCESS_TOKEN\", \"accept\": \"application\/json\"}&#10;&#10;def connect_whatsapp_qr() -&gt; dict:&#10;    response = requests.post(&#10;        f\"{BASE_URL}\/accounts\",&#10;        headers=HEADERS,&#10;        json={\"provider\": \"WHATSAPP\"},&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()&#10;&#10;account = connect_whatsapp_qr()&#10;print(account)&#10;# account holds a new account_id plus a checkpoint object.&#10;# Render the checkpoint as a QR code and have the user scan it&#10;# from WhatsApp &gt; Linked Devices.<\/code><\/div>\n    <\/div>\n\n    <div class=\"wcn-h3\">Option B: pairing code<\/div>\n    <div class=\"wcn-p\">Pass <code>pairing_phone_number<\/code> in E.164 digits only, country code first, no plus sign, no spaces. Unipile returns a checkpoint carrying a short code the user types into WhatsApp instead of scanning anything, which is a better fit for a headless server with no screen to show a QR code on.<\/div>\n    <div class=\"wcn-code-wrapper\">\n      <div class=\"wcn-editor-bar\"><span class=\"wcn-dot wcn-dot-r\"><\/span><span class=\"wcn-dot wcn-dot-y\"><\/span><span class=\"wcn-dot wcn-dot-g\"><\/span><span class=\"wcn-filename\">connect_pairing_code.py<\/span><\/div>\n      <div class=\"wcn-pre\"><code class=\"wcn-code-2\">def connect_whatsapp_pairing_code(phone_e164_digits: str) -&gt; dict:&#10;    response = requests.post(&#10;        f\"{BASE_URL}\/accounts\",&#10;        headers=HEADERS,&#10;        json={&#10;            \"provider\": \"WHATSAPP\",&#10;            \"pairing_phone_number\": phone_e164_digits,&#10;        },&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()&#10;&#10;# Country code + number, digits only, e.g. France&#10;account = connect_whatsapp_pairing_code(\"33612345678\")&#10;# account's checkpoint carries the pairing code to show in your UI.&#10;# The user enters it in WhatsApp &gt; Linked Devices &gt; Link with phone number.<\/code><\/div>\n    <\/div>\n\n    <div class=\"wcn-h3\">Confirm that the account is connected<\/div>\n    <div class=\"wcn-p\">Once the user scans the QR code or types the pairing code, you need to know when the account is actually ready to send and receive. Unipile gives you two options.<\/div>\n    <div class=\"wcn-grid2\">\n      <div class=\"wcn-box\">\n        <div class=\"wcn-box-title\"><svg viewBox=\"0 0 24 24\"><polyline points=\"23 4 23 10 17 10\"\/><path d=\"M20.49 15a9 9 0 1 1-2.12-9.36L23 10\"\/><\/svg><span>Poll the account status<\/span><\/div>\n        <div class=\"wcn-box-desc\">Call <code>GET \/api\/v1\/accounts\/{account_id}<\/code> every couple of seconds until the account no longer needs its checkpoint. Simple, but it wastes requests while you wait.<\/div>\n      <\/div>\n      <div class=\"wcn-box\">\n        <div class=\"wcn-box-title\"><svg viewBox=\"0 0 24 24\"><path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\"\/><\/svg><span>Account Status Webhook<\/span><\/div>\n        <div class=\"wcn-box-desc\">Register a webhook with <code>source<\/code> set to <code>account_status<\/code> (same <code>POST \/api\/v1\/webhooks<\/code> endpoint used for messages) and Unipile pushes <code>{\"AccountStatus\": {\"account_id\": \"...\", \"message\": \"OK\"}}<\/code> the instant the account is ready. This is what most production integrations use.<\/div>\n      <\/div>\n    <\/div>\n    <div class=\"wcn-code-wrapper\">\n      <div class=\"wcn-editor-bar\"><span class=\"wcn-dot wcn-dot-r\"><\/span><span class=\"wcn-dot wcn-dot-y\"><\/span><span class=\"wcn-dot wcn-dot-g\"><\/span><span class=\"wcn-filename\">poll_status.py<\/span><\/div>\n      <div class=\"wcn-pre\"><code class=\"wcn-code-3\">import time&#10;&#10;def wait_for_connection(account_id: str, timeout_seconds: int = 120) -&gt; dict:&#10;    deadline = time.time() + timeout_seconds&#10;    while time.time() &lt; deadline:&#10;        response = requests.get(f\"{BASE_URL}\/accounts\/{account_id}\", headers=HEADERS)&#10;        response.raise_for_status()&#10;        account = response.json()&#10;        print(account)  # inspect the live payload for your own status check&#10;        time.sleep(2)&#10;    raise TimeoutError(\"WhatsApp account did not confirm connection in time\")<\/code><\/div>\n    <\/div>\n\n    <div class=\"wcn-cta-row\">\n      <a class=\"wcn-cta\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n        <span>Build the connection flow<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n      <\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-connect');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-send,#upl-wpy-send *,#upl-wpy-send *::before,#upl-wpy-send *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-send br{display:none !important;}#upl-wpy-send p{display:contents !important;}#upl-wpy-send{display:block !important;background:transparent !important;padding:70px 20px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-send .wsd-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-send .wsd-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-send h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-send .wsd-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:22px !important;display:block !important;width:100% !important;}#upl-wpy-send .wsd-lede code,#upl-wpy-send .wsd-p code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-send .wsd-lede strong,#upl-wpy-send .wsd-p strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-send .wsd-p{font-size:15.5px !important;line-height:1.75 !important;color:#475569 !important;margin-bottom:16px !important;display:block !important;}#upl-wpy-send .wsd-p a{color:#2aaa7e !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-send .wsd-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;margin:16px 0 20px !important;}#upl-wpy-send .wsd-editor-bar{background:#161b22 !important;padding:11px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-send .wsd-dot{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-send .wsd-dot-r{background:#ff5f57 !important;}#upl-wpy-send .wsd-dot-y{background:#febc2e !important;}#upl-wpy-send .wsd-dot-g{background:#28c840 !important;}#upl-wpy-send .wsd-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-send .wsd-pre{padding:20px 22px !important;font-size:13px !important;line-height:1.75 !important;overflow-x:auto !important;background:#0d1117 !important;max-width:100% !important;}#upl-wpy-send .wsd-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-send .wsd-note{display:flex !important;align-items:flex-start !important;gap:12px !important;background:#f4f5f7 !important;border-radius:10px !important;border:1px solid #e5e7eb !important;padding:14px 18px !important;margin-bottom:46px !important;}#upl-wpy-send .wsd-note svg{width:18px !important;height:18px !important;stroke:#64748b !important;fill:none !important;stroke-width:2 !important;flex-shrink:0 !important;margin-top:2px !important;}#upl-wpy-send .wsd-note-text{font-size:0.85rem !important;line-height:1.6 !important;color:#383838 !important;}#upl-wpy-send .wsd-note-text a{color:#0f2736 !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-send .wsd-h3{font-family:'Poppins',sans-serif !important;font-size:1.2rem !important;font-weight:700 !important;color:#0f2736 !important;margin:6px 0 12px !important;display:block !important;}#upl-wpy-send .wsd-cta-row{display:flex !important;align-items:center !important;gap:16px !important;margin-top:30px !important;}#upl-wpy-send .wsd-cta{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:13px 24px !important;border-radius:8px !important;font-size:0.9rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;}#upl-wpy-send .wsd-cta:hover{transform:translateY(-5px) !important;}#upl-wpy-send .wsd-cta svg{width:15px !important;height:15px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}@media (max-width:900px){#upl-wpy-send h2{font-size:28px !important;}}@media (max-width:600px){#upl-wpy-send{padding:50px 16px !important;}#upl-wpy-send h2{font-size:26px !important;}#upl-wpy-send .wsd-lede{font-size:15.5px !important;}#upl-wpy-send .wsd-pre{font-size:11.5px !important;padding:14px !important;}#upl-wpy-send .wsd-cta-row{width:100% !important;}#upl-wpy-send .wsd-cta{width:100% !important;justify-content:center !important;}}<\/style>\n\n<div id=\"upl-wpy-send\">\n  <div class=\"wsd-container\">\n    <span id=\"wpy-send\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wsd-eyebrow\">Send<\/div>\n    <h2>How do you send a WhatsApp message with Python?<\/h2>\n    <div class=\"wsd-lede\">Sending a WhatsApp message from Python is a single HTTP call: <code>POST \/api\/v1\/chats\/{chat_id}\/messages<\/code>, with the <code>chat_id<\/code> you already have from listing chats or from an incoming webhook, and a <code>text<\/code> field. The endpoint accepts form-encoded and JSON-encoded bodies alike, so a plain <code>requests.post<\/code> with <code>data=<\/code> works with no extra setup.<\/div>\n    <div class=\"wsd-p\">If there is no existing <code>chat_id<\/code>, for example the first message to a new contact, call <code>POST \/api\/v1\/chats<\/code> instead with an <code>account_id<\/code> and the recipient's <code>attendees_ids<\/code>; Unipile creates the 1:1 chat and sends the message in the same request.<\/div>\n    <div class=\"wsd-code-wrapper\">\n      <div class=\"wsd-editor-bar\"><span class=\"wsd-dot wsd-dot-r\"><\/span><span class=\"wsd-dot wsd-dot-y\"><\/span><span class=\"wsd-dot wsd-dot-g\"><\/span><span class=\"wsd-filename\">send.py<\/span><\/div>\n      <div class=\"wsd-pre\"><code class=\"wsd-code-1\">import requests&#10;&#10;BASE_URL = \"https:\/\/{YOUR_DSN}\/api\/v1\"&#10;HEADERS = {\"X-API-KEY\": \"YOUR_ACCESS_TOKEN\"}&#10;&#10;def send_message(chat_id: str, text: str) -&gt; dict:&#10;    response = requests.post(&#10;        f\"{BASE_URL}\/chats\/{chat_id}\/messages\",&#10;        headers=HEADERS,&#10;        data={\"text\": text},&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()&#10;&#10;def start_chat(account_id: str, attendee_provider_id: str, text: str) -&gt; dict:&#10;    response = requests.post(&#10;        f\"{BASE_URL}\/chats\",&#10;        headers=HEADERS,&#10;        data={&#10;            \"account_id\": account_id,&#10;            \"attendees_ids\": attendee_provider_id,&#10;            \"text\": text,&#10;        },&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()<\/code><\/div>\n    <\/div>\n    <div class=\"wsd-p\">Message types (text, media, voice notes, templates) and the 24-hour customer service window are their own topic, covered in full in the guide to <a href=\"https:\/\/www.unipile.com\/whatsapp-api-to-send-messages\/\">message types the WhatsApp API supports<\/a>. This section only covers the Python plumbing.<\/div>\n\n    <div class=\"wsd-note\">\n      <svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\"\/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"\/><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"\/><\/svg>\n      <div class=\"wsd-note-text\"><span>Meta bills WhatsApp API messages per message sent, not per conversation, since July 2025. See <a href=\"https:\/\/www.unipile.com\/whatsapp-business-api-pricing\/\">how WhatsApp API pricing works per message<\/a> for current per-country rates.<\/span><\/div>\n    <\/div>\n\n    <span id=\"wpy-async\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wsd-eyebrow\">Concurrency<\/div>\n    <h2>How do you send WhatsApp messages asynchronously in Python?<\/h2>\n    <div class=\"wsd-lede\">When you send to many recipients at once, a broadcast, a queue drain, a bulk follow-up job, a loop that awaits one <code>requests.post<\/code> at a time is the bottleneck, not the API. <code>httpx.AsyncClient<\/code> combined with <code>asyncio.gather<\/code> fires many requests concurrently from a single event loop, no threads required. A semaphore is what keeps you a good citizen: WhatsApp accounts are still bound by the platform's own rate limits, so uncapped concurrency just trades a slow loop for a wall of 429 responses.<\/div>\n\n    <div class=\"wsd-code-wrapper\">\n      <div class=\"wsd-editor-bar\"><span class=\"wsd-dot wsd-dot-r\"><\/span><span class=\"wsd-dot wsd-dot-y\"><\/span><span class=\"wsd-dot wsd-dot-g\"><\/span><span class=\"wsd-filename\">send_bulk_async.py<\/span><\/div>\n      <div class=\"wsd-pre\"><code class=\"wsd-code-2\">import asyncio&#10;import httpx&#10;&#10;BASE_URL = \"https:\/\/{YOUR_DSN}\/api\/v1\"&#10;HEADERS = {\"X-API-KEY\": \"YOUR_ACCESS_TOKEN\"}&#10;CONCURRENCY_LIMIT = 5&#10;&#10;async def send_message_async(&#10;    client: httpx.AsyncClient,&#10;    semaphore: asyncio.Semaphore,&#10;    chat_id: str,&#10;    text: str,&#10;) -&gt; dict:&#10;    async with semaphore:&#10;        response = await client.post(&#10;            f\"{BASE_URL}\/chats\/{chat_id}\/messages\",&#10;            headers=HEADERS,&#10;            data={\"text\": text},&#10;        )&#10;        response.raise_for_status()&#10;        return response.json()&#10;&#10;async def send_bulk(messages: list[tuple[str, str]]) -&gt; list:&#10;    semaphore = asyncio.Semaphore(CONCURRENCY_LIMIT)&#10;    async with httpx.AsyncClient(timeout=30) as client:&#10;        tasks = [&#10;            send_message_async(client, semaphore, chat_id, text)&#10;            for chat_id, text in messages&#10;        ]&#10;        return await asyncio.gather(*tasks, return_exceptions=True)&#10;&#10;messages = [&#10;    (\"9f9uio56sopa456s\", \"Your order shipped!\"),&#10;    (\"a1b2c3d4e5f6g7h8\", \"Your order shipped!\"),&#10;]&#10;results = asyncio.run(send_bulk(messages))&#10;for chat_id_text, result in zip(messages, results):&#10;    if isinstance(result, Exception):&#10;        print(\"failed:\", chat_id_text[0], result)<\/code><\/div>\n    <\/div>\n    <div class=\"wsd-p\">Keep <code>CONCURRENCY_LIMIT<\/code> conservative and raise it only after you have watched real error rates. <code>return_exceptions=True<\/code> means one failed send does not cancel the rest of the batch, which matters once you are firing hundreds of messages in one run. The rate limit and retry section below builds on this same pattern.<\/div>\n\n    <div class=\"wsd-cta-row\">\n      <a class=\"wsd-cta\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n        <span>Build your sending pipeline<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n      <\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-send');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-webhook,#upl-wpy-webhook *,#upl-wpy-webhook *::before,#upl-wpy-webhook *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-webhook br{display:none !important;}#upl-wpy-webhook p{display:contents !important;}#upl-wpy-webhook{display:block !important;background:transparent !important;padding:70px 20px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-webhook .wwh-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-webhook .wwh-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(221,223,76,0.18) !important;color:#8a8c2e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-webhook h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-webhook .wwh-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:26px !important;display:block !important;width:100% !important;}#upl-wpy-webhook .wwh-lede code,#upl-wpy-webhook .wwh-p code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-webhook .wwh-lede a,#upl-wpy-webhook .wwh-p a{color:#0f2736 !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-webhook .wwh-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-webhook .wwh-p{font-size:15.5px !important;line-height:1.75 !important;color:#475569 !important;margin-bottom:14px !important;display:block !important;}#upl-wpy-webhook .wwh-h3{font-family:'Poppins',sans-serif !important;font-size:1.2rem !important;font-weight:700 !important;color:#0f2736 !important;margin:30px 0 12px !important;display:block !important;}#upl-wpy-webhook .wwh-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;margin:16px 0 !important;}#upl-wpy-webhook .wwh-editor-bar{background:#161b22 !important;padding:11px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-webhook .wwh-dot{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-webhook .wwh-dot-r{background:#ff5f57 !important;}#upl-wpy-webhook .wwh-dot-y{background:#febc2e !important;}#upl-wpy-webhook .wwh-dot-g{background:#28c840 !important;}#upl-wpy-webhook .wwh-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-webhook .wwh-pre{padding:20px 22px !important;font-size:12.8px !important;line-height:1.72 !important;overflow-x:auto !important;background:#0d1117 !important;max-width:100% !important;}#upl-wpy-webhook .wwh-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-webhook .wwh-cta-row{display:flex !important;align-items:center !important;gap:16px !important;margin-top:30px !important;}#upl-wpy-webhook .wwh-cta{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:13px 24px !important;border-radius:8px !important;font-size:0.9rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;}#upl-wpy-webhook .wwh-cta:hover{transform:translateY(-5px) !important;}#upl-wpy-webhook .wwh-cta svg{width:15px !important;height:15px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}@media (max-width:900px){#upl-wpy-webhook h2{font-size:28px !important;}}@media (max-width:600px){#upl-wpy-webhook{padding:50px 16px !important;}#upl-wpy-webhook h2{font-size:26px !important;}#upl-wpy-webhook .wwh-lede{font-size:15.5px !important;}#upl-wpy-webhook .wwh-pre{font-size:11px !important;padding:14px !important;}#upl-wpy-webhook .wwh-cta-row{width:100% !important;}#upl-wpy-webhook .wwh-cta{width:100% !important;justify-content:center !important;}}<\/style>\n\n<div id=\"upl-wpy-webhook\">\n  <div class=\"wwh-container\">\n    <span id=\"wpy-webhook\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wwh-eyebrow\">Webhooks<\/div>\n    <h2>How do you receive WhatsApp messages with a FastAPI webhook?<\/h2>\n    <div class=\"wwh-lede\">A webhook is how your Python service learns about a new WhatsApp message the moment it arrives, instead of polling for it. You register one endpoint with Unipile, and every matching event is delivered to your server as JSON. <a href=\"https:\/\/fastapi.tiangolo.com\" target=\"_blank\" rel=\"noopener\" style=\"color:#0f2736;text-decoration:underline;font-weight:600;\">FastAPI<\/a> is a natural fit for the receiving side: a <code>pydantic<\/code> model validates the payload for you, and <code>BackgroundTasks<\/code> lets your route return a response immediately while the real work, calling a model, writing to a database, happens after.<\/div>\n\n    <div class=\"wwh-h3\">1. Register the webhook<\/div>\n    <div class=\"wwh-p\">Point <code>request_url<\/code> at your FastAPI route. During local development, that means the HTTPS URL your tunnel (from the prerequisites section above) exposes, not <code>localhost<\/code>.<\/div>\n    <div class=\"wwh-code-wrapper\">\n      <div class=\"wwh-editor-bar\"><span class=\"wwh-dot wwh-dot-r\"><\/span><span class=\"wwh-dot wwh-dot-y\"><\/span><span class=\"wwh-dot wwh-dot-g\"><\/span><span class=\"wwh-filename\">register_webhook.py<\/span><\/div>\n      <div class=\"wwh-pre\"><code class=\"wwh-code-1\">import requests&#10;&#10;BASE_URL = \"https:\/\/{YOUR_DSN}\/api\/v1\"&#10;HEADERS = {\"X-API-KEY\": \"YOUR_ACCESS_TOKEN\"}&#10;&#10;response = requests.post(&#10;    f\"{BASE_URL}\/webhooks\",&#10;    headers=HEADERS,&#10;    json={&#10;        \"source\": \"messaging\",&#10;        \"request_url\": \"https:\/\/your-tunnel.example.com\/webhooks\/whatsapp\",&#10;        \"name\": \"whatsapp-fastapi\",&#10;        \"format\": \"json\",&#10;        \"events\": [\"message_received\"],&#10;    },&#10;)&#10;response.raise_for_status()&#10;print(response.json())<\/code><\/div>\n    <\/div>\n\n    <div class=\"wwh-h3\">2. Receive it in FastAPI<\/div>\n    <div class=\"wwh-p\">The payload Unipile sends carries the chat, the sender and the message text as flat fields, plus a list of attachments when there are any. Model only what you need; Pydantic ignores extra fields by default.<\/div>\n    <div class=\"wwh-code-wrapper\">\n      <div class=\"wwh-editor-bar\"><span class=\"wwh-dot wwh-dot-r\"><\/span><span class=\"wwh-dot wwh-dot-y\"><\/span><span class=\"wwh-dot wwh-dot-g\"><\/span><span class=\"wwh-filename\">main.py<\/span><\/div>\n      <div class=\"wwh-pre\"><code class=\"wwh-code-2\">from typing import List, Optional&#10;&#10;from fastapi import BackgroundTasks, FastAPI&#10;from pydantic import BaseModel&#10;&#10;app = FastAPI()&#10;&#10;class Sender(BaseModel):&#10;    attendee_id: str&#10;    attendee_name: Optional[str] = None&#10;    attendee_provider_id: str&#10;&#10;class Attachment(BaseModel):&#10;    id: str&#10;    type: str&#10;    mimetype: Optional[str] = None&#10;    unavailable: bool = False&#10;&#10;class WhatsAppMessageEvent(BaseModel):&#10;    account_id: str&#10;    account_type: str&#10;    event: str&#10;    chat_id: str&#10;    message_id: str&#10;    message: Optional[str] = None&#10;    timestamp: str&#10;    webhook_name: Optional[str] = None&#10;    sender: Sender&#10;    attachments: List[Attachment] = []&#10;&#10;def handle_message(event: WhatsAppMessageEvent) -&gt; None:&#10;    if event.account_type != \"WHATSAPP\" or event.event != \"message_received\":&#10;        return&#10;    # Unipile includes messages the linked account itself sent, from&#10;    # another device or from your own API calls. Compare the sender&#10;    # against the account owner you stored at connection time if you&#10;    # only want to react to messages coming from the other side.&#10;    print(f\"New WhatsApp message on chat {event.chat_id}: {event.message}\")&#10;    # forward to your queue, your database, or an AI agent from here&#10;&#10;@app.post(\"\/webhooks\/whatsapp\")&#10;async def whatsapp_webhook(&#10;    event: WhatsAppMessageEvent,&#10;    background_tasks: BackgroundTasks,&#10;):&#10;    background_tasks.add_task(handle_message, event)&#10;    return {\"status\": \"received\"}<\/code><\/div>\n    <\/div>\n    <div class=\"wwh-p\">Run it with <code>uvicorn main:app --reload<\/code>, point your tunnel at port 8000, and register that public URL as <code>request_url<\/code> in step 1. Returning <code>{\"status\": \"received\"}<\/code> before the message is fully processed matters: Unipile expects a fast response, and <code>BackgroundTasks<\/code> is what keeps <code>handle_message<\/code> from blocking it.<\/div>\n    <div class=\"wwh-p\">One more thing worth building in from the start: store each processed <code>message_id<\/code> before you act on it, and skip anything you have already seen. If the linked WhatsApp account itself disconnects and reconnects, Unipile delivers the messages that arrived during that gap once it catches up, and a redeploy or a crashed background task can separately cause your own handler to see the same event twice, so treating <code>message_id<\/code> as an idempotency key keeps a WhatsApp bot from double-replying.<\/div>\n\n    <div class=\"wwh-cta-row\">\n      <a class=\"wwh-cta\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n        <span>Build your FastAPI webhook<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n      <\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-webhook');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-history,#upl-wpy-history *,#upl-wpy-history *::before,#upl-wpy-history *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-history br{display:none !important;}#upl-wpy-history p{display:contents !important;}#upl-wpy-history{display:block !important;background:transparent !important;padding:70px 20px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-history .whi-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-history .whi-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-history h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-history .whi-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:24px !important;display:block !important;width:100% !important;}#upl-wpy-history .whi-lede code,#upl-wpy-history .whi-p code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-history .whi-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-history .whi-p{font-size:15.5px !important;line-height:1.75 !important;color:#475569 !important;margin-bottom:16px !important;display:block !important;}#upl-wpy-history .whi-p a{color:#2aaa7e !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-history .whi-h3{font-family:'Poppins',sans-serif !important;font-size:1.2rem !important;font-weight:700 !important;color:#0f2736 !important;margin:28px 0 12px !important;display:block !important;}#upl-wpy-history .whi-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;margin:14px 0 !important;}#upl-wpy-history .whi-editor-bar{background:#161b22 !important;padding:11px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-history .whi-dot{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-history .whi-dot-r{background:#ff5f57 !important;}#upl-wpy-history .whi-dot-y{background:#febc2e !important;}#upl-wpy-history .whi-dot-g{background:#28c840 !important;}#upl-wpy-history .whi-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-history .whi-pre{padding:20px 22px !important;font-size:13px !important;line-height:1.72 !important;overflow-x:auto !important;background:#0d1117 !important;max-width:100% !important;}#upl-wpy-history .whi-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-history .whi-group-box{display:flex !important;align-items:flex-start !important;gap:14px !important;background:#f4f5f7 !important;border-radius:12px !important;border:1px solid #e5e7eb !important;padding:20px 22px !important;margin-top:30px !important;}#upl-wpy-history .whi-group-box svg{width:22px !important;height:22px !important;stroke:#64748b !important;fill:none !important;stroke-width:2 !important;flex-shrink:0 !important;margin-top:2px !important;}#upl-wpy-history .whi-group-box-text{font-size:0.9rem !important;line-height:1.65 !important;color:#383838 !important;}#upl-wpy-history .whi-group-box-text code{font-family:'SF Mono',Monaco,monospace !important;background:#ffffff !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;border:1px solid #e5e7eb !important;}#upl-wpy-history .whi-group-box-text a{color:#0f2736 !important;text-decoration:underline !important;font-weight:600 !important;}@media (max-width:900px){#upl-wpy-history h2{font-size:28px !important;}}@media (max-width:600px){#upl-wpy-history{padding:50px 16px !important;}#upl-wpy-history h2{font-size:26px !important;}#upl-wpy-history .whi-lede{font-size:15.5px !important;}#upl-wpy-history .whi-pre{font-size:11px !important;padding:14px !important;}}<\/style>\n\n<div id=\"upl-wpy-history\">\n  <div class=\"whi-container\">\n    <span id=\"wpy-history\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"whi-eyebrow\">Read<\/div>\n    <h2>How do you retrieve chats and message history in Python?<\/h2>\n    <div class=\"whi-lede\">Every list endpoint in the Unipile API, chats, messages, attendees, is paginated the same way: the response carries an <code>items<\/code> array and a <code>cursor<\/code>. Pass that <code>cursor<\/code> back on the next call, and stop once it comes back <code>null<\/code>. Python's <code>while True<\/code> loop maps onto that pattern directly.<\/div>\n\n    <div class=\"whi-h3\">List every WhatsApp chat for an account<\/div>\n    <div class=\"whi-code-wrapper\">\n      <div class=\"whi-editor-bar\"><span class=\"whi-dot whi-dot-r\"><\/span><span class=\"whi-dot whi-dot-y\"><\/span><span class=\"whi-dot whi-dot-g\"><\/span><span class=\"whi-filename\">list_chats.py<\/span><\/div>\n      <div class=\"whi-pre\"><code class=\"whi-code-1\">import requests&#10;&#10;BASE_URL = \"https:\/\/{YOUR_DSN}\/api\/v1\"&#10;HEADERS = {\"X-API-KEY\": \"YOUR_ACCESS_TOKEN\"}&#10;&#10;def list_all_whatsapp_chats(account_id: str) -&gt; list:&#10;    chats = []&#10;    cursor = None&#10;    while True:&#10;        params = {\"account_id\": account_id, \"limit\": 100}&#10;        if cursor:&#10;            params[\"cursor\"] = cursor&#10;        response = requests.get(f\"{BASE_URL}\/chats\", headers=HEADERS, params=params)&#10;        response.raise_for_status()&#10;        page = response.json()&#10;        chats.extend(page[\"items\"])&#10;        cursor = page[\"cursor\"]&#10;        if not cursor:&#10;            break&#10;    return chats&#10;&#10;for chat in list_all_whatsapp_chats(\"Yk08cDzzdsqs9_8ds\"):&#10;    print(chat[\"id\"], chat[\"name\"], chat[\"unread_count\"])<\/code><\/div>\n    <\/div>\n\n    <div class=\"whi-h3\">Read the message history and the attendees of one chat<\/div>\n    <div class=\"whi-p\">Most recent messages come back first. Use the same <code>limit<\/code> and <code>cursor<\/code> pattern to page backward through older history, and call the attendees endpoint whenever you need to resolve who is actually in a chat, individual or group.<\/div>\n    <div class=\"whi-code-wrapper\">\n      <div class=\"whi-editor-bar\"><span class=\"whi-dot whi-dot-r\"><\/span><span class=\"whi-dot whi-dot-y\"><\/span><span class=\"whi-dot whi-dot-g\"><\/span><span class=\"whi-filename\">chat_history.py<\/span><\/div>\n      <div class=\"whi-pre\"><code class=\"whi-code-2\">def get_chat_history(chat_id: str, limit: int = 100) -&gt; list:&#10;    response = requests.get(&#10;        f\"{BASE_URL}\/chats\/{chat_id}\/messages\",&#10;        headers=HEADERS,&#10;        params={\"limit\": limit},&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()[\"items\"]&#10;&#10;def get_chat_attendees(chat_id: str) -&gt; list:&#10;    response = requests.get(&#10;        f\"{BASE_URL}\/chats\/{chat_id}\/attendees\",&#10;        headers=HEADERS,&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()[\"items\"]&#10;&#10;messages = get_chat_history(\"9f9uio56sopa456s\")&#10;attendees = get_chat_attendees(\"9f9uio56sopa456s\")<\/code><\/div>\n    <\/div>\n    <div class=\"whi-p\">This is also the code path a CRM sync or a support inbox actually runs in Python: on a fresh connection, walk every chat once with <code>list_all_whatsapp_chats<\/code> to seed your database, then rely on the webhook from the previous section to keep it current instead of re-polling. The <code>GET \/chats<\/code> endpoint also accepts an <code>unread<\/code> filter, so a lighter job that only checks for unread chats on a schedule does not have to page through a full account history each time it runs.<\/div>\n\n    <div class=\"whi-group-box\">\n      <svg viewBox=\"0 0 24 24\"><path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"\/><circle cx=\"9\" cy=\"7\" r=\"4\"\/><path d=\"M23 21v-2a4 4 0 0 0-3-3.87\"\/><path d=\"M16 3.13a4 4 0 0 1 0 7.75\"\/><\/svg>\n      <div class=\"whi-group-box-text\"><span>WhatsApp groups are chats too, so the same <code>GET \/chats<\/code> and <code>GET \/chats\/{chat_id}\/attendees<\/code> calls list them and their members from Python with no extra code. To add or remove a participant, or to fetch the invite link, use <code>PATCH \/chats\/{chat_id}<\/code> with an <code>addParticipant<\/code>, <code>removeParticipant<\/code>, or <code>getInviteLink<\/code> action. The full walkthrough, together with Meta's own participant limits on its native Groups API, lives in the guide to <a href=\"https:\/\/www.unipile.com\/whatsapp-group-api\/\">add or remove WhatsApp group participants<\/a>.<\/span><\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-agent,#upl-wpy-agent *,#upl-wpy-agent *::before,#upl-wpy-agent *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-agent br{display:none !important;}#upl-wpy-agent p{display:contents !important;}#upl-wpy-agent{display:block !important;background:transparent !important;padding:70px 20px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-agent .wag-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-agent .wag-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-agent h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-agent .wag-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:24px !important;display:block !important;width:100% !important;}#upl-wpy-agent .wag-lede code,#upl-wpy-agent .wag-p code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-agent .wag-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-agent .wag-p{font-size:15.5px !important;line-height:1.75 !important;color:#475569 !important;margin-bottom:16px !important;display:block !important;}#upl-wpy-agent .wag-p a{color:#2aaa7e !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-agent .wag-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;margin:14px 0 20px !important;}#upl-wpy-agent .wag-editor-bar{background:#161b22 !important;padding:11px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-agent .wag-dot{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-agent .wag-dot-r{background:#ff5f57 !important;}#upl-wpy-agent .wag-dot-y{background:#febc2e !important;}#upl-wpy-agent .wag-dot-g{background:#28c840 !important;}#upl-wpy-agent .wag-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-agent .wag-pre{padding:20px 22px !important;font-size:13px !important;line-height:1.72 !important;overflow-x:auto !important;background:#0d1117 !important;max-width:100% !important;}#upl-wpy-agent .wag-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-agent .wag-cta-row{display:flex !important;align-items:center !important;gap:16px !important;margin-top:28px !important;}#upl-wpy-agent .wag-cta{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:13px 24px !important;border-radius:8px !important;font-size:0.9rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;}#upl-wpy-agent .wag-cta:hover{transform:translateY(-5px) !important;}#upl-wpy-agent .wag-cta svg{width:15px !important;height:15px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}@media (max-width:900px){#upl-wpy-agent h2{font-size:28px !important;}}@media (max-width:600px){#upl-wpy-agent{padding:50px 16px !important;}#upl-wpy-agent h2{font-size:26px !important;}#upl-wpy-agent .wag-lede{font-size:15.5px !important;}#upl-wpy-agent .wag-pre{font-size:11px !important;padding:14px !important;}#upl-wpy-agent .wag-cta-row{width:100% !important;}#upl-wpy-agent .wag-cta{width:100% !important;justify-content:center !important;}}<\/style>\n\n<div id=\"upl-wpy-agent\">\n  <div class=\"wag-container\">\n    <span id=\"wpy-agent\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wag-eyebrow\">Automation<\/div>\n    <h2>How do you build a WhatsApp bot or AI agent in Python?<\/h2>\n    <div class=\"wag-lede\">Every WhatsApp bot or AI agent follows the same three steps: receive a message through the webhook, decide what to do with it, send a reply on the same <code>chat_id<\/code>. Nothing about steps one and three changes when you put an LLM in the middle, which is why the FastAPI handler and the <code>send_message<\/code> function from the earlier sections are already most of the code you need.<\/div>\n\n    <div class=\"wag-code-wrapper\">\n      <div class=\"wag-editor-bar\"><span class=\"wag-dot wag-dot-r\"><\/span><span class=\"wag-dot wag-dot-y\"><\/span><span class=\"wag-dot wag-dot-g\"><\/span><span class=\"wag-filename\">agent.py<\/span><\/div>\n      <div class=\"wag-pre\"><code class=\"wag-code-1\">from openai import OpenAI  # or any LLM client you use&#10;&#10;llm = OpenAI()&#10;_recent_bot_replies: dict = {}&#10;&#10;def generate_reply(incoming_text: str) -&gt; str:&#10;    completion = llm.chat.completions.create(&#10;        model=\"gpt-4o-mini\",&#10;        messages=[&#10;            {\"role\": \"system\", \"content\": \"You are a helpful WhatsApp support agent.\"},&#10;            {\"role\": \"user\", \"content\": incoming_text},&#10;        ],&#10;    )&#10;    return completion.choices[0].message.content&#10;&#10;def handle_message(event: WhatsAppMessageEvent) -&gt; None:&#10;    if event.account_type != \"WHATSAPP\" or event.event != \"message_received\":&#10;        return&#10;    if not event.message:&#10;        return&#10;    if _recent_bot_replies.get(event.chat_id) == event.message:&#10;        return  # echo of our own last reply, ignore it&#10;&#10;    reply_text = generate_reply(event.message)&#10;    _recent_bot_replies[event.chat_id] = reply_text&#10;    send_message(event.chat_id, reply_text)<\/code><\/div>\n    <\/div>\n    <div class=\"wag-p\">The <code>_recent_bot_replies<\/code> guard matters more than it looks: Unipile's <code>message_received<\/code> event fires for messages the linked account sends too, from another device or from your own API calls, so without a guard an agent can end up replying to its own reply. A dictionary is fine for a demo; a production agent should keep that state in Redis or a database alongside conversation history and an idempotency key.<\/div>\n    <div class=\"wag-p\">The webhook payload and the <code>send_message<\/code> call are shaped the same way across WhatsApp, LinkedIn, Instagram and Telegram, only <code>account_type<\/code> changes, so the same FastAPI handler can route one agent's replies across every channel a user connected. Keeping channel-specific tone, formatting and rate limits straight when you do that is covered in the guide to the <a href=\"https:\/\/www.unipile.com\/multi-channel-api-for-ai-agents\/\">multi-channel API for AI agents<\/a>.<\/div>\n\n    <div class=\"wag-cta-row\">\n      <a class=\"wag-cta\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n        <span>Build your WhatsApp AI agent<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n      <\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-agent');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>#upl-wpy-advanced,#upl-wpy-advanced *,#upl-wpy-advanced *::before,#upl-wpy-advanced *::after{margin:0 !important;padding:0 !important;box-sizing:border-box !important;border:none !important;outline:none !important;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif !important;line-height:normal !important;letter-spacing:normal !important;text-transform:none !important;text-decoration:none !important;list-style:none !important;background:transparent !important;}#upl-wpy-advanced br{display:none !important;}#upl-wpy-advanced p{display:contents !important;}#upl-wpy-advanced{display:block !important;background:transparent !important;padding:70px 20px 80px !important;overflow-x:hidden !important;max-width:100vw !important;width:100% !important;}#upl-wpy-advanced .wadv-container{max-width:1100px !important;margin:0 auto !important;}#upl-wpy-advanced .wadv-eyebrow{display:inline-flex !important;align-items:center !important;gap:8px !important;background:rgba(59,185,139,0.12) !important;color:#2aaa7e !important;padding:6px 14px !important;border-radius:20px !important;font-size:12px !important;font-weight:700 !important;text-transform:uppercase !important;letter-spacing:0.5px !important;margin-bottom:18px !important;width:fit-content !important;}#upl-wpy-advanced .wadv-eyebrow.wadv-yellow{background:rgba(221,223,76,0.18) !important;color:#8a8c2e !important;}#upl-wpy-advanced h2{font-family:'Poppins',sans-serif !important;font-size:35px !important;font-weight:700 !important;color:#0f2736 !important;line-height:1.2 !important;margin-bottom:18px !important;display:block !important;width:100% !important;}#upl-wpy-advanced .wadv-lede{font-size:17px !important;line-height:1.8 !important;color:#383838 !important;margin-bottom:22px !important;display:block !important;width:100% !important;}#upl-wpy-advanced .wadv-lede code,#upl-wpy-advanced .wadv-p code{font-family:'SF Mono',Monaco,monospace !important;background:#f1f5f9 !important;padding:2px 6px !important;border-radius:4px !important;font-size:0.88em !important;color:#0f2736 !important;}#upl-wpy-advanced .wadv-lede a{color:#0f2736 !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-advanced .wadv-lede a code{text-decoration:underline !important;color:#0f2736 !important;}#upl-wpy-advanced .wadv-lede strong{color:#0f2736 !important;font-weight:600 !important;}#upl-wpy-advanced .wadv-p{font-size:15.5px !important;line-height:1.75 !important;color:#475569 !important;margin-bottom:16px !important;display:block !important;}#upl-wpy-advanced .wadv-p a{color:#2aaa7e !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-advanced .wadv-sub{margin-top:56px !important;}#upl-wpy-advanced .wadv-code-wrapper{border-radius:14px !important;overflow:hidden !important;background:#0d1117 !important;margin:14px 0 20px !important;}#upl-wpy-advanced .wadv-editor-bar{background:#161b22 !important;padding:11px 18px !important;display:flex !important;align-items:center !important;gap:8px !important;border-bottom:1px solid rgba(255,255,255,0.06) !important;}#upl-wpy-advanced .wadv-dot{width:11px !important;height:11px !important;border-radius:50% !important;display:inline-block !important;flex-shrink:0 !important;}#upl-wpy-advanced .wadv-dot-r{background:#ff5f57 !important;}#upl-wpy-advanced .wadv-dot-y{background:#febc2e !important;}#upl-wpy-advanced .wadv-dot-g{background:#28c840 !important;}#upl-wpy-advanced .wadv-filename{color:#8b949e !important;font-size:12.5px !important;margin-left:6px !important;font-family:'SF Mono',Monaco,monospace !important;}#upl-wpy-advanced .wadv-pre{padding:20px 22px !important;font-size:13px !important;line-height:1.72 !important;overflow-x:auto !important;background:#0d1117 !important;max-width:100% !important;}#upl-wpy-advanced .wadv-pre code{font-family:'SF Mono',Monaco,monospace !important;white-space:pre !important;display:block !important;color:#e6edf3 !important;}#upl-wpy-advanced .wadv-badges{display:flex !important;flex-wrap:wrap !important;gap:10px !important;margin:18px 0 24px !important;}#upl-wpy-advanced .wadv-badge{display:inline-flex !important;align-items:center !important;gap:7px !important;padding:7px 13px !important;background:#f8fafc !important;border:1px solid #e5e7eb !important;border-radius:8px !important;font-size:0.78rem !important;color:#1e293b !important;font-weight:500 !important;}#upl-wpy-advanced .wadv-badge svg{width:14px !important;height:14px !important;stroke:#3BB98B !important;fill:none !important;stroke-width:2.5 !important;flex-shrink:0 !important;}#upl-wpy-advanced .wadv-aside{display:flex !important;align-items:flex-start !important;gap:14px !important;background:#f4f5f7 !important;border-radius:12px !important;border:1px solid #e5e7eb !important;padding:18px 22px !important;margin:30px 0 !important;}#upl-wpy-advanced .wadv-aside svg{width:20px !important;height:20px !important;stroke:#64748b !important;fill:none !important;stroke-width:2 !important;flex-shrink:0 !important;margin-top:2px !important;}#upl-wpy-advanced .wadv-aside-text{font-size:0.88rem !important;line-height:1.65 !important;color:#383838 !important;}#upl-wpy-advanced .wadv-aside-text a{color:#0f2736 !important;text-decoration:underline !important;font-weight:600 !important;}#upl-wpy-advanced .wadv-cta-row{display:flex !important;align-items:center !important;gap:16px !important;margin-top:30px !important;}#upl-wpy-advanced .wadv-cta{display:inline-flex !important;align-items:center !important;gap:8px !important;background:#DDDF4C !important;color:#0f2736 !important;padding:13px 24px !important;border-radius:8px !important;font-size:0.9rem !important;font-weight:700 !important;transition:transform 0.3s ease !important;cursor:pointer !important;}#upl-wpy-advanced .wadv-cta:hover{transform:translateY(-5px) !important;}#upl-wpy-advanced .wadv-cta svg{width:15px !important;height:15px !important;stroke:#0f2736 !important;fill:none !important;stroke-width:2.5 !important;stroke-linecap:round !important;stroke-linejoin:round !important;}@media (max-width:900px){#upl-wpy-advanced h2{font-size:28px !important;}}@media (max-width:600px){#upl-wpy-advanced{padding:50px 16px 60px !important;}#upl-wpy-advanced h2{font-size:26px !important;}#upl-wpy-advanced .wadv-lede{font-size:15.5px !important;}#upl-wpy-advanced .wadv-pre{font-size:11px !important;padding:14px !important;}#upl-wpy-advanced .wadv-cta-row{width:100% !important;}#upl-wpy-advanced .wadv-cta{width:100% !important;justify-content:center !important;}#upl-wpy-advanced .wadv-sub{margin-top:42px !important;}}<\/style>\n\n<div id=\"upl-wpy-advanced\">\n  <div class=\"wadv-container\">\n    <span id=\"wpy-retry\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wadv-eyebrow\">Reliability<\/div>\n    <h2>How do you handle rate limits and retries in Python?<\/h2>\n    <div class=\"wadv-lede\">Unipile returns a JSON body with a <code>type<\/code> field, like <code>errors\/invalid_credentials<\/code> or <code>errors\/disconnected_account<\/code>, whenever a request fails. Some of those are worth retrying, a dropped connection or a temporary provider hiccup; others, like bad credentials, will not fix themselves no matter how many times you call again. How fast and how much you send from a single WhatsApp account stays a customer-side decision, shaped by the rate limits WhatsApp itself enforces on that account, not a fixed number Unipile imposes on top.<\/div>\n    <div class=\"wadv-p\">The <code>tenacity<\/code> package turns that into a decorator instead of a hand-rolled loop. Wrap the same <code>send_message<\/code> function from the sending section with exponential backoff and a capped attempt count:<\/div>\n\n    <div class=\"wadv-code-wrapper\">\n      <div class=\"wadv-editor-bar\"><span class=\"wadv-dot wadv-dot-r\"><\/span><span class=\"wadv-dot wadv-dot-y\"><\/span><span class=\"wadv-dot wadv-dot-g\"><\/span><span class=\"wadv-filename\">retry.py<\/span><\/div>\n      <div class=\"wadv-pre\"><code class=\"wadv-code-1\"># pip install tenacity&#10;import requests&#10;from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type&#10;&#10;@retry(&#10;    stop=stop_after_attempt(5),&#10;    wait=wait_exponential(multiplier=1, min=2, max=30),&#10;    retry=retry_if_exception_type(requests.exceptions.HTTPError),&#10;)&#10;def send_message_with_retry(chat_id: str, text: str) -&gt; dict:&#10;    response = requests.post(&#10;        f\"{BASE_URL}\/chats\/{chat_id}\/messages\",&#10;        headers=HEADERS,&#10;        data={\"text\": text},&#10;    )&#10;    response.raise_for_status()&#10;    return response.json()<\/code><\/div>\n    <\/div>\n    <div class=\"wadv-p\">Five attempts with a 2 to 30 second exponential backoff is a sane default for a background job; drop the attempt count for anything running in a user-facing request path, since <code>tenacity<\/code> will otherwise hold the request open while it retries. The same decorator wraps the async version from the concurrency section, just add <code>await<\/code> where <code>tenacity<\/code> supports it through <code>AsyncRetrying<\/code>.<\/div>\n\n    <span id=\"wpy-sdk\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n    <div class=\"wadv-eyebrow wadv-yellow wadv-sub\">SDK<\/div>\n    <h2>Is there an official Unipile Python SDK?<\/h2>\n    <div class=\"wadv-lede\">Yes. <a href=\"https:\/\/github.com\/unipile\/unipile-python\" target=\"_blank\" rel=\"noopener\"><code>unipile\/unipile-python<\/code><\/a> is real and actively maintained, with a commit pushed as recently as August 11, 2026. Two things are worth knowing before you reach for it: it is not published on PyPI yet, and it targets Unipile's API v2, which is still in beta, while every endpoint used throughout this guide is v1.<\/div>\n\n    <div class=\"wadv-badges\">\n      <div class=\"wadv-badge\"><svg viewBox=\"0 0 24 24\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg><span>Actively maintained, GitHub only<\/span><\/div>\n      <div class=\"wadv-badge\"><svg viewBox=\"0 0 24 24\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg><span>Python 3.9+, pydantic 2.11+<\/span><\/div>\n      <div class=\"wadv-badge\"><svg viewBox=\"0 0 24 24\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg><span>Not on PyPI, install from GitHub<\/span><\/div>\n      <div class=\"wadv-badge\"><svg viewBox=\"0 0 24 24\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg><span>Targets API v2 beta, not v1<\/span><\/div>\n    <\/div>\n\n    <div class=\"wadv-code-wrapper\">\n      <div class=\"wadv-editor-bar\"><span class=\"wadv-dot wadv-dot-r\"><\/span><span class=\"wadv-dot wadv-dot-y\"><\/span><span class=\"wadv-dot wadv-dot-g\"><\/span><span class=\"wadv-filename\">install_sdk.sh<\/span><\/div>\n      <div class=\"wadv-pre\"><code class=\"wadv-code-2\">pip install git+https:\/\/github.com\/unipile\/unipile-python.git<\/code><\/div>\n    <\/div>\n    <div class=\"wadv-code-wrapper\">\n      <div class=\"wadv-editor-bar\"><span class=\"wadv-dot wadv-dot-r\"><\/span><span class=\"wadv-dot wadv-dot-y\"><\/span><span class=\"wadv-dot wadv-dot-g\"><\/span><span class=\"wadv-filename\">sdk_usage.py<\/span><\/div>\n      <div class=\"wadv-pre\"><code class=\"wadv-code-3\">import unipile&#10;&#10;configuration = unipile.Configuration()&#10;configuration.api_key[\"apiKey\"] = \"YOUR_ACCESS_TOKEN\"&#10;&#10;api_client = unipile.ApiClient(configuration)&#10;messaging_api = unipile.MessagingApi(api_client)<\/code><\/div>\n    <\/div>\n    <div class=\"wadv-p\">For everything this guide covers today, build on the v1 REST endpoints with <code>requests<\/code> or <code>httpx<\/code>: they are stable, documented, and what every code sample above actually runs on. Once the Python SDK graduates out of beta and lands on PyPI, migrating mostly means swapping HTTP calls for typed client methods, the endpoints and the connected-account model underneath do not change. For comparison, the Node.js SDK is the one currently referenced throughout Unipile's main documentation index, and the older PHP SDK has been archived since October 2023.<\/div>\n\n    <div class=\"wadv-aside\">\n      <svg viewBox=\"0 0 24 24\"><polyline points=\"16 18 22 12 16 6\"\/><polyline points=\"8 6 2 12 8 18\"\/><\/svg>\n      <div class=\"wadv-aside-text\"><span>Building the same kind of integration for another channel? The <a href=\"https:\/\/www.unipile.com\/instagram-api-python-must-know-endpoints-for-fast-saas-integration\/\">Instagram API with Python<\/a> guide follows the identical connect, send, retrieve and webhook pattern shown in this article.<\/span><\/div>\n    <\/div>\n\n    <div class=\"wadv-cta-row\">\n      <a class=\"wadv-cta\" data-upl-link=\"https:\/\/dashboard.unipile.com\/signup\/\" data-upl-target=\"_blank\" href=\"https:\/\/dashboard.unipile.com\/signup\/\">\n        <span>Build with the REST API today<\/span>\n        <svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>\n      <\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  function init(){\n    var wrapper = document.getElementById('upl-wpy-advanced');\n    if (!wrapper) return;\n    wrapper.addEventListener('click', function(e) {\n      var linkEl = e.target.closest('[data-upl-link]');\n      if (linkEl) {\n        e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();\n        var url = linkEl.getAttribute('data-upl-link');\n        var target = linkEl.getAttribute('data-upl-target');\n        if (target === '_blank') { window.open(url, '_blank'); } else { window.location.href = url; }\n        return false;\n      }\n    }, true);\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n[et_pb_section fb_built=\"1\" _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_row _builder_version=\"4.27.3\" background_color=\"transparent\" custom_padding=\"0px|0px|0px|0px|false|false\" global_colors_info=\"{}\"]\n[et_pb_column type=\"4_4\" _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n[et_pb_code _builder_version=\"4.27.3\" global_colors_info=\"{}\"]\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"What is the best Python library for the WhatsApp Cloud API?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"There is no single best library, it depends on what you already have. If you are already approved on Meta's Cloud API, whatsapp-cloud-api gives you a Pythonic wrapper around it. If you want to skip Meta Business verification entirely and connect WhatsApp accounts on behalf of your users instead, Unipile's REST API called with requests or httpx covers WhatsApp alongside LinkedIn, Instagram and Telegram from one interface. pywhatkit is worth ruling out early: it drives WhatsApp Web in a browser, not a server-side API, so it does not fit a production backend.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How do you send a WhatsApp message with Python?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Send a POST request to \/api\/v1\/chats\/{chat_id}\/messages with a text field and your X-API-KEY header, for example requests.post(url, headers=headers, data={'text': 'Hello'}). If you do not have a chat_id yet, POST \/api\/v1\/chats with an account_id and the recipient's attendees_ids creates the chat and sends the first message in the same call.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Can you use the WhatsApp API in Python without a Meta Business account?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes. Connecting a WhatsApp account through Unipile only requires the account owner to scan a QR code or enter a pairing code, the same way WhatsApp Web works. There is no Meta Business Platform application and no phone number verification with Meta, because the integration runs on behalf of the authenticated user rather than through a registered WhatsApp Business number.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is there an official Unipile Python SDK, and is it on PyPI?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes, unipile\/unipile-python is an actively maintained official SDK, but it is not on PyPI: install it with pip install git+https:\/\/github.com\/unipile\/unipile-python.git. It also targets Unipile's API v2, which is in beta, while every endpoint in this guide uses the stable v1 API, so most Python integrations today are still built directly on requests or httpx rather than the SDK.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Should you use requests or httpx for the WhatsApp API?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"requests is simpler and enough for scripts, cron jobs and low-volume sending. httpx is worth the switch once you are sending to many recipients at once or building an async FastAPI service, because its AsyncClient lets you fire multiple requests concurrently from the same event loop instead of blocking on each one.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How do you receive WhatsApp messages in Python locally?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Run a FastAPI app locally, expose it with a tunnel like ngrok or cloudflared to get a public HTTPS URL, and register that URL as request_url when you create a webhook with source set to messaging. Unipile posts every new message to that tunnel URL, which forwards it straight to your local FastAPI route while you develop.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Can you manage WhatsApp groups with the API in Python?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes. WhatsApp groups show up as regular chats, so GET \/chats and GET \/chats\/{chat_id}\/attendees list them and their members with no special-casing. To add a participant, remove one, or fetch the group invite link, send a PATCH \/chats\/{chat_id} request with an addParticipant, removeParticipant, or getInviteLink action.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"What is different between the WhatsApp API in Python and in PHP?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"The underlying endpoints are identical, the difference is the runtime and its ecosystem: Python favors requests or httpx with asyncio for concurrency and FastAPI for webhooks, while PHP integrations typically use Guzzle and fit into a Laravel application with queued jobs.\"\n      }\n    }\n  ]\n}\n<\/script>\n\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Poppins:wght@600;700&#038;display=swap\" rel=\"stylesheet\"><span id=\"faq-wpy\" style=\"display:block;position:relative;top:-80px;visibility:hidden;\"><\/span>\n<style>#upl-wpy-faq{font-family:'Inter',sans-serif;padding:80px 20px;max-width:min(900px,100vw);width:100%;margin:0 auto;background:transparent!important;overflow-x:hidden!important;box-sizing:border-box!important;}#upl-wpy-faq *,#upl-wpy-faq *::before,#upl-wpy-faq *::after{margin:0!important;padding:0!important;box-sizing:border-box!important;}#upl-wpy-faq br{display:none !important;}#upl-wpy-faq p{display:contents !important;}#upl-wpy-faq .upl-faq-header{text-align:center!important;margin-bottom:60px!important;}#upl-wpy-faq .upl-faq-title{font-family:'Poppins',sans-serif!important;font-size:clamp(32px,5vw,38px)!important;font-weight:700!important;color:#0f2736!important;margin-bottom:16px!important;line-height:1.2!important;}#upl-wpy-faq .upl-faq-subtitle{font-size:17px!important;color:#383838!important;max-width:700px!important;margin:0 auto!important;line-height:1.6!important;}#upl-wpy-faq .upl-faq-list{display:flex!important;flex-direction:column!important;gap:12px!important;}#upl-wpy-faq .upl-faq-item{background:#ffffff!important;border:1px solid #e5e7eb!important;border-radius:16px!important;overflow:hidden!important;transition:all 0.3s ease!important;}#upl-wpy-faq .upl-faq-item:hover{border-color:#3BB98B!important;box-shadow:0 4px 20px rgba(59,185,139,0.08)!important;}#upl-wpy-faq .upl-faq-item.active{border-color:#3BB98B!important;box-shadow:0 8px 30px rgba(59,185,139,0.12)!important;}#upl-wpy-faq .upl-faq-question{width:100%!important;display:flex!important;align-items:flex-start!important;justify-content:space-between!important;gap:20px!important;padding:24px 28px!important;background:transparent!important;border:none!important;cursor:pointer!important;text-align:left!important;}#upl-wpy-faq .upl-faq-question-content{display:flex!important;align-items:flex-start!important;gap:16px!important;flex:1!important;}#upl-wpy-faq .upl-faq-number{flex-shrink:0!important;padding:6px 12px!important;background:rgba(59,185,139,0.12)!important;color:#3BB98B!important;border-radius:20px!important;font-size:0.8rem!important;font-weight:600!important;}#upl-wpy-faq .upl-faq-item.active .upl-faq-number{background:rgba(59,185,139,0.2)!important;color:#2a9d6e!important;}#upl-wpy-faq .upl-faq-question-text{font-family:'Poppins',sans-serif!important;font-size:1.1rem!important;font-weight:600!important;color:#0f2736!important;line-height:1.4!important;padding-top:4px!important;}#upl-wpy-faq .upl-faq-icon{flex-shrink:0!important;width:36px!important;height:36px!important;background:#f4f5f7!important;border-radius:50%!important;display:flex!important;align-items:center!important;justify-content:center!important;transition:all 0.3s ease!important;margin-top:2px!important;}#upl-wpy-faq .upl-faq-icon svg{width:18px!important;height:18px!important;color:#64748b!important;transition:all 0.3s ease!important;}#upl-wpy-faq .upl-faq-item:hover .upl-faq-icon{background:rgba(59,185,139,0.1)!important;}#upl-wpy-faq .upl-faq-item:hover .upl-faq-icon svg{color:#3BB98B!important;}#upl-wpy-faq .upl-faq-item.active .upl-faq-icon{background:#3BB98B!important;transform:rotate(45deg)!important;}#upl-wpy-faq .upl-faq-item.active .upl-faq-icon svg{color:#ffffff!important;}#upl-wpy-faq .upl-faq-answer{max-height:0!important;overflow:hidden!important;transition:max-height 0.4s ease!important;}#upl-wpy-faq .upl-faq-item.active .upl-faq-answer{max-height:600px!important;}#upl-wpy-faq .upl-faq-answer-content{padding:0 28px 28px 76px!important;color:#475569!important;font-size:1rem!important;line-height:1.7!important;}#upl-wpy-faq .upl-faq-answer-content strong{color:#0f2736!important;font-weight:600!important;}#upl-wpy-faq .upl-faq-answer-content a{color:#3BB98B!important;text-decoration:underline!important;}#upl-wpy-faq .upl-faq-answer-content code{font-family:monospace!important;background:#f1f5f9!important;padding:2px 6px!important;border-radius:3px!important;font-size:0.85em!important;}#upl-wpy-faq .upl-faq-cta{margin-top:50px!important;display:flex!important;align-items:center!important;justify-content:space-between!important;gap:20px!important;padding:20px 28px!important;background:#ffffff!important;border:1px solid #e5e7eb!important;border-radius:12px!important;}#upl-wpy-faq .upl-faq-cta-text{color:#475569!important;font-size:1rem!important;}#upl-wpy-faq .upl-faq-cta-button{display:inline-flex!important;align-items:center!important;gap:10px!important;background:#DDDF4C!important;color:#0F2836!important;padding:13px 20px!important;border-radius:8px!important;text-decoration:none!important;font-weight:700!important;font-size:1rem!important;border:none!important;cursor:pointer!important;white-space:nowrap!important;}#upl-wpy-faq .upl-faq-cta-button:hover{transform:translateY(-2px)!important;}@media (max-width:768px){#upl-wpy-faq{padding:60px 16px!important;}#upl-wpy-faq .upl-faq-answer-content{padding:0 20px 20px 20px!important;}#upl-wpy-faq .upl-faq-question{padding:18px 20px!important;}#upl-wpy-faq .upl-faq-cta{flex-direction:column!important;align-items:flex-start!important;}}<\/style>\n\n<section id=\"upl-wpy-faq\">\n  <div class=\"upl-faq-header\">\n    <h2 class=\"upl-faq-title\">WhatsApp API in Python: FAQ<\/h2>\n    <pee class=\"upl-faq-subtitle\">Straight answers on libraries, connection, SDKs and webhooks for building the WhatsApp API in Python.<\/pee>\n  <\/div>\n  <div class=\"upl-faq-list\">\n\n    <div class=\"upl-faq-item active\">\n      <button class=\"upl-faq-question\" aria-expanded=\"true\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">01<\/span>\n          <span class=\"upl-faq-question-text\">What is the best Python library for the WhatsApp Cloud API?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>There is no single best library, it depends on what you already have. If you are already approved on Meta's Cloud API, <code>whatsapp-cloud-api<\/code> gives you a Pythonic wrapper around it. If you want to skip Meta Business verification entirely and connect WhatsApp accounts on behalf of your users instead, Unipile's REST API called with <code>requests<\/code> or <code>httpx<\/code> covers WhatsApp alongside LinkedIn, Instagram and Telegram from one interface. <code>pywhatkit<\/code> is worth ruling out early: it drives WhatsApp Web in a browser, not a server-side API, so it does not fit a production backend.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">02<\/span>\n          <span class=\"upl-faq-question-text\">How do you send a WhatsApp message with Python?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>Send a <code>POST<\/code> request to <code>\/api\/v1\/chats\/{chat_id}\/messages<\/code> with a <code>text<\/code> field and your <code>X-API-KEY<\/code> header, for example <code>requests.post(url, headers=headers, data={\"text\": \"Hello\"})<\/code>. If you do not have a <code>chat_id<\/code> yet, <code>POST \/api\/v1\/chats<\/code> with an <code>account_id<\/code> and the recipient's <code>attendees_ids<\/code> creates the chat and sends the first message in the same call.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">03<\/span>\n          <span class=\"upl-faq-question-text\">Can you use the WhatsApp API in Python without a Meta Business account?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>Yes. Connecting a WhatsApp account through Unipile only requires the account owner to scan a QR code or enter a pairing code, the same way WhatsApp Web works. There is no Meta Business Platform application and no phone number verification with Meta, because the integration runs <strong>on behalf of the authenticated user<\/strong> rather than through a registered WhatsApp Business number.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">04<\/span>\n          <span class=\"upl-faq-question-text\">Is there an official Unipile Python SDK, and is it on PyPI?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>Yes, <code>unipile\/unipile-python<\/code> is an actively maintained official SDK, but it is not on PyPI yet: install it with <code>pip install git+https:\/\/github.com\/unipile\/unipile-python.git<\/code>. It also targets Unipile's API v2, which is in beta, while every endpoint in this guide uses the stable v1 API, so most Python integrations today are still built directly on <code>requests<\/code> or <code>httpx<\/code> rather than the SDK.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">05<\/span>\n          <span class=\"upl-faq-question-text\">Should you use requests or httpx for the WhatsApp API?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div><code>requests<\/code> is simpler and enough for scripts, cron jobs and low-volume sending. <code>httpx<\/code> is worth the switch once you are sending to many recipients at once or building an async FastAPI service, because its <code>AsyncClient<\/code> lets you fire multiple requests concurrently from the same event loop instead of blocking on each one.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">06<\/span>\n          <span class=\"upl-faq-question-text\">How do you receive WhatsApp messages in Python locally?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>Run a FastAPI app locally, expose it with a tunnel like <code>ngrok<\/code> or <code>cloudflared<\/code> to get a public HTTPS URL, and register that URL as <code>request_url<\/code> when you create a webhook with <code>source<\/code> set to <code>messaging<\/code>. Unipile posts every new message to that tunnel URL, which forwards it straight to your local FastAPI route while you develop.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">07<\/span>\n          <span class=\"upl-faq-question-text\">Can you manage WhatsApp groups with the API in Python?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>Yes. WhatsApp groups show up as regular chats, so <code>GET \/chats<\/code> and <code>GET \/chats\/{chat_id}\/attendees<\/code> list them and their members with no special-casing. To add a participant, remove one, or fetch the group invite link, send a <code>PATCH \/chats\/{chat_id}<\/code> request with an <code>addParticipant<\/code>, <code>removeParticipant<\/code>, or <code>getInviteLink<\/code> action, detailed in the guide to <a href=\"https:\/\/www.unipile.com\/whatsapp-group-api\/\" style=\"color:#3BB98B;text-decoration:underline;\">adding and removing WhatsApp group members<\/a>.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"upl-faq-item\">\n      <button class=\"upl-faq-question\" aria-expanded=\"false\">\n        <div class=\"upl-faq-question-content\">\n          <span class=\"upl-faq-number\">08<\/span>\n          <span class=\"upl-faq-question-text\">What is different between the WhatsApp API in Python and in PHP?<\/span>\n        <\/div>\n        <div class=\"upl-faq-icon\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"\/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><\/svg><\/div>\n      <\/button>\n      <div class=\"upl-faq-answer\">\n        <div class=\"upl-faq-answer-content\"><div>The underlying endpoints are identical, the difference is the runtime and its ecosystem: Python favors <code>requests<\/code> or <code>httpx<\/code> with <code>asyncio<\/code> for concurrency and FastAPI for webhooks, while PHP integrations typically use Guzzle and fit into a Laravel application with queued jobs. If your stack is PHP, <a href=\"https:\/\/www.unipile.com\/whatsapp-api-php\/\" style=\"color:#3BB98B;text-decoration:underline;\">the same integration in PHP<\/a> walks through every equivalent step.<\/div><\/div>\n      <\/div>\n    <\/div>\n\n  <\/div>\n  <div class=\"upl-faq-cta\">\n    <pee class=\"upl-faq-cta-text\">Still have questions? Our team is here to help.<\/pee>\n    <span class=\"upl-faq-cta-button\" onclick=\"if(window.$crisp){$crisp.push(['do','chat:open'])}\"><span>Talk to an expert<\/span><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"\/><polyline points=\"12 5 19 12 12 19\"\/><\/svg><\/span>\n  <\/div>\n<\/section>\n\n<script>\n(function(){\n  function initFaq(){\n    var faq=document.getElementById('upl-wpy-faq');\n    if(!faq)return;\n    faq.querySelectorAll('.upl-faq-question').forEach(function(btn){\n      btn.addEventListener('click',function(){\n        var item=btn.closest('.upl-faq-item');\n        var isActive=item.classList.contains('active');\n        faq.querySelectorAll('.upl-faq-item').forEach(function(i){i.classList.remove('active');i.querySelector('.upl-faq-question').setAttribute('aria-expanded','false');});\n        if(!isActive){item.classList.add('active');btn.setAttribute('aria-expanded','true');}\n      });\n    });\n  }\n  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',initFaq);}else{initFaq();}\n})();\n<\/script>\n\n[\/et_pb_code]\n[\/et_pb_column]\n[\/et_pb_row]\n[\/et_pb_section]\n","protected":false},"excerpt":{"rendered":"<p>Send How do you send a WhatsApp message with Python? Sending a WhatsApp message from Python is a single HTTP call: POST \/api\/v1\/chats\/{chat_id}\/messages, with the chat_id you already have from listing chats or from an incoming webhook, and a text field. The endpoint accepts form-encoded and JSON-encoded bodies alike, so a plain requests.post with data= [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":279777,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","inline_featured_image":false,"footnotes":""},"categories":[69],"tags":[],"post_folder":[],"class_list":["post-279753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-api-guidelines"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>WhatsApp API with Python: Send, Receive and Automate Messages - Unipile<\/title>\n<meta name=\"description\" content=\"Use the WhatsApp API in Python: compare the libraries, connect an account, send messages with requests or httpx, and receive webhooks in FastAPI.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.unipile.com\/br\/whatsapp-api-python\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WhatsApp API with Python: Send, Receive and Automate Messages - Unipile\" \/>\n<meta property=\"og:description\" content=\"Use the WhatsApp API in Python: compare the libraries, connect an account, send messages with requests or httpx, and receive webhooks in FastAPI.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.unipile.com\/br\/whatsapp-api-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Unipile\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/unipilefr\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-13T13:45:25+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-18T08:54:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.unipile.com\/wp-content\/uploads\/2026\/08\/whatsapp-api-python-featured.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1600\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Damien Girardeau\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@UnipileAPI\" \/>\n<meta name=\"twitter:site\" content=\"@UnipileAPI\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Damien Girardeau\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. tempo de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/\"},\"author\":{\"name\":\"Damien Girardeau\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#\\\/schema\\\/person\\\/a2ac44e22bdc27d497ce8b58716a673e\"},\"headline\":\"WhatsApp API with Python: Send, Receive and Automate Messages\",\"datePublished\":\"2026-08-13T13:45:25+00:00\",\"dateModified\":\"2026-08-18T08:54:18+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/\"},\"wordCount\":3911,\"publisher\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.unipile.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/whatsapp-api-python-featured.png\",\"articleSection\":[\"API Guidelines\"],\"inLanguage\":\"pt-BR\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/\",\"url\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/\",\"name\":\"WhatsApp API with Python: Send, Receive and Automate Messages - Unipile\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.unipile.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/whatsapp-api-python-featured.png\",\"datePublished\":\"2026-08-13T13:45:25+00:00\",\"dateModified\":\"2026-08-18T08:54:18+00:00\",\"description\":\"Use the WhatsApp API in Python: compare the libraries, connect an account, send messages with requests or httpx, and receive webhooks in FastAPI.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.unipile.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/whatsapp-api-python-featured.png\",\"contentUrl\":\"https:\\\/\\\/www.unipile.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/whatsapp-api-python-featured.png\",\"width\":2400,\"height\":1600,\"caption\":\"Receiving WhatsApp messages in FastAPI and sending them with requests or httpx\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/whatsapp-api-python\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.unipile.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WhatsApp API with Python: Send, Receive and Automate Messages\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#website\",\"url\":\"https:\\\/\\\/www.unipile.com\\\/\",\"name\":\"Unipile\",\"description\":\"Integrate Messaging &amp; Email, Connect with Ease via API\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.unipile.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#organization\",\"name\":\"Unipile\",\"url\":\"https:\\\/\\\/www.unipile.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.unipile.com\\\/wp-content\\\/uploads\\\/2021\\\/05\\\/logo-unipile.png\",\"contentUrl\":\"https:\\\/\\\/www.unipile.com\\\/wp-content\\\/uploads\\\/2021\\\/05\\\/logo-unipile.png\",\"width\":200,\"height\":49,\"caption\":\"Unipile\"},\"image\":{\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/unipilefr\",\"https:\\\/\\\/x.com\\\/UnipileAPI\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/unipile\\\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.unipile.com\\\/#\\\/schema\\\/person\\\/a2ac44e22bdc27d497ce8b58716a673e\",\"name\":\"Damien Girardeau\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/12dd140720736a8db29f540c42a17d2680cd54a04fb26bb7b55423c179b065a9?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/12dd140720736a8db29f540c42a17d2680cd54a04fb26bb7b55423c179b065a9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/12dd140720736a8db29f540c42a17d2680cd54a04fb26bb7b55423c179b065a9?s=96&d=mm&r=g\",\"caption\":\"Damien Girardeau\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WhatsApp API with Python: Send, Receive and Automate Messages - Unipile","description":"Use the WhatsApp API in Python: compare the libraries, connect an account, send messages with requests or httpx, and receive webhooks in FastAPI.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.unipile.com\/br\/whatsapp-api-python\/","og_locale":"pt_BR","og_type":"article","og_title":"WhatsApp API with Python: Send, Receive and Automate Messages - Unipile","og_description":"Use the WhatsApp API in Python: compare the libraries, connect an account, send messages with requests or httpx, and receive webhooks in FastAPI.","og_url":"https:\/\/www.unipile.com\/br\/whatsapp-api-python\/","og_site_name":"Unipile","article_publisher":"https:\/\/www.facebook.com\/unipilefr","article_published_time":"2026-08-13T13:45:25+00:00","article_modified_time":"2026-08-18T08:54:18+00:00","og_image":[{"width":2400,"height":1600,"url":"https:\/\/www.unipile.com\/wp-content\/uploads\/2026\/08\/whatsapp-api-python-featured.png","type":"image\/png"}],"author":"Damien Girardeau","twitter_card":"summary_large_image","twitter_creator":"@UnipileAPI","twitter_site":"@UnipileAPI","twitter_misc":{"Escrito por":"Damien Girardeau","Est. tempo de leitura":"15 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#article","isPartOf":{"@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/"},"author":{"name":"Damien Girardeau","@id":"https:\/\/www.unipile.com\/#\/schema\/person\/a2ac44e22bdc27d497ce8b58716a673e"},"headline":"WhatsApp API with Python: Send, Receive and Automate Messages","datePublished":"2026-08-13T13:45:25+00:00","dateModified":"2026-08-18T08:54:18+00:00","mainEntityOfPage":{"@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/"},"wordCount":3911,"publisher":{"@id":"https:\/\/www.unipile.com\/#organization"},"image":{"@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.unipile.com\/wp-content\/uploads\/2026\/08\/whatsapp-api-python-featured.png","articleSection":["API Guidelines"],"inLanguage":"pt-BR"},{"@type":"WebPage","@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/","url":"https:\/\/www.unipile.com\/whatsapp-api-python\/","name":"WhatsApp API with Python: Send, Receive and Automate Messages - Unipile","isPartOf":{"@id":"https:\/\/www.unipile.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#primaryimage"},"image":{"@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.unipile.com\/wp-content\/uploads\/2026\/08\/whatsapp-api-python-featured.png","datePublished":"2026-08-13T13:45:25+00:00","dateModified":"2026-08-18T08:54:18+00:00","description":"Use the WhatsApp API in Python: compare the libraries, connect an account, send messages with requests or httpx, and receive webhooks in FastAPI.","breadcrumb":{"@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.unipile.com\/whatsapp-api-python\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#primaryimage","url":"https:\/\/www.unipile.com\/wp-content\/uploads\/2026\/08\/whatsapp-api-python-featured.png","contentUrl":"https:\/\/www.unipile.com\/wp-content\/uploads\/2026\/08\/whatsapp-api-python-featured.png","width":2400,"height":1600,"caption":"Receiving WhatsApp messages in FastAPI and sending them with requests or httpx"},{"@type":"BreadcrumbList","@id":"https:\/\/www.unipile.com\/whatsapp-api-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.unipile.com\/"},{"@type":"ListItem","position":2,"name":"WhatsApp API with Python: Send, Receive and Automate Messages"}]},{"@type":"WebSite","@id":"https:\/\/www.unipile.com\/#website","url":"https:\/\/www.unipile.com\/","name":"Unipile","description":"Integre mensagens e e-mail, conecte-se com facilidade via API","publisher":{"@id":"https:\/\/www.unipile.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.unipile.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.unipile.com\/#organization","name":"Unipile","url":"https:\/\/www.unipile.com\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.unipile.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.unipile.com\/wp-content\/uploads\/2021\/05\/logo-unipile.png","contentUrl":"https:\/\/www.unipile.com\/wp-content\/uploads\/2021\/05\/logo-unipile.png","width":200,"height":49,"caption":"Unipile"},"image":{"@id":"https:\/\/www.unipile.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/unipilefr","https:\/\/x.com\/UnipileAPI","https:\/\/www.linkedin.com\/company\/unipile\/"]},{"@type":"Person","@id":"https:\/\/www.unipile.com\/#\/schema\/person\/a2ac44e22bdc27d497ce8b58716a673e","name":"Damien Girardeau","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/secure.gravatar.com\/avatar\/12dd140720736a8db29f540c42a17d2680cd54a04fb26bb7b55423c179b065a9?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/12dd140720736a8db29f540c42a17d2680cd54a04fb26bb7b55423c179b065a9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/12dd140720736a8db29f540c42a17d2680cd54a04fb26bb7b55423c179b065a9?s=96&d=mm&r=g","caption":"Damien Girardeau"}}]}},"_links":{"self":[{"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/posts\/279753","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/comments?post=279753"}],"version-history":[{"count":2,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/posts\/279753\/revisions"}],"predecessor-version":[{"id":279774,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/posts\/279753\/revisions\/279774"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/media\/279777"}],"wp:attachment":[{"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/media?parent=279753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/categories?post=279753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/tags?post=279753"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/www.unipile.com\/br\/wp-json\/wp\/v2\/post_folder?post=279753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}