通过 API 管理模板 - WhatsApp Cloud API
通过 WhatsApp Business Management API 以编程方式创建、列出、删除和管理消息模板的完整指南。
目录
- 概述
- 模板类别
- 创建模板
- 列出模板
- 删除模板
- 带变量的模板
- 带媒体的模板
- 带按钮的模板
- 发送模板消息
- 最佳实践
概述
模板是 WhatsApp 预先批准的消息。它们是开始与客户对话的唯一方式(24 小时窗口外)。
限制:
- 每个 WABA 账号最多 6,000 个模板翻译
- 批准需要几分钟到几小时
- 模板提交后无法编辑(删除并重新创建)
- 模板正文:最多 1,600 个字符
基础端点:https://graph.facebook.com/v21.0/{waba-id}/message_templates
模板类别
| 类别 | 用途 | 费用 |
|---|---|---|
| MARKETING | 促销、活动、发布 | $0.025-$0.1365/条 |
| UTILITY | 订单确认、更新、跟踪 | $0.004-$0.0456/条 |
| AUTHENTICATION | OTP、密码重置、两步验证 | $0.004-$0.0456/条 |
类别影响费用和批准规则。营销模板有更严格的规则。
创建模板
Node.js
interfaceTemplateComponent{type:'HEADER'|'BODY'|'FOOTER'|'BUTTONS';format?:'TEXT'|'IMAGE'|'VIDEO'|'DOCUMENT';text?:string;example?:{header_handle?:string[];body_text?:string[][]};buttons?:Array<{type:'QUICK_REPLY'|'URL'|'PHONE_NUMBER';text:string;url?:string;phone_number?:string;example?:string[];}>;}asyncfunctioncreateTemplate(name:string,category:'MARKETING'|'UTILITY'|'AUTHENTICATION',language:string,components:TemplateComponent[]):Promise<any>{constresponse=awaitaxios.post(`${GRAPH_API}/${process.env.WABA_ID}/message_templates`,{name,category,language,components},{headers:{Authorization:`Bearer${process.env.WHATSAPP_TOKEN}`}});returnresponse.data;// { id: "template_id", status: "PENDING", category: "UTILITY" }}// Exemplo: Criar template de confirmacao de pedidoawaitcreateTemplate('order_confirmation_v1','UTILITY','pt_BR',[{type:'HEADER',format:'TEXT',text:'Pedido Confirmado!'},{type:'BODY',text:'Ola {{1}}, seu pedido #{{2}} foi confirmado!\n\nValor: R$ {{3}}\nPrevisao de entrega: {{4}}',example:{body_text:[['Joao','12345','99,90','3 dias uteis']]}},{type:'FOOTER',text:'Obrigado por comprar conosco!'}]);Python
asyncdefcreate_template(name:str,category:str,language:str,components:list[dict])->dict:asyncwithhttpx.AsyncClient()asclient:response=awaitclient.post(f"{GRAPH_API}/{os.environ['WABA_ID']}/message_templates",json={"name":name,"category":category,"language":language,"components":components},headers={"Authorization":f"Bearer{os.environ['WHATSAPP_TOKEN']}"})returnresponse.json()# Exemplo: Criar template de boas-vindasawaitcreate_template(name="welcome_v1",category="MARKETING",language="pt_BR",components=[{"type":"BODY","text":"Ola {{1}}, bem-vindo a nossa loja! 🎉\n\nConfira nossas ofertas exclusivas.","example":{"body_text":[["Maria"]]}},{"type":"BUTTONS","buttons":[{"type":"URL","text":"Ver Ofertas","url":"https://example.com/ofertas"},{"type":"QUICK_REPLY","text":"Falar com Vendedor"}]}])列出模板
Node.js
asyncfunctionlistTemplates(status?:string):Promise<any[]>{constparams=newURLSearchParams({limit:'100'});if(status)params.append('status',status);constresponse=awaitaxios.get(`${GRAPH_API}/${process.env.WABA_ID}/message_templates?${params}`,{headers:{Authorization:`Bearer${process.env.WHATSAPP_TOKEN}`}});returnresponse.data.data;}// Listar apenas templates aprovadosconstapproved=awaitlistTemplates('APPROVED');// Listar todosconstall=awaitlistTemplates();Python
asyncdeflist_templates(status:str|None=None)->list[dict]:params={"limit":100}ifstatus:params["status"]=statusasyncwithhttpx.AsyncClient()asclient:response=awaitclient.get(f"{GRAPH_API}/{os.environ['WABA_ID']}/message_templates",params=params,headers={"Authorization":f"Bearer{os.environ['WHATSAPP_TOKEN']}"})returnresponse.json()["data"]模板状态
| 状态 | 含义 |
|---|---|
| APPROVED | 已批准,可随时使用 |
| PENDING | WhatsApp 正在审核 |
| REJECTED | 已拒绝(在响应中查看原因) |
| PAUSED | 因质量低而暂停 |
| DISABLED | 已禁用 |
删除模板
Node.js
asyncfunctiondeleteTemplate(templateName:string):Promise<void>{awaitaxios.delete(`${GRAPH_API}/${process.env.WABA_ID}/message_templates`,{data:{name:templateName},headers:{Authorization:`Bearer${process.env.WHATSAPP_TOKEN}`}});}awaitdeleteTemplate('old_template_v1');Python
asyncdefdelete_template(template_name:str)->None:asyncwithhttpx.AsyncClient()asclient:awaitclient.request("DELETE",f"{GRAPH_API}/{os.environ['WABA_ID']}/message_templates",json={"name":template_name},headers={"Authorization":f"Bearer{os.environ['WHATSAPP_TOKEN']}"})注意:删除模板会移除所有关联的翻译。
带变量的模板
变量在模板文本中用{{N}}(从 1 开始)表示。
规则
- 变量必须连续:
{{1}}、{{2}}、{{3}} - 创建时,提供带示例值的
example - 发送时,提供带实际值的
parameters - 不要跳过数字:
{{1}}、{{3}}而没有{{2}}是无效的
完整示例
创建:
{"type":"BODY","text":"Ola {{1}}, seu pedido #{{2}} sera entregue em {{3}}.","example":{"body_text":[["Joao","12345","2 dias"]]}}发送:
{"type":"body","parameters":[{"type":"text","text":"Maria"},{"type":"text","text":"67890"},{"type":"text","text":"3 dias uteis"}]}带媒体的模板
带图片的标题
创建:
{"type":"HEADER","format":"IMAGE","example":{"header_handle":["4::aW1hZ2UvanBlZw==:ARb..."]}}要获取header_handle,先上传示例图片:
POST /{app-id}/uploads?file_type=image/jpeg&file_length=12345发送:
{"type":"header","parameters":[{"type":"image","image":{"link":"https://example.com/image.jpg"}}]}带文档的标题
创建:
{"type":"HEADER","format":"DOCUMENT","example":{"header_handle":["4::YXBwbGljYXRpb24vcGRm:ARb..."]}}发送:
{"type":"header","parameters":[{"type":"document","document":{"link":"https://example.com/invoice.pdf","filename":"Nota_Fiscal_12345.pdf"}}]}带按钮的模板
快速回复(最多 3 个按钮)
{"type":"BUTTONS","buttons":[{"type":"QUICK_REPLY","text":"Sim, confirmo"},{"type":"QUICK_REPLY","text":"Nao, cancelar"},{"type":"QUICK_REPLY","text":"Falar com atendente"}]}URL 按钮
{"type":"BUTTONS","buttons":[{"type":"URL","text":"Rastrear Pedido","url":"https://example.com/tracking/{{1}}","example":["12345"]}]}电话号码按钮
{"type":"BUTTONS","buttons":[{"type":"PHONE_NUMBER","text":"Ligar para Suporte","phone_number":"+5511999999999"}]}发送带动态 URL 按钮的模板
awaitsendMessage({messaging_product:'whatsapp',to:'5511999999999',type:'template',template:{name:'order_tracking_v1',language:{code:'pt_BR'},components:[{type:'body',parameters:[{type:'text',text:'Maria'},{type:'text',text:'67890'}]},{type:'button',sub_type:'url',index:0,parameters:[{type:'text',text:'67890'}// substitui {{1}} na URL]}]}});发送模板消息
完整示例 - Node.js
asyncfunctionsendTemplate(to:string,templateName:string,language:string,components?:Array<{type:string;parameters?:Array<{type:string;text?:string;image?:any;document?:any}>;sub_type?:string;index?:number;}>):Promise<any>{constpayload:any={messaging_product:'whatsapp',to,type:'template',template:{name:templateName,language:{code:language}}};if(components){payload.template.components=components;}returnsendWithRetry(payload);}// Uso simples (sem variaveis)awaitsendTemplate('5511999999999','hello_world','pt_BR');// Com variaveis no bodyawaitsendTemplate('5511999999999','order_confirmation_v1','pt_BR',[{type:'body',parameters:[{type:'text',text:'Joao'},{type:'text',text:'12345'},{type:'text',text:'99,90'},{type:'text',text:'3 dias uteis'}]}]);完整示例 - Python
asyncdefsend_template(to:str,template_name:str,language:str,components:list[dict]|None=None)->dict:payload={"messaging_product":"whatsapp","to":to,"type":"template","template":{"name":template_name,"language":{"code":language}}}ifcomponents:payload["template"]["components"]=componentsreturnawaitsend_with_retry(payload)# Uso simplesawaitsend_template("5511999999999","hello_world","pt_BR")# Com variaveisawaitsend_template("5511999999999","order_confirmation_v1","pt_BR",[{"type":"body","parameters":[{"type":"text","text":"Maria"},{"type":"text","text":"67890"},{"type":"text","text":"149,90"},{"type":"text","text":"5 dias uteis"}]}])最佳实践
命名
为模板名称使用一致的命名模式:
{finalidade}_{descricao}_v{versao}示例:
order_confirmation_v1welcome_new_customer_v2payment_reminder_v1nps_survey_v3
版本管理
由于模板无法编辑:
- 创建新版本:
template_name_v2 - 测试新版本
- 批准后,迁移代码以使用 v2
- 不再需要时删除 v1
批准技巧
- 在正文中避免过度促销的语言
- 在
example中包含清晰真实的示例 - 不要使用短链接(bit.ly 等)
- 不要包含可能被解读为垃圾邮件的内容
- 实用模板比营销模板批准更快
- 使用变量进行个性化(客户姓名、订单号)
监控
// Verificar status de templates periodicamenteasyncfunctionmonitorTemplates():Promise<void>{consttemplates=awaitlistTemplates();for(consttemplateoftemplates){if(template.status==='REJECTED'){console.warn(`Template rejeitado:${template.name}`);console.warn(`Motivo:${template.rejected_reason}`);}if(template.status==='PAUSED'){console.warn(`Template pausado por qualidade:${template.name}`);}}}