cdp-edge 2.5.6 → 2.5.7

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.
Files changed (60) hide show
  1. package/README.md +5 -8
  2. package/contracts/agent-versions.json +2 -2
  3. package/contracts/api-versions.json +8 -8
  4. package/extracted-skill/tracking-events-generator/INSTALACAO-CDPEDGE.md +2 -2
  5. package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +3 -3
  6. package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +1 -1
  7. package/extracted-skill/tracking-events-generator/SKILL.md +4 -4
  8. package/extracted-skill/tracking-events-generator/advanced-matching.js +1 -1
  9. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +3 -3
  10. package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +2 -2
  11. package/extracted-skill/tracking-events-generator/agents/code-guardian-agent.md +2 -2
  12. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +1 -1
  13. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +6 -6
  14. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +12 -12
  15. package/extracted-skill/tracking-events-generator/agents/match-quality-agent.md +1 -1
  16. package/extracted-skill/tracking-events-generator/agents/memory-agent.md +8 -8
  17. package/extracted-skill/tracking-events-generator/agents/meta-agent.md +8 -8
  18. package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +1 -1
  19. package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +1 -1
  20. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +1 -1
  21. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +9 -9
  22. package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +1 -1
  23. package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +5 -5
  24. package/extracted-skill/tracking-events-generator/agents/validator-agent.md +8 -8
  25. package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +4 -4
  26. package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +7 -7
  27. package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +16 -16
  28. package/extracted-skill/tracking-events-generator/agents/zapman-agent.md +189 -0
  29. package/extracted-skill/tracking-events-generator/cdpTrack.js +1 -1
  30. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +8 -8
  31. package/extracted-skill/tracking-events-generator/docs/guia-cloudflare-iniciante.md +2 -2
  32. package/extracted-skill/tracking-events-generator/evals/evals.json +5 -5
  33. package/extracted-skill/tracking-events-generator/knowledge-base.md +5 -5
  34. package/extracted-skill/tracking-events-generator/models/captura-de-lead.md +1 -1
  35. package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +1 -1
  36. package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +1 -1
  37. package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +5 -5
  38. package/extracted-skill/tracking-events-generator/models/pagina-obrigado.md +1 -1
  39. package/extracted-skill/tracking-events-generator/models/trafego-direto.md +4 -4
  40. package/extracted-skill/tracking-events-generator/models/webinar-registration.md +1 -1
  41. package/package.json +1 -1
  42. package/server-edge-tracker/INSTALAR.md +3 -3
  43. package/server-edge-tracker/index.ts +37 -36
  44. package/server-edge-tracker/modules/db.ts +1 -1
  45. package/server-edge-tracker/modules/dispatch/crm.ts +26 -363
  46. package/server-edge-tracker/modules/dispatch/meta.ts +2 -2
  47. package/server-edge-tracker/modules/dispatch/whatsapp.ts +7 -18
  48. package/server-edge-tracker/modules/intelligence.ts +4 -4
  49. package/server-edge-tracker/modules/nurture.ts +1 -1
  50. package/server-edge-tracker/schema.sql +1 -1
  51. package/server-edge-tracker/types.ts +6 -8
  52. package/server-edge-tracker/wrangler.toml +143 -140
  53. package/templates/captura-de-lead.md +1 -1
  54. package/templates/checkout-proprio.md +1 -1
  55. package/templates/lancamento-imobiliario.md +1 -1
  56. package/templates/multi-step-checkout.md +5 -5
  57. package/templates/pagina-obrigado.md +1 -1
  58. package/templates/trafego-direto.md +4 -4
  59. package/templates/webinar-registration.md +1 -1
  60. package/extracted-skill/tracking-events-generator/agents/evo-crm-agent.md +0 -253
@@ -1,382 +1,45 @@
1
1
  /**
2
- * CDP Edge — EVO CRM Premium Integration
3
- * Fluxo: Meta CAPI Worker Contato + Conversa + Nota interna no EVO CRM
2
+ * CDP Edge — ZapMan SDR Integration
3
+ * Cria lead direto no Kanban do ZapMan SDR via API.
4
4
  *
5
5
  * Secrets necessários (wrangler secret put):
6
- * EVO_CRM_BASE_URL → URL base do EVO CRM (ex: https://api-evocrm.suaempresa.com)
7
- * EVO_CRM_CLIENT_ID OAuth client_id (Doorkeeper app no CRM)
8
- * EVO_CRM_CLIENT_SECRET OAuth client_secret
9
- * EVO_CRM_INBOX_ID → ID do inbox onde as conversas serão criadas
10
- *
11
- * Secrets opcionais (defaults BR):
12
- * EVO_CRM_DEFAULT_COUNTRY → Dial code para números locais sem +cc (default "55")
13
- * EVO_CRM_LOCALE → "pt-BR" | "en-US" | "es-ES" (default "pt-BR")
14
- *
15
- * Uso (qualquer origem de lead):
16
- * await pushLeadToCrm(env, {
17
- * phone: '5511999990000',
18
- * name: 'João Silva',
19
- * email: 'joao@exemplo.com',
20
- * utmSource: 'facebook',
21
- * utmCampaign: 'campanha-x',
22
- * fbclid: 'AbC123...',
23
- * intentScore: 85,
24
- * ltvClass: 'high',
25
- * pageUrl: 'https://exemplo.com/lp',
26
- * });
6
+ * ZAPMAN_API_URL Base URL: https://zapman-api.arkitekt.space
7
+ * ZAPMAN_API_KEY DASHBOARD_SECRET do ZapMan (X-API-Key)
8
+ * ZAPMAN_CRM_INSTANCE ID da instância ZapMan (ex: minha-instancia)
27
9
  */
28
10
 
29
11
  import { Env } from '../../types.js';
30
12
 
31
- // ── Tipos públicos ────────────────────────────────────────────────────────────
32
-
33
- export interface CrmLeadData {
34
- // Identificação
35
- phone: string;
36
- name?: string | null;
37
- email?: string | null;
38
-
39
- // Meta CAPI
40
- fbclid?: string | null;
41
- fbc?: string | null;
42
- fbp?: string | null;
43
- ctwaClid?: string | null;
44
- adId?: string | null;
45
- messageBody?: string | null;
46
- headline?: string | null;
47
-
48
- // UTMs
49
- utmSource?: string | null;
50
- utmMedium?: string | null;
51
- utmCampaign?: string | null;
52
- utmContent?: string | null;
53
- utmTerm?: string | null;
54
-
55
- // Contexto
56
- eventName?: string | null;
57
- pageUrl?: string | null;
58
- formName?: string | null;
59
-
60
- // Scoring (Quantum Tracking)
61
- intentScore?: number | null;
62
- ltvClass?: string | null;
63
- funnelStage?: string | null;
64
- botScore?: number | null;
65
-
66
- // Monetário
67
- value?: number | null;
68
- currency?: string | null;
13
+ // ── ZapMan CRM — cria lead direto no Kanban do ZapMan SDR ────────────────────
69
14
 
70
- // Atributos livres adicionais
71
- attributes?: Record<string, string>;
72
- }
73
-
74
- /** @deprecated Use CrmLeadData + pushLeadToCrm */
75
- export interface CTWALeadData {
76
- phone: string;
77
- name?: string | null;
78
- messageBody?: string | null;
79
- ctwaClid?: string | null;
80
- adId?: string | null;
81
- sourceUrl?: string | null;
82
- headline?: string | null;
83
- wamid?: string | null;
84
- }
85
-
86
- /** @deprecated Use CrmLeadData + pushLeadToCrm */
87
- export interface FormLeadData {
15
+ export async function pushLeadToZapmanCrm(env: Env, data: {
88
16
  phone: string;
89
17
  name?: string | null;
90
- email?: string | null;
91
- formName?: string | null;
92
- utmSource?: string | null;
93
- utmCampaign?: string | null;
94
- pageUrl?: string | null;
95
- }
96
-
97
- // ── Helpers internos ──────────────────────────────────────────────────────────
98
-
99
- function isCrmConfigured(env: Env): boolean {
100
- return !!(env.EVO_CRM_BASE_URL && env.EVO_CRM_CLIENT_ID && env.EVO_CRM_CLIENT_SECRET);
101
- }
18
+ email?: string;
19
+ empresa?: string;
20
+ campanha?: string;
21
+ origem?: string;
22
+ }): Promise<void> {
23
+ if (!env.ZAPMAN_API_URL || !env.ZAPMAN_API_KEY) return;
102
24
 
103
- function normalizePhone(phone: string, defaultCountryCode = '55'): string {
104
- const trimmed = phone.trim();
105
- const cc = (defaultCountryCode || '55').replace(/\D/g, '') || '55';
106
-
107
- // Already in E.164 (starts with +): só limpa e re-prefixa
108
- if (trimmed.startsWith('+')) return '+' + trimmed.replace(/\D/g, '');
109
-
110
- const digits = trimmed.replace(/\D/g, '');
111
-
112
- // Comportamento BR canônico (preservado): 55 + 10 ou 11 dígitos = válido
113
- if (cc === '55' && digits.startsWith('55') && (digits.length === 12 || digits.length === 13)) {
114
- return `+${digits}`;
115
- }
116
- if (cc === '55' && (digits.length === 10 || digits.length === 11)) {
117
- return `+55${digits}`;
118
- }
119
-
120
- // Genérico: já tem o country code
121
- if (digits.startsWith(cc) && digits.length > cc.length + 6) return `+${digits}`;
122
-
123
- // Genérico: número local → prepend country code
124
- if (digits.length >= 7 && digits.length <= 11) return `+${cc}${digits}`;
125
-
126
- // Fallback: assume que já tem algum cc
127
- return `+${digits}`;
128
- }
129
-
130
- // ── Localização da nota interna ───────────────────────────────────────────────
131
-
132
- type Locale = 'pt-BR' | 'en-US' | 'es-ES';
133
-
134
- const NOTE_LABELS: Record<Locale, Record<string, string>> = {
135
- 'pt-BR': {
136
- title: '📊 *Novo Lead*',
137
- name: 'Nome',
138
- source: 'Origem',
139
- campaign: 'Campanha',
140
- form: 'Formulário',
141
- ad: 'Anúncio',
142
- message: 'Mensagem',
143
- score: 'Score',
144
- ltv: 'LTV',
145
- },
146
- 'en-US': {
147
- title: '📊 *New Lead*',
148
- name: 'Name',
149
- source: 'Source',
150
- campaign: 'Campaign',
151
- form: 'Form',
152
- ad: 'Ad',
153
- message: 'Message',
154
- score: 'Score',
155
- ltv: 'LTV',
156
- },
157
- 'es-ES': {
158
- title: '📊 *Nuevo Lead*',
159
- name: 'Nombre',
160
- source: 'Origen',
161
- campaign: 'Campaña',
162
- form: 'Formulario',
163
- ad: 'Anuncio',
164
- message: 'Mensaje',
165
- score: 'Score',
166
- ltv: 'LTV',
167
- },
168
- };
169
-
170
- function resolveLocale(input?: string | null): Locale {
171
- if (input && input in NOTE_LABELS) return input as Locale;
172
- return 'pt-BR';
173
- }
174
-
175
- async function getAccessToken(env: Env): Promise<string | null> {
176
25
  try {
177
- const res = await fetch(`${env.EVO_CRM_BASE_URL}/oauth/token`, {
26
+ await fetch(`${env.ZAPMAN_API_URL}/crm/leads`, {
178
27
  method: 'POST',
179
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
180
- body: new URLSearchParams({
181
- grant_type: 'client_credentials',
182
- client_id: env.EVO_CRM_CLIENT_ID!,
183
- client_secret: env.EVO_CRM_CLIENT_SECRET!,
184
- }),
185
- });
186
- if (!res.ok) return null;
187
- const data: any = await res.json();
188
- return data.access_token ?? null;
189
- } catch {
190
- return null;
191
- }
192
- }
193
-
194
- /** Nota interna para o agente: apenas o essencial para atender o lead. */
195
- function buildAgentNote(data: CrmLeadData, locale: Locale = 'pt-BR'): string {
196
- const L = NOTE_LABELS[locale];
197
- const lines: string[] = [L.title];
198
-
199
- const name = data.name || data.phone;
200
- lines.push(`• ${L.name}: ${name}`);
201
-
202
- const source = [data.utmSource, data.utmMedium].filter(Boolean).join(' / ');
203
- if (source) lines.push(`• ${L.source}: ${source}`);
204
-
205
- if (data.utmCampaign) lines.push(`• ${L.campaign}: ${data.utmCampaign}`);
206
- if (data.formName && data.formName !== data.eventName) lines.push(`• ${L.form}: ${data.formName}`);
207
- if (data.headline) lines.push(`• ${L.ad}: ${data.headline}`);
208
- if (data.messageBody) lines.push(`• ${L.message}: "${data.messageBody}"`);
209
-
210
- if (data.intentScore != null) {
211
- const score = data.intentScore > 1 ? data.intentScore : Math.round(data.intentScore * 100);
212
- const stage = data.funnelStage ? ` · ${data.funnelStage}` : '';
213
- lines.push(`• ${L.score}: ${score}${stage}`);
214
- }
215
- if (data.ltvClass) lines.push(`• ${L.ltv}: ${data.ltvClass}`);
216
-
217
- return lines.join('\n');
218
- }
219
-
220
- /** Monta additional_attributes para o contato no CRM. */
221
- function buildContactAttributes(data: CrmLeadData): Record<string, string> {
222
- const attrs: Record<string, string> = {};
223
-
224
- if (data.utmSource) attrs['utm_source'] = data.utmSource;
225
- if (data.utmMedium) attrs['utm_medium'] = data.utmMedium;
226
- if (data.utmCampaign) attrs['utm_campaign'] = data.utmCampaign;
227
- if (data.utmContent) attrs['utm_content'] = data.utmContent;
228
- if (data.utmTerm) attrs['utm_term'] = data.utmTerm;
229
- if (data.pageUrl) attrs['pagina'] = data.pageUrl;
230
- if (data.formName) attrs['formulario'] = data.formName;
231
- if (data.fbclid) attrs['fbclid'] = data.fbclid;
232
- if (data.fbc) attrs['fbc'] = data.fbc;
233
- if (data.fbp) attrs['fbp'] = data.fbp;
234
- if (data.ctwaClid) attrs['ctwa_clid'] = data.ctwaClid;
235
- if (data.adId) attrs['ad_id'] = data.adId;
236
- if (data.messageBody) attrs['mensagem'] = data.messageBody;
237
- if (data.headline) attrs['anuncio'] = data.headline;
238
- if (data.ltvClass) attrs['ltv_class'] = data.ltvClass;
239
- if (data.funnelStage) attrs['funil'] = data.funnelStage;
240
- if (data.intentScore != null) attrs['intencao'] = String(data.intentScore);
241
- if (data.eventName) attrs['evento'] = data.eventName;
242
-
243
- // Atributos livres
244
- if (data.attributes) Object.assign(attrs, data.attributes);
245
-
246
- return attrs;
247
- }
248
-
249
- // ── API principal (recomendada) ───────────────────────────────────────────────
250
-
251
- /**
252
- * Cria contato + conversa aberta + nota interna no EVO CRM.
253
- * Silencioso se os secrets não estiverem configurados.
254
- * Retorna o ID do contato criado ou null em caso de erro/duplicata.
255
- */
256
- export async function pushLeadToCrm(env: Env, data: CrmLeadData): Promise<string | null> {
257
- if (!isCrmConfigured(env)) return null;
258
-
259
- const token = await getAccessToken(env);
260
- if (!token) {
261
- console.warn('[EVO CRM] Failed to get access token');
262
- return null;
263
- }
264
-
265
- const locale = resolveLocale(env.EVO_CRM_LOCALE);
266
- const defaultCountry = env.EVO_CRM_DEFAULT_COUNTRY || '55';
267
-
268
- const attrs = buildContactAttributes(data);
269
- const contactPayload: Record<string, any> = {
270
- name: data.name || data.phone,
271
- phone_number: normalizePhone(data.phone, defaultCountry),
272
- };
273
- if (data.email) contactPayload.email = data.email;
274
- if (Object.keys(attrs).length) contactPayload.additional_attributes = attrs;
275
-
276
- // 1. Criar contato
277
- let contactId: string | null = null;
278
- try {
279
- const res = await fetch(`${env.EVO_CRM_BASE_URL}/api/v1/contacts`, {
280
- method: 'POST',
281
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
282
- body: JSON.stringify(contactPayload),
283
- });
284
- if (!res.ok) {
285
- const body = await res.text();
286
- console.warn('[EVO CRM] createContact non-ok:', res.status, body.slice(0, 200));
287
- // 422 = contato já existe — tentar extrair o ID do payload de erro
288
- if (res.status === 422) {
289
- try {
290
- const errJson: any = JSON.parse(body);
291
- const rawId = errJson?.id ?? errJson?.data?.id ?? errJson?.contact?.id ?? errJson?.data?.contact?.id;
292
- if (rawId != null) contactId = String(rawId);
293
- } catch { /* body não é JSON */ }
294
- }
295
- if (!contactId) return null;
296
- } else {
297
- const result: any = await res.json();
298
- // EVO CRM pode retornar { id } direto ou { data: { id } } ou { data: { contact: { id } } }
299
- const rawId = result?.id ?? result?.data?.id ?? result?.data?.contact?.id;
300
- contactId = rawId != null ? String(rawId) : null;
301
- }
302
- } catch (err: any) {
303
- console.warn('[EVO CRM] createContact failed:', err?.message || String(err));
304
- return null;
305
- }
306
-
307
- if (!contactId || !env.EVO_CRM_INBOX_ID) return contactId;
308
-
309
- // 2. Criar conversa
310
- let conversationId: string | null = null;
311
- try {
312
- const res = await fetch(`${env.EVO_CRM_BASE_URL}/api/v1/conversations`, {
313
- method: 'POST',
314
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ 'X-API-Key': env.ZAPMAN_API_KEY,
31
+ },
315
32
  body: JSON.stringify({
316
- inbox_id: env.EVO_CRM_INBOX_ID,
317
- contact_id: contactId,
318
- additional_attributes: {},
33
+ telefone: data.phone,
34
+ nome: data.name || data.phone,
35
+ email: data.email || '',
36
+ empresa: data.empresa || '',
37
+ campanha: data.campanha || '',
38
+ origem: data.origem || 'whatsapp',
39
+ instancia_id: env.ZAPMAN_CRM_INSTANCE || '',
319
40
  }),
320
41
  });
321
- if (!res.ok) {
322
- const err = await res.text();
323
- console.warn('[EVO CRM] createConversation non-ok:', res.status, err.slice(0, 200));
324
- } else {
325
- const result: any = await res.json();
326
- const rawConvId = result?.id ?? result?.data?.id;
327
- conversationId = rawConvId != null ? String(rawConvId) : null;
328
- }
329
42
  } catch (err: any) {
330
- console.warn('[EVO CRM] createConversation failed:', err?.message || String(err));
43
+ console.error('[ZapMan CRM] Erro ao criar lead:', err?.message || String(err));
331
44
  }
332
-
333
- // 3. Criar nota interna com contexto do lead
334
- if (conversationId) {
335
- try {
336
- await fetch(`${env.EVO_CRM_BASE_URL}/api/v1/conversations/${conversationId}/messages`, {
337
- method: 'POST',
338
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
339
- body: JSON.stringify({
340
- content: buildAgentNote(data, locale),
341
- message_type: 'activity',
342
- private: true,
343
- }),
344
- });
345
- } catch {
346
- // nota interna é best-effort
347
- }
348
- }
349
-
350
- return contactId;
351
- }
352
-
353
- // ── Compat: CTWA (WhatsApp click-to-chat) ────────────────────────────────────
354
-
355
- export async function notifyEvolutionCTWA(env: Env, data: CTWALeadData): Promise<void> {
356
- await pushLeadToCrm(env, {
357
- phone: data.phone,
358
- name: data.name,
359
- messageBody: data.messageBody,
360
- ctwaClid: data.ctwaClid,
361
- adId: data.adId,
362
- pageUrl: data.sourceUrl,
363
- headline: data.headline,
364
- utmSource: 'whatsapp',
365
- eventName: 'CTWA',
366
- });
367
- }
368
-
369
- // ── Compat: Formulário ────────────────────────────────────────────────────────
370
-
371
- export async function notifyEvolutionForm(env: Env, data: FormLeadData): Promise<void> {
372
- await pushLeadToCrm(env, {
373
- phone: data.phone,
374
- name: data.name,
375
- email: data.email,
376
- formName: data.formName,
377
- utmSource: data.utmSource,
378
- utmCampaign: data.utmCampaign,
379
- pageUrl: data.pageUrl,
380
- eventName: 'Lead',
381
- });
382
45
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CDP Edge — Meta Conversions API v22.0
2
+ * CDP Edge — Meta Conversions API v25.0
3
3
  * Envia eventos server-side para a Meta CAPI.
4
4
  */
5
5
 
@@ -104,7 +104,7 @@ export async function sendMetaCapi(env: Env, eventName: string, payload: TrackPa
104
104
  logMatchQuality(env.DB, eventName, payload, recovered).catch(() => {});
105
105
  }
106
106
 
107
- const endpoint = `https://graph.facebook.com/v22.0/${env.META_PIXEL_ID}/events`;
107
+ const endpoint = `https://graph.facebook.com/v25.0/${env.META_PIXEL_ID}/events`;
108
108
 
109
109
  try {
110
110
  const res = await fetch(endpoint, {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CDP Edge — WhatsApp Cloud API v22.0 + HMAC Verification
2
+ * CDP Edge — WhatsApp Cloud API v25.0 + HMAC Verification
3
3
  * sendWhatsApp, processWhatsAppWebhook, verifyHmac, sendCallMeBot
4
4
  */
5
5
 
@@ -7,7 +7,7 @@ import { sha256, normalizePhone } from '../utils.js';
7
7
  import { saveLead, logApiFailure } from '../db.js';
8
8
  import { Env, TrackPayload } from '../../types.js';
9
9
  import { ExecutionContext } from '@cloudflare/workers-types';
10
- import { notifyEvolutionCTWA } from './crm.js';
10
+ import { pushLeadToZapmanCrm } from './crm.js';
11
11
 
12
12
  // ── Tipos ───────────────────────────────────────────────────────────────────────
13
13
  interface WhatsAppOptions {
@@ -42,7 +42,7 @@ interface WhatsAppMessage {
42
42
  }
43
43
 
44
44
  // ── Resolvedores de secrets (canônico + legado) ────────────────────────────────
45
- // Meta Cloud API v22.0 usa PHONE_NUMBER_ID e ACCESS_TOKEN como termos oficiais.
45
+ // Meta Cloud API v25.0 usa PHONE_NUMBER_ID e ACCESS_TOKEN como termos oficiais.
46
46
  // Suportamos ambos os nomes para compatibilidade com secrets já configurados.
47
47
  function resolvePhoneNumberId(env: Env): string | undefined {
48
48
  return env.WHATSAPP_PHONE_NUMBER_ID || env.WA_PHONE_ID;
@@ -129,7 +129,7 @@ async function _sendWARequest(env: Env, body: Record<string, any>): Promise<any>
129
129
  try {
130
130
  const phoneNumberId = resolvePhoneNumberId(env);
131
131
  const accessToken = resolveAccessToken(env);
132
- const res = await fetch(`https://graph.facebook.com/v22.0/${phoneNumberId}/messages`, {
132
+ const res = await fetch(`https://graph.facebook.com/v25.0/${phoneNumberId}/messages`, {
133
133
  method: 'POST',
134
134
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` },
135
135
  body: JSON.stringify(body),
@@ -223,7 +223,7 @@ export async function processWhatsAppWebhook(env: Env, body: any, request: Reque
223
223
  if (env.META_TEST_CODE) requestBody.test_event_code = env.META_TEST_CODE;
224
224
 
225
225
  const res = await fetch(
226
- `https://graph.facebook.com/v22.0/${env.META_PIXEL_ID}/events`,
226
+ `https://graph.facebook.com/v25.0/${env.META_PIXEL_ID}/events`,
227
227
  { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody) }
228
228
  );
229
229
  const data = await res.json();
@@ -249,20 +249,9 @@ export async function processWhatsAppWebhook(env: Env, body: any, request: Reque
249
249
  }, request, 'whatsapp')
250
250
  );
251
251
 
252
- // ── Notifica o Evolution CRM sobre o novo lead CTWA ──────────────────────
253
- // Cria/atualiza o contato no Evolution e abre a conversa para o vendedor.
254
- // Silencioso se EVOLUTION_BASE_URL / EVOLUTION_INSTANCE / EVOLUTION_API_KEY
255
- // não estiverem configurados.
252
+ // ── ZapMan CRM cria lead direto no Kanban ──────────────────────────────
256
253
  ctx.waitUntil(
257
- notifyEvolutionCTWA(env, {
258
- phone: phoneNorm,
259
- messageBody: messageBody || undefined,
260
- ctwaClid,
261
- adId,
262
- sourceUrl,
263
- headline,
264
- wamid,
265
- })
254
+ pushLeadToZapmanCrm(env, { phone: phoneNorm, name: undefined, origem: 'whatsapp' })
266
255
  );
267
256
 
268
257
  results.push({ ok: true, phone: phoneNorm.slice(0, 4) + '****', ctwa_clid: ctwaClid ? 'present' : 'absent', event_id: eventId });
@@ -94,7 +94,7 @@ export interface GoogleCustomerMatchExport {
94
94
 
95
95
  // ── Versões esperadas das APIs ────────────────────────────────────────────────
96
96
  const EXPECTED_API_VERSIONS: Record<string, string> = {
97
- meta: 'v22.0',
97
+ meta: 'v25.0',
98
98
  ga4: 'latest',
99
99
  tiktok: 'v1.3',
100
100
  pinterest: 'v5',
@@ -126,7 +126,7 @@ export async function checkApiVersionsIntelligence(
126
126
  const results: ApiVersionCheck[] = [];
127
127
 
128
128
  for (const [platform, expected] of Object.entries(EXPECTED_API_VERSIONS)) {
129
- const currentMap: Record<string, string> = { meta: 'v22.0', tiktok: 'v1.3', ga4: 'latest', pinterest: 'v5', reddit: 'v2.0' };
129
+ const currentMap: Record<string, string> = { meta: 'v25.0', tiktok: 'v1.3', ga4: 'latest', pinterest: 'v5', reddit: 'v2.0' };
130
130
  const current = currentMap[platform] || 'unknown';
131
131
  const isOk = current === expected || expected === 'latest';
132
132
  const status = isOk ? 'ok' : 'warning';
@@ -436,7 +436,7 @@ export async function syncMetaCustomAudience(env: Env): Promise<CustomerMatchRes
436
436
  );
437
437
 
438
438
  const body = { payload: { schema: ['EMAIL_SHA256', 'PHONE_SHA256'], data } };
439
- const endpoint = `https://graph.facebook.com/v22.0/${env.META_AUDIENCE_ID}/users`;
439
+ const endpoint = `https://graph.facebook.com/v25.0/${env.META_AUDIENCE_ID}/users`;
440
440
 
441
441
  const res = await fetch(endpoint, {
442
442
  method: 'POST',
@@ -506,7 +506,7 @@ export async function syncMetaLookalikeSeed(env: Env): Promise<{
506
506
  );
507
507
 
508
508
  const body = { payload: { schema: ['EMAIL_SHA256', 'PHONE_SHA256'], data } };
509
- const endpoint = `https://graph.facebook.com/v22.0/${env.META_AUDIENCE_ID}/users`;
509
+ const endpoint = `https://graph.facebook.com/v25.0/${env.META_AUDIENCE_ID}/users`;
510
510
 
511
511
  const res = await fetch(endpoint, {
512
512
  method: 'POST',
@@ -201,7 +201,7 @@ export async function runNurtureQueue(env: Env): Promise<NurtureRunResult> {
201
201
  const e164 = digits.startsWith('55') ? `+${digits}` : `+55${digits}`;
202
202
 
203
203
  const res = await fetch(
204
- `https://graph.facebook.com/v22.0/${env.WHATSAPP_PHONE_NUMBER_ID}/messages`,
204
+ `https://graph.facebook.com/v25.0/${env.WHATSAPP_PHONE_NUMBER_ID}/messages`,
205
205
  {
206
206
  method: 'POST',
207
207
  headers: { 'Authorization': `Bearer ${env.WHATSAPP_ACCESS_TOKEN}`, 'Content-Type': 'application/json' },
@@ -198,7 +198,7 @@ CREATE INDEX IF NOT EXISTS idx_intel_logs_status ON intelligence_logs(status)
198
198
  CREATE INDEX IF NOT EXISTS idx_intel_logs_platform ON intelligence_logs(platform);
199
199
 
200
200
  -- ── Meta Ads Dashboard — Tabelas (conectadas ao mesmo D1) ────────────────────
201
- -- Alimentadas pelo sync diário da Meta Marketing API v22.0
201
+ -- Alimentadas pelo sync diário da Meta Marketing API v25.0
202
202
 
203
203
  CREATE TABLE IF NOT EXISTS meta_account (
204
204
  account_id TEXT PRIMARY KEY,
@@ -36,7 +36,7 @@ export interface Env {
36
36
  GA4_API_SECRET?: string;
37
37
  TIKTOK_ACCESS_TOKEN?: string;
38
38
  WA_WEBHOOK_VERIFY_TOKEN?: string;
39
- // WhatsApp Cloud API — nomes canônicos (Meta Cloud API v22.0)
39
+ // WhatsApp Cloud API — nomes canônicos (Meta Cloud API v25.0)
40
40
  WHATSAPP_ACCESS_TOKEN?: string; // canonical: Bearer token do System User
41
41
  WHATSAPP_PHONE_NUMBER_ID?: string; // canonical: ID numérico do número no Meta Business
42
42
  // WhatsApp Cloud API — nomes legados (backwards compat)
@@ -65,13 +65,11 @@ export interface Env {
65
65
  RESEND_FROM_EMAIL?: string;
66
66
  CALLMEBOT_APIKEY?: string;
67
67
 
68
- // EVO CRMOAuth2 client_credentials
69
- EVO_CRM_BASE_URL?: string; // URL base do EVO CRM (ex: https://api-evocrm.suaempresa.com)
70
- EVO_CRM_CLIENT_ID?: string; // OAuth client_id (Doorkeeper app)
71
- EVO_CRM_CLIENT_SECRET?: string; // OAuth client_secret
72
- EVO_CRM_INBOX_ID?: string; // ID do inbox onde as conversas serão criadas
73
- EVO_CRM_DEFAULT_COUNTRY?: string; // Country dial code para phones locais (default "55" = Brasil)
74
- EVO_CRM_LOCALE?: string; // Locale da nota interna: "pt-BR" | "en-US" | "es-ES" (default "pt-BR")
68
+ // ZapMan SDRforward WhatsApp webhooks para qualificação de leads
69
+ ZAPMAN_WEBHOOK_URL?: string; // URL completa: https://zapman-api.arkitekt.space/webhook/{instance_id}?token={secret}
70
+ ZAPMAN_API_URL?: string; // Base URL do ZapMan: https://zapman-api.arkitekt.space
71
+ ZAPMAN_API_KEY?: string; // DASHBOARD_SECRET do ZapMan (X-API-Key)
72
+ ZAPMAN_CRM_INSTANCE?: string; // ID da instância ZapMan para associar o lead (ex: Ramon-SDR)
75
73
 
76
74
  // Fraud Gate — defaults parametrizáveis por projeto (vazio = comportamento legado)
77
75
  ALLOWED_COUNTRIES?: string; // CSV ISO-2, ex: "BR" ou "BR,PT,AO". Vazio = sem geo-fence