cdp-edge 1.17.0 → 1.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/contracts/api-versions.json +12 -8
- package/dist/commands/install.js +186 -0
- package/dist/commands/setup.js +18 -1
- package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +23 -23
- package/extracted-skill/tracking-events-generator/agents/bing-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +172 -72
- package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +20 -0
- package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +56 -16
- package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +7 -7
- package/extracted-skill/tracking-events-generator/agents/database-agent.md +16 -8
- package/extracted-skill/tracking-events-generator/agents/debug-agent.md +13 -13
- package/extracted-skill/tracking-events-generator/agents/devops-agent.md +32 -7
- package/extracted-skill/tracking-events-generator/agents/domain-setup-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/email-agent.md +27 -0
- package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +205 -0
- package/extracted-skill/tracking-events-generator/agents/google-agent.md +126 -0
- package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +90 -4
- package/extracted-skill/tracking-events-generator/agents/intelligence-scheduling.md +8 -641
- package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +116 -0
- package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +1 -1
- package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +68 -8
- package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +71 -34
- package/extracted-skill/tracking-events-generator/agents/memory-agent.md +127 -2
- package/extracted-skill/tracking-events-generator/agents/meta-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/performance-agent.md +29 -19
- package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +11 -1
- package/extracted-skill/tracking-events-generator/agents/pinterest-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/r2-setup-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/reddit-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +137 -28
- package/extracted-skill/tracking-events-generator/agents/server-tracking.md +8 -8
- package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +8 -0
- package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +71 -0
- package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +100 -5
- package/extracted-skill/tracking-events-generator/agents/validator-agent.md +4 -0
- package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +108 -0
- package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +58 -5
- package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +23 -15
- package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +140 -25
- package/extracted-skill/tracking-events-generator/contracts/api-versions.json +12 -8
- package/package.json +2 -2
- package/server-edge-tracker/worker.js +53 -8
|
@@ -4,6 +4,14 @@ Especialista exclusivo em TikTok Pixel (browser via cdpTrack) + TikTok Events AP
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## ✅ REGRAS CRÍTICAS
|
|
8
|
+
|
|
9
|
+
0. **CONSULTA OBRIGATÓRIA À MEMÓRIA**: Extraia o ID de Pixel TikTok e Token de Acesso (`TIKTOK_PIXEL_ID`, `TIKTOK_ACCESS_TOKEN`) consultando ativamente o "memory-agent.json". Solicite ao Orquestrador tudo o que faltar. Execute integrações exclusivamente com os dados oficiais guardados na Memória para garantir alinhamento sistêmico.
|
|
10
|
+
1. Cloudflare-Only: Sem dependências externas.
|
|
11
|
+
2. Same-Domain: Worker no domínio do site (anti-adblock).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
7
15
|
## 🏗️ ARQUITETURA Quantum Tier
|
|
8
16
|
- **Browser**: Use `cdpTrack.js` para captura direta.
|
|
9
17
|
- **Server**: Cloudflare Worker enviando para `/open_api/v1.3/event/track/`.
|
|
@@ -65,6 +73,69 @@ Gere payloads para o Worker seguir a API oficial:
|
|
|
65
73
|
|
|
66
74
|
---
|
|
67
75
|
|
|
76
|
+
## ⏱️ RATE LIMITS — TikTok Events API v1.3
|
|
77
|
+
|
|
78
|
+
Conforme `contracts/api-versions.json`, a TikTok Events API tem limites estritos:
|
|
79
|
+
|
|
80
|
+
| Limite | Valor | Ação se excedido |
|
|
81
|
+
|--------|-------|-----------------|
|
|
82
|
+
| Requisições por minuto (por pixel) | 10 req/min | Implementar throttling |
|
|
83
|
+
| Eventos por batch | 5 events/batch | Agrupar eventos em batches |
|
|
84
|
+
| Retries máximos | 3 tentativas | Backoff exponencial |
|
|
85
|
+
|
|
86
|
+
### Implementação de Throttling no Worker
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
// Rate limit KV key: 'tiktok_rate_{pixel_id}_{minute}'
|
|
90
|
+
async function dispatchTikTokWithRateLimit(env, events, pixelId, accessToken) {
|
|
91
|
+
const now = new Date();
|
|
92
|
+
const minuteKey = `tiktok_rate_${pixelId}_${now.getUTCFullYear()}${now.getUTCMonth()}${now.getUTCDate()}${now.getUTCHours()}${now.getUTCMinutes()}`;
|
|
93
|
+
|
|
94
|
+
// Verificar rate limit no KV
|
|
95
|
+
const currentCount = parseInt(await env.GEO_CACHE.get(minuteKey) || '0');
|
|
96
|
+
|
|
97
|
+
if (currentCount >= 10) {
|
|
98
|
+
// Rate limit atingido — encaminhar para RETRY_QUEUE
|
|
99
|
+
await env.RETRY_QUEUE.send({ platform: 'tiktok', events, pixelId });
|
|
100
|
+
return { queued: true, reason: 'rate_limit' };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Agrupar eventos em batches de 5
|
|
104
|
+
const batches = [];
|
|
105
|
+
for (let i = 0; i < events.length; i += 5) {
|
|
106
|
+
batches.push(events.slice(i, i + 5));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const results = [];
|
|
110
|
+
for (const batch of batches) {
|
|
111
|
+
const result = await fetch('https://business-api.tiktok.com/open_api/v1.3/event/track/', {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: {
|
|
114
|
+
'Content-Type': 'application/json',
|
|
115
|
+
'Access-Token': accessToken
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
pixel_code: pixelId,
|
|
119
|
+
event_source: 'web',
|
|
120
|
+
event_source_id: pixelId,
|
|
121
|
+
data: batch
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Incrementar contador no KV (TTL de 60s = 1 minuto)
|
|
126
|
+
await env.GEO_CACHE.put(minuteKey, String(currentCount + 1), { expirationTtl: 60 });
|
|
127
|
+
|
|
128
|
+
results.push(result);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return { sent: results.length, batches: batches.length };
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
> **Regra:** Se `HTTP 429` for recebido da TikTok API, encaminhar eventos para `RETRY_QUEUE` com backoff de 1min, 2min, 4min (máximo 3 tentativas).
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
68
139
|
## INPUTS RECEBIDOS
|
|
69
140
|
|
|
70
141
|
- JSON do Page Analyzer Agent (eventos mapeados, seletores, tipo de página)
|
|
@@ -59,19 +59,30 @@ function validateEventCoverage(pageAnalysis, agentOutputs) {
|
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
// Encontrar eventos
|
|
63
|
-
const
|
|
62
|
+
// Encontrar eventos do Page Analyzer NÃO implementados por nenhum agente
|
|
63
|
+
const unimplementedEvents = [];
|
|
64
|
+
pageEvents.forEach(eventKey => {
|
|
65
|
+
if (!agentEvents.has(eventKey)) {
|
|
66
|
+
unimplementedEvents.push(eventKey);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Encontrar eventos implementados pelos agentes mas SEM correspondência no Page Analyzer
|
|
71
|
+
const orphanEvents = [];
|
|
64
72
|
agentEvents.forEach(eventKey => {
|
|
65
73
|
if (!pageEvents.has(eventKey)) {
|
|
66
|
-
|
|
74
|
+
orphanEvents.push(eventKey);
|
|
67
75
|
}
|
|
68
76
|
});
|
|
69
77
|
|
|
70
78
|
return {
|
|
71
79
|
total_page_events: pageEvents.size,
|
|
72
80
|
total_implemented_events: agentEvents.size,
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
unimplemented_events: unimplementedEvents, // ← Eventos do plano sem código
|
|
82
|
+
orphan_events: orphanEvents, // ← Código sem evento no plano
|
|
83
|
+
coverage_percentage: Math.round(
|
|
84
|
+
((pageEvents.size - unimplementedEvents.length) / Math.max(pageEvents.size, 1)) * 100
|
|
85
|
+
)
|
|
75
86
|
};
|
|
76
87
|
}
|
|
77
88
|
```
|
|
@@ -187,6 +198,90 @@ async function validateApiVersions(trackingPlan) {
|
|
|
187
198
|
}
|
|
188
199
|
```
|
|
189
200
|
|
|
201
|
+
### 1.5 Validação Cruzada Completa (runFullValidation)
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
/**
|
|
205
|
+
* Ponto de entrada principal — executa TODAS as validações em sequência
|
|
206
|
+
* e retorna um relatório consolidado com status PASS | WARN | BLOCK
|
|
207
|
+
*
|
|
208
|
+
* @param {Object} pageAnalysis - Output do Page Analyzer Agent
|
|
209
|
+
* @param {Object} agentOutputs - Código gerado por todos os agentes
|
|
210
|
+
* @param {Object} apiVersions - Conteúdo de contracts/api-versions.json
|
|
211
|
+
* @returns {Object} Relatório consolidado de validação
|
|
212
|
+
*/
|
|
213
|
+
async function runFullValidation(pageAnalysis, agentOutputs, apiVersions) {
|
|
214
|
+
const report = {
|
|
215
|
+
status: 'PASS', // PASS | WARN | BLOCK
|
|
216
|
+
timestamp: new Date().toISOString(),
|
|
217
|
+
checks: {}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// CHECK 1: Cobertura de eventos
|
|
221
|
+
const coverage = validateEventCoverage(pageAnalysis, agentOutputs);
|
|
222
|
+
report.checks.event_coverage = coverage;
|
|
223
|
+
if (coverage.coverage_percentage < 100) {
|
|
224
|
+
report.status = coverage.coverage_percentage < 80 ? 'BLOCK' : 'WARN';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// CHECK 2: Parâmetros de conversão
|
|
228
|
+
const allEvents = Object.values(agentOutputs).flatMap(o => o.events || []);
|
|
229
|
+
const paramIssues = validateConversionParameters(allEvents, apiVersions);
|
|
230
|
+
report.checks.conversion_params = paramIssues;
|
|
231
|
+
if (paramIssues.filter(i => i.severity === 'HIGH').length > 0) {
|
|
232
|
+
report.status = 'BLOCK';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// CHECK 3: Seletores existentes no código
|
|
236
|
+
const missingSelectors = validateSelectorsExist({}, pageAnalysis);
|
|
237
|
+
report.checks.selectors = { missing: missingSelectors };
|
|
238
|
+
if (missingSelectors.length > 0) {
|
|
239
|
+
if (report.status === 'PASS') report.status = 'WARN';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// CHECK 4: Versões de API consistentes com api-versions.json
|
|
243
|
+
const trackingPlan = { events: {} };
|
|
244
|
+
Object.entries(agentOutputs).forEach(([agent, output]) => {
|
|
245
|
+
if (output.events) trackingPlan.events[agent] = output.events;
|
|
246
|
+
});
|
|
247
|
+
await validateApiVersions(trackingPlan);
|
|
248
|
+
const apiIssues = Object.values(trackingPlan.events)
|
|
249
|
+
.flatMap(events => events.filter(e => e.api_version_issue || e.api_deprecated));
|
|
250
|
+
report.checks.api_versions = apiIssues;
|
|
251
|
+
if (apiIssues.some(e => e.api_deprecated)) {
|
|
252
|
+
report.status = 'BLOCK'; // API depreciada = bloquear deploy
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// CHECK 5: Regras de ouro — deduplicação event_id
|
|
256
|
+
const missingEventId = allEvents.filter(e => !e.event_id && !e.params?.event_id);
|
|
257
|
+
report.checks.deduplication = {
|
|
258
|
+
events_missing_event_id: missingEventId.map(e => `${e.platform}:${e.name}`)
|
|
259
|
+
};
|
|
260
|
+
if (missingEventId.length > 0) report.status = 'WARN';
|
|
261
|
+
|
|
262
|
+
// CHECK 6: SHA-256 em campos PII
|
|
263
|
+
const piiFields = ['em', 'ph', 'fn', 'ln'];
|
|
264
|
+
const unhashed = allEvents.filter(e =>
|
|
265
|
+
piiFields.some(field => e.user_data?.[field] && !e.user_data[field].match(/^[a-f0-9]{64}$/))
|
|
266
|
+
);
|
|
267
|
+
report.checks.pii_hashing = {
|
|
268
|
+
events_with_unhashed_pii: unhashed.map(e => `${e.platform}:${e.name}`)
|
|
269
|
+
};
|
|
270
|
+
if (unhashed.length > 0) {
|
|
271
|
+
report.status = 'BLOCK'; // PII sem hash = bloquear imediatamente
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Determinar mensagem de status
|
|
275
|
+
report.summary = {
|
|
276
|
+
PASS: '✅ Tracking Plan validado — pode fazer deploy',
|
|
277
|
+
WARN: '⚠️ Tracking Plan com alertas — revisar antes do deploy',
|
|
278
|
+
BLOCK: '❌ BLOQUEADO — corrigir itens críticos antes do deploy'
|
|
279
|
+
}[report.status];
|
|
280
|
+
|
|
281
|
+
return report;
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
190
285
|
---
|
|
191
286
|
|
|
192
287
|
## PASSO 2 — GERAR O TRACKING PLAN COM VALIDAÇÃO
|
|
@@ -6,6 +6,10 @@ Você é o agente de controle de qualidade do CDP Edge. Sua responsabilidade: **
|
|
|
6
6
|
|
|
7
7
|
## 🛠️ CRITÉRIOS DE VALIDAÇÃO (Quantum Tier)
|
|
8
8
|
|
|
9
|
+
### PASSO 0 — Sincronização Obrigatória de Memória
|
|
10
|
+
|
|
11
|
+
- **CONSULTA OBRIGATÓRIA**: Extraia os valores oficiais do projeto (Versões de API, Domínios, Limites) lendo ativamente o "memory-agent.json". Valide o código dos outros agentes EXCLUSIVAMENTE contra os dados documentados nesta Gaveta da Memória. Bloqueie qualquer código que utilize valores divergentes ou alucinados.
|
|
12
|
+
|
|
9
13
|
### PASSO 1 — Verificações de API
|
|
10
14
|
|
|
11
15
|
- **Meta CAPI**: Endpoint DEVE ser `https://graph.facebook.com/v22.0/{PIXEL_ID}/events`. Rejeitar versões < v22.0.
|
|
@@ -4,6 +4,56 @@ Você é o especialista em Webhooks do CDP Edge. Sua missão é capturar vendas
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## ✅ REGRAS CRÍTICAS
|
|
8
|
+
|
|
9
|
+
0. **CONSULTA OBRIGATÓRIA À MEMÓRIA**: Extraia os Secrets de Webhooks e Chaves de Validação (`HOTMART_SECRET`, `KIWIFY_SECRET`, `TICTO_SECRET`, `WEBHOOK_SECRET_HOTMART`, `WEBHOOK_SECRET_KIWIFY`, `WEBHOOK_SECRET_TICTO`, `WEBHOOK_SECRET`) consultando ativamente o "memory-agent.json". Solicite ao Orquestrador tudo o que faltar. Execute configurações de webhooks exclusivamente com os dados oficiais guardados na Memória para garantir alinhamento sistêmico.
|
|
10
|
+
1. Cloudflare-Only: Sem dependências externas.
|
|
11
|
+
2. Same-Domain: Worker no domínio do site (anti-adblock).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🔐 NORMALIZAÇÃO E HASHING DE PII (OBRIGATÓRIO)
|
|
16
|
+
|
|
17
|
+
Antes de qualquer dispatch para CAPI, normalizar e hashear PII extraída do webhook:
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
// Hashing SHA-256 para PII — usar WebCrypto (disponível em Cloudflare Workers)
|
|
21
|
+
async function hashPII(value) {
|
|
22
|
+
if (!value) return null;
|
|
23
|
+
const normalized = value.toString().toLowerCase().trim();
|
|
24
|
+
const encoder = new TextEncoder();
|
|
25
|
+
const data = encoder.encode(normalized);
|
|
26
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
27
|
+
return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Normalização E.164 para telefone (Brasil)
|
|
31
|
+
function normalizePhone(phone) {
|
|
32
|
+
if (!phone) return null;
|
|
33
|
+
const digits = phone.replace(/\D/g, '');
|
|
34
|
+
// Adicionar +55 se não tiver código de país
|
|
35
|
+
if (digits.length === 10 || digits.length === 11) return `+55${digits}`;
|
|
36
|
+
if (digits.startsWith('55') && (digits.length === 12 || digits.length === 13)) return `+${digits}`;
|
|
37
|
+
return `+${digits}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Exemplo de uso no handler de webhook:
|
|
41
|
+
async function hashWebhookUserData(webhookPayload) {
|
|
42
|
+
const email = webhookPayload.buyer?.email || webhookPayload.email;
|
|
43
|
+
const phone = webhookPayload.buyer?.phone || webhookPayload.phone;
|
|
44
|
+
return {
|
|
45
|
+
em: email ? await hashPII(email) : null, // SHA-256 lowercase+trim
|
|
46
|
+
ph: phone ? await hashPII(normalizePhone(phone)) : null, // SHA-256 após E.164
|
|
47
|
+
fn: webhookPayload.buyer?.first_name ? await hashPII(webhookPayload.buyer.first_name) : null,
|
|
48
|
+
ln: webhookPayload.buyer?.last_name ? await hashPII(webhookPayload.buyer.last_name) : null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
> **Regra:** NUNCA enviar email ou telefone em plaintext para Meta CAPI, GA4 MP ou TikTok Events API. Sempre normalizar → hashear → enviar.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
7
57
|
## 🏗️ PADRÕES TÉCNICOS (Quantum Tier)
|
|
8
58
|
|
|
9
59
|
1. **D1 Identity Cross-Check**: Utilize o e-mail ou telefone do webhook para buscar no banco **D1** os identificadores originais (`fbp`, `fbc`, `ttp`). Isso garante a precisão da atribuição.
|
|
@@ -21,6 +71,64 @@ Você é o especialista em Webhooks do CDP Edge. Sua missão é capturar vendas
|
|
|
21
71
|
|
|
22
72
|
---
|
|
23
73
|
|
|
74
|
+
## 🔗 INTEGRAÇÃO COM OUTROS AGENTES (Fluxo Pós-Compra)
|
|
75
|
+
|
|
76
|
+
Após processar um webhook de compra com sucesso, o Webhook Agent DEVE disparar:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Webhook (Hotmart/Kiwify/Ticto/Stripe)
|
|
80
|
+
│
|
|
81
|
+
├─► [1] Validar HMAC → rejeitar 401 se inválido
|
|
82
|
+
├─► [2] Dedup D1 por transaction_id
|
|
83
|
+
├─► [3] Cross-check D1 por email → fbp/fbc/ttp/gclid
|
|
84
|
+
├─► [4] Hashear PII (SHA-256) — ver seção acima
|
|
85
|
+
│
|
|
86
|
+
├─► [5] CAPI Dispatch (ctx.waitUntil) — paralelo:
|
|
87
|
+
│ → Meta CAPI v22.0 (Purchase)
|
|
88
|
+
│ → GA4 MP (purchase)
|
|
89
|
+
│ → TikTok Events API v1.3 (CompletePayment)
|
|
90
|
+
│
|
|
91
|
+
├─► [6] Email Agent (ctx.waitUntil) — enviar confirmação de compra:
|
|
92
|
+
│ → Chamar sendEmail(env, 'purchase_confirmation', { email, nome, produto, valor })
|
|
93
|
+
│ → Ver email-agent.md para implementação completa
|
|
94
|
+
│
|
|
95
|
+
└─► [7] CRM Sync (ctx.waitUntil) — sincronizar comprador:
|
|
96
|
+
→ Chamar syncToCRM(env, 'purchase', { email, nome, produto, valor, order_id })
|
|
97
|
+
→ Ver crm-integration-agent.md para implementação completa
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Código de Integração (webhook handler)
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// No handler de webhook, após validação e dedup:
|
|
104
|
+
ctx.waitUntil(Promise.allSettled([
|
|
105
|
+
// [5] CAPI dispatch
|
|
106
|
+
dispatchToCAPI(env, hashedUserData, purchaseData),
|
|
107
|
+
|
|
108
|
+
// [6] Email Agent — confirmação de compra
|
|
109
|
+
sendEmail(env, 'purchase_confirmation', {
|
|
110
|
+
to: buyerEmail,
|
|
111
|
+
name: buyerName,
|
|
112
|
+
product: productName,
|
|
113
|
+
value: purchaseValue
|
|
114
|
+
}),
|
|
115
|
+
|
|
116
|
+
// [7] CRM Sync — criar/atualizar contato como comprador
|
|
117
|
+
syncToCRM(env, 'purchase', {
|
|
118
|
+
email: buyerEmail,
|
|
119
|
+
name: buyerName,
|
|
120
|
+
product: productName,
|
|
121
|
+
value: purchaseValue,
|
|
122
|
+
order_id: transactionId
|
|
123
|
+
})
|
|
124
|
+
]));
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
> **Nota:** `sendEmail()` é implementada pelo Email Agent em `cloudflare/email-service.js`.
|
|
128
|
+
> `syncToCRM()` é implementada pelo CRM Integration Agent em `cloudflare/crm-service.js`.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
24
132
|
## INPUTS RECEBIDOS
|
|
25
133
|
|
|
26
134
|
- Payload JSON do webhook da plataforma de vendas (Hotmart, Kiwify, Ticto, Stripe)
|
|
@@ -9,8 +9,8 @@ Você é o **Especialista em Mensageria WhatsApp (Quantum Tier)** do CDP Edge. S
|
|
|
9
9
|
1. **Meta Cloud API v22.0 (Eixo Vendas/Notificações ao dono)**:
|
|
10
10
|
- **Público**: O dono do sistema — notificações de Nova Venda e Novo Lead em tempo real.
|
|
11
11
|
- **Objetivo**: Avisar o dono quando chegar uma venda ou lead via webhook.
|
|
12
|
-
- **Padrão**: API oficial Meta v22.0 — `POST /v22.0/{
|
|
13
|
-
- **Secrets**: `
|
|
12
|
+
- **Padrão**: API oficial Meta v22.0 — `POST /v22.0/{WHATSAPP_PHONE_NUMBER_ID}/messages`.
|
|
13
|
+
- **Secrets**: `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_ACCESS_TOKEN`, `WA_NOTIFY_NUMBER`.
|
|
14
14
|
2. **CallMeBot (Eixo Guardião/Alertas de Sistema)**:
|
|
15
15
|
- **Público**: O dono do sistema (admin).
|
|
16
16
|
- **Objetivo**: Alertas internos do Cloudflare — Worker com erro, API falhando, token expirado, D1 com problema. **NÃO usado para mensagens a clientes.**
|
|
@@ -29,11 +29,64 @@ Sempre que o usuário desejar robustez na mensageria:
|
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
+
## 🔗 INTEGRAÇÃO COM WHATSAPP CTWA SETUP AGENT
|
|
33
|
+
|
|
34
|
+
O **WhatsApp CTWA Setup Agent** (`whatsapp-ctwa-setup-agent.md`) é o parceiro deste agente para rastreamento de anúncios Click-to-WhatsApp. A divisão de responsabilidades é clara:
|
|
35
|
+
|
|
36
|
+
| Este agente (whatsapp-agent) | CTWA Setup Agent |
|
|
37
|
+
|---|---|
|
|
38
|
+
| Notificações de venda/lead ao dono (Meta API) | Webhook `/webhook/whatsapp` — recebe mensagens da Meta |
|
|
39
|
+
| Alertas de sistema ao admin (CallMeBot) | Extração de `ctwa_clid` e disparo à Meta CAPI |
|
|
40
|
+
| Tracking de clique em botão WhatsApp (browser) | Setup do webhook de verificação (GET + POST) |
|
|
41
|
+
|
|
42
|
+
### Fluxo CTWA → Meta CAPI (implementado pelo CTWA Setup Agent)
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Usuário clica anúncio CTWA no Facebook/Instagram
|
|
46
|
+
↓
|
|
47
|
+
WhatsApp abre com mensagem pré-preenchida
|
|
48
|
+
↓
|
|
49
|
+
Meta faz POST ao Worker: /webhook/whatsapp
|
|
50
|
+
↓ (CTWA Setup Agent processa)
|
|
51
|
+
Worker extrai ctwa_clid + phone do payload
|
|
52
|
+
↓
|
|
53
|
+
Worker envia evento 'Contact' à Meta CAPI:
|
|
54
|
+
{
|
|
55
|
+
event_name: 'Contact',
|
|
56
|
+
action_source: 'chat', ← obrigatório para CTWA
|
|
57
|
+
event_source_url: ad_source_url,
|
|
58
|
+
user_data: { ph: sha256(phone) },
|
|
59
|
+
custom_data: { ctwa_clid: '...' } ← identifica o anúncio
|
|
60
|
+
}
|
|
61
|
+
↓
|
|
62
|
+
Worker salva no D1: tabela whatsapp_contacts
|
|
63
|
+
↓
|
|
64
|
+
WhatsApp Agent dispara notificação ao dono via Meta Cloud API v22.0
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### O que este agente gera para o fluxo CTWA
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// sendWhatsApp() — notificação ao dono quando chega lead CTWA
|
|
71
|
+
async function notifyOwnerNewCtwaLead(env, contactData) {
|
|
72
|
+
const message = `📲 Novo Lead CTWA!\n\nNome: ${contactData.name || 'Desconhecido'}\nTelefone: ${contactData.phone}\nAnúncio: ${contactData.headline || '-'}\nMensagem: "${contactData.messageBody?.slice(0, 80) || '-'}"`;
|
|
73
|
+
|
|
74
|
+
await sendWhatsApp(env, 'system', {
|
|
75
|
+
to: env.WA_NOTIFY_NUMBER,
|
|
76
|
+
message
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> **Regra de coordenação:** O CTWA Setup Agent processa o webhook e extrai ctwa_clid. Após salvar no D1 com `capi_sent = 0`, ele chama `notifyOwnerNewCtwaLead()` deste agente para notificar o dono. Manter esta divisão — nunca misturar as responsabilidades.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
32
85
|
## INPUTS RECEBIDOS
|
|
33
86
|
|
|
34
87
|
- Tipo de disparo: `Purchase` | `Lead` (Meta Cloud API) ou falha de sistema (CallMeBot)
|
|
35
88
|
- Dados do comprador/lead: `name`, `email`, `phone`, `product_name`, `value` (via webhook ou D1)
|
|
36
|
-
- Secrets Meta: `
|
|
89
|
+
- Secrets Meta: `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_ACCESS_TOKEN`, `WA_NOTIFY_NUMBER`
|
|
37
90
|
- Secrets CallMeBot: `CALLMEBOT_PHONE`, `CALLMEBOT_APIKEY`
|
|
38
91
|
- Contexto de erro (para alertas CallMeBot): plataforma afetada, mensagem de erro, timestamp
|
|
39
92
|
|
|
@@ -58,9 +111,9 @@ Sempre que o usuário desejar robustez na mensageria:
|
|
|
58
111
|
"eixos": {
|
|
59
112
|
"notificacoes": {
|
|
60
113
|
"api": "Meta Cloud API v22.0",
|
|
61
|
-
"endpoint": "POST /v22.0/{
|
|
114
|
+
"endpoint": "POST /v22.0/{WHATSAPP_PHONE_NUMBER_ID}/messages",
|
|
62
115
|
"tipos": ["Purchase", "Lead"],
|
|
63
|
-
"secrets": ["
|
|
116
|
+
"secrets": ["WHATSAPP_PHONE_NUMBER_ID", "WHATSAPP_ACCESS_TOKEN", "WA_NOTIFY_NUMBER"]
|
|
64
117
|
},
|
|
65
118
|
"alertas_sistema": {
|
|
66
119
|
"api": "CallMeBot",
|
|
@@ -5,6 +5,14 @@ Sua missão: configurar o rastreamento completo de anúncios Click to WhatsApp d
|
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## ✅ REGRAS CRÍTICAS
|
|
9
|
+
|
|
10
|
+
0. **CONSULTA OBRIGATÓRIA À MEMÓRIA**: Extraia o ID de Número WhatsApp, Token de API e Token de Verificação (`WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_ACCESS_TOKEN`, `WA_WEBHOOK_VERIFY_TOKEN`) consultando ativamente o "memory-agent.json". Solicite ao Orquestrador tudo o que faltar. Execute configurações de WhatsApp exclusivamente com os dados oficiais guardados na Memória para garantir alinhamento sistêmico.
|
|
11
|
+
1. Cloudflare-Only: Sem dependências externas.
|
|
12
|
+
2. Same-Domain: Worker no domínio do site (anti-adblock).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
8
16
|
## PARTE 1 — FUNDAMENTOS: O QUE É CTWA E COMO OS DADOS FLUEM
|
|
9
17
|
|
|
10
18
|
### O que é Click to WhatsApp (CTWA)
|
|
@@ -164,8 +172,8 @@ message_body | Olá, vi o anúncio e tenho interesse
|
|
|
164
172
|
[ ] META_APP_ID — ID do app no Meta for Developers ← usuário fornece
|
|
165
173
|
[ ] META_APP_SECRET — App Secret (developers.facebook.com → Básico) ← usuário fornece
|
|
166
174
|
[ ] WA_WEBHOOK_VERIFY_TOKEN — gerado pelo agente (crypto.randomUUID) ← agente cria
|
|
167
|
-
[ ]
|
|
168
|
-
[ ]
|
|
175
|
+
[ ] WHATSAPP_PHONE_NUMBER_ID — descoberto automaticamente via API ← agente descobre
|
|
176
|
+
[ ] WHATSAPP_ACCESS_TOKEN — mesmo que META_ACCESS_TOKEN ← agente reutiliza
|
|
169
177
|
[ ] WHATSAPP_BUSINESS_ACCOUNT_ID — descoberto automaticamente via API ← agente descobre
|
|
170
178
|
```
|
|
171
179
|
|
|
@@ -490,16 +498,16 @@ Deve mostrar o app com `override_callback_uri` (se não-SMB) ou apenas o app sub
|
|
|
490
498
|
|
|
491
499
|
```bash
|
|
492
500
|
echo "{WABA_ID}" | wrangler secret put WHATSAPP_BUSINESS_ACCOUNT_ID
|
|
493
|
-
echo "{PHONE_ID}" | wrangler secret put
|
|
494
|
-
echo "{META_ACCESS_TOKEN}" | wrangler secret put
|
|
501
|
+
echo "{PHONE_ID}" | wrangler secret put WHATSAPP_PHONE_NUMBER_ID
|
|
502
|
+
echo "{META_ACCESS_TOKEN}" | wrangler secret put WHATSAPP_ACCESS_TOKEN
|
|
495
503
|
echo "{META_APP_SECRET}" | wrangler secret put META_APP_SECRET
|
|
496
504
|
echo "{META_ACCESS_TOKEN}" | wrangler secret put META_ACCESS_TOKEN
|
|
497
505
|
|
|
498
506
|
# ── Secrets para Auto-Resposta WhatsApp (enviar mensagens de saída) ─────────
|
|
499
507
|
# Necessários para: worker.js → auto-resposta após Lead/Purchase
|
|
500
|
-
#
|
|
508
|
+
# WHATSAPP_ACCESS_TOKEN = mesmo token Meta (Cloud API) — pode reutilizar META_ACCESS_TOKEN
|
|
501
509
|
# WHATSAPP_PHONE_NUMBER_ID = mesmo {PHONE_ID} descoberto acima
|
|
502
|
-
echo "{META_ACCESS_TOKEN}" | wrangler secret put
|
|
510
|
+
echo "{META_ACCESS_TOKEN}" | wrangler secret put WHATSAPP_ACCESS_TOKEN
|
|
503
511
|
echo "{PHONE_ID}" | wrangler secret put WHATSAPP_PHONE_NUMBER_ID
|
|
504
512
|
|
|
505
513
|
# Confirmar todos
|
|
@@ -510,15 +518,15 @@ Secrets esperados no worker ao final:
|
|
|
510
518
|
```
|
|
511
519
|
META_ACCESS_TOKEN
|
|
512
520
|
META_APP_SECRET
|
|
513
|
-
|
|
514
|
-
|
|
521
|
+
WHATSAPP_ACCESS_TOKEN
|
|
522
|
+
WHATSAPP_PHONE_NUMBER_ID
|
|
515
523
|
WA_WEBHOOK_VERIFY_TOKEN
|
|
516
524
|
WHATSAPP_BUSINESS_ACCOUNT_ID
|
|
517
|
-
|
|
518
|
-
WHATSAPP_PHONE_NUMBER_ID ← auto-resposta outbound (mesmo valor de
|
|
525
|
+
WHATSAPP_ACCESS_TOKEN ← auto-resposta outbound (mesmo valor de META_ACCESS_TOKEN)
|
|
526
|
+
WHATSAPP_PHONE_NUMBER_ID ← auto-resposta outbound (mesmo valor de WHATSAPP_PHONE_NUMBER_ID)
|
|
519
527
|
```
|
|
520
528
|
|
|
521
|
-
> **Nota:** `
|
|
529
|
+
> **Nota:** `WHATSAPP_ACCESS_TOKEN` e `WHATSAPP_PHONE_NUMBER_ID` são usados pela função de auto-resposta no worker (envio de mensagens de saída para o lead após eventos de conversão). São o mesmo token/phone_id da CTWA — apenas referenciados por nomes distintos no código.
|
|
522
530
|
|
|
523
531
|
---
|
|
524
532
|
|
|
@@ -603,13 +611,13 @@ App: {META_APP_ID} — subscriptions: messages ✅
|
|
|
603
611
|
|
|
604
612
|
SECRETS NO WORKER:
|
|
605
613
|
✅ META_ACCESS_TOKEN
|
|
606
|
-
✅
|
|
607
|
-
✅
|
|
614
|
+
✅ WHATSAPP_ACCESS_TOKEN
|
|
615
|
+
✅ WHATSAPP_PHONE_NUMBER_ID → {PHONE_ID}
|
|
608
616
|
✅ WA_WEBHOOK_VERIFY_TOKEN
|
|
609
617
|
✅ WHATSAPP_BUSINESS_ACCOUNT_ID → {WABA_ID}
|
|
610
618
|
✅ META_APP_SECRET
|
|
611
|
-
✅
|
|
612
|
-
✅ WHATSAPP_PHONE_NUMBER_ID → mesmo valor de
|
|
619
|
+
✅ WHATSAPP_ACCESS_TOKEN → mesmo valor de META_ACCESS_TOKEN (auto-resposta)
|
|
620
|
+
✅ WHATSAPP_PHONE_NUMBER_ID → mesmo valor de WHATSAPP_PHONE_NUMBER_ID (auto-resposta)
|
|
613
621
|
|
|
614
622
|
TESTE E2E:
|
|
615
623
|
✅ GET verificação → challenge retornado
|