New skills covering 10 categories: **Security & Audit**: 007 (STRIDE/PASTA/OWASP), cred-omega (secrets management) **AI Personas**: Karpathy, Hinton, Sutskever, LeCun (4 sub-skills), Altman, Musk, Gates, Jobs, Buffett **Multi-agent Orchestration**: agent-orchestrator, task-intelligence, multi-advisor **Code Analysis**: matematico-tao (Terence Tao-inspired mathematical code analysis) **Social & Messaging**: Instagram Graph API, Telegram Bot, WhatsApp Cloud API, social-orchestrator **Image Generation**: AI Studio (Gemini), Stability AI, ComfyUI Gateway, image-studio router **Brazilian Domain**: 6 auction specialist modules, 2 legal advisors, auctioneers data scraper **Product & Growth**: design, invention, monetization, analytics, growth engine **DevOps & LLM Ops**: Docker/CI-CD/AWS, RAG/embeddings/fine-tuning **Skill Governance**: installer, sentinel auditor, context management Each skill includes: - Standardized YAML frontmatter (name, description, risk, source, tags, tools) - Structured sections (Overview, When to Use, How it Works, Best Practices) - Python scripts and reference documentation where applicable - Cross-platform compatibility (Claude Code, Antigravity, Cursor, Gemini CLI, Codex CLI) Co-authored-by: ProgramadorBrasil <214873561+ProgramadorBrasil@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
101 lines
3.3 KiB
Python
101 lines
3.3 KiB
Python
"""WhatsApp Template Management - CRUD operations via API."""
|
|
|
|
import os
|
|
from typing import Any
|
|
|
|
import httpx
|
|
|
|
GRAPH_API = "https://graph.facebook.com/v21.0"
|
|
|
|
|
|
class TemplateManager:
|
|
"""Manage WhatsApp message templates programmatically."""
|
|
|
|
def __init__(
|
|
self,
|
|
token: str | None = None,
|
|
waba_id: str | None = None,
|
|
):
|
|
self.token = token or os.environ["WHATSAPP_TOKEN"]
|
|
self.waba_id = waba_id or os.environ["WABA_ID"]
|
|
self.headers = {
|
|
"Authorization": f"Bearer {self.token}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
async def list_templates(self, status: str | None = None) -> list[dict[str, Any]]:
|
|
"""List all templates, optionally filtered by status (APPROVED, PENDING, REJECTED)."""
|
|
params: dict[str, Any] = {"limit": 100}
|
|
if status:
|
|
params["status"] = status
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.get(
|
|
f"{GRAPH_API}/{self.waba_id}/message_templates",
|
|
params=params,
|
|
headers=self.headers,
|
|
)
|
|
response.raise_for_status()
|
|
return response.json()["data"]
|
|
|
|
async def create_template(
|
|
self,
|
|
name: str,
|
|
category: str,
|
|
language: str,
|
|
components: list[dict[str, Any]],
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Create a new message template.
|
|
|
|
Args:
|
|
name: Template name (lowercase, underscores, no spaces)
|
|
category: MARKETING, UTILITY, or AUTHENTICATION
|
|
language: Language code (e.g., 'pt_BR')
|
|
components: List of template components (HEADER, BODY, FOOTER, BUTTONS)
|
|
|
|
Returns:
|
|
Dict with id, status, and category of created template.
|
|
"""
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.post(
|
|
f"{GRAPH_API}/{self.waba_id}/message_templates",
|
|
json={
|
|
"name": name,
|
|
"category": category,
|
|
"language": language,
|
|
"components": components,
|
|
},
|
|
headers=self.headers,
|
|
)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
async def delete_template(self, template_name: str) -> None:
|
|
"""
|
|
Delete a template by name.
|
|
|
|
Note: This deletes ALL translations of the template.
|
|
Templates cannot be edited - delete and recreate instead.
|
|
"""
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.request(
|
|
"DELETE",
|
|
f"{GRAPH_API}/{self.waba_id}/message_templates",
|
|
json={"name": template_name},
|
|
headers=self.headers,
|
|
)
|
|
response.raise_for_status()
|
|
|
|
async def get_approved(self) -> list[dict[str, Any]]:
|
|
"""List only approved templates ready for use."""
|
|
return await self.list_templates("APPROVED")
|
|
|
|
async def get_pending(self) -> list[dict[str, Any]]:
|
|
"""List templates awaiting approval."""
|
|
return await self.list_templates("PENDING")
|
|
|
|
async def get_rejected(self) -> list[dict[str, Any]]:
|
|
"""List rejected templates."""
|
|
return await self.list_templates("REJECTED")
|