ТЗ v2: передача підтверджених покупок у Meta / GA4 / Google Ads

Дві серверні події з CRM · Лавка Молфара · 24.06.2026 · розширення ТЗ «Qualified Purchase» · для розробника CRM + інженера GTM/сайту
⚠️ Безпека: зробити в першу чергу. У вихідному ТЗ лежали живі токени відкритим текстом (Meta access_token, Google Ads developer/refresh/client_secret, GA4 api_secret). Вважати їх скомпрометованими. Ротувати всі, тримати лише в серверних змінних оточення / secret-менеджері. У прикладах нижче токени подані як {{ENV}}.

1. Мета та рамки

2. Що змінилось проти v1

Параметр❌ v1✅ v2
Джерело тригерастатус у OpenCartстатус у CRM (SuiteCRM)
Скільки подійоднадві (в обробці + викуп)
Сума (value)на момент оформленняфінальна, з допродажами
Telegramне передавалисьпередаються (через CRM)
Google conversionActionхибний ID 110221645032 нові Import-дії (створено)
3 API, дедуп, хешування— без змін —те саме з v1

3. Архітектура потоку

🅰 Сайтреклама → GTM ловить utm/gclid/gbraid/wbraid/fbclid/_ga → OpenCart → CRM
🅱 Telegramреклама → tg.pulse.is з мітками → SendPulse → менеджер переносить у CRM
↘  обидва входи сходяться  ↙
CRM (SuiteCRM): один запис на order_idатрибуція + товари + клієнт + фінальна сума + статус + флаги
Подія 1 на статусі «в обробці»sender шле Meta + GA4 + Google OCI
Подія 2 на статусі «викуп»sender шле Meta + GA4 + Google OCI (фінальна сума)

4. Логіка статусів

ПодіяТригер (статус CRM)value
Подія 1 PurchaseConfirmed_POST
підтверджено, в роботі
ЗАПОВНИТИ: назва статусуvalue_processing
Подія 2 QualifiedPurchase_POST
реальний викуп, закрито
ЗАПОВНИТИ: назва статусуvalue_final (з допродажами)
Деталізація тригера Події 2 (з вихідного ТЗ): Подія 2 спрацьовує на статусі реального отримання грошей: Що настане раніше, те й тригерить Подію 2. Подія 1 = раніший статус «підтверджено / в обробці» (новий сигнал, якого в v1 не було). Точні назви статусів у SuiteCRM ЗАПОВНИТИ.

Обидві події незалежні, кожна один раз (флаги e1_* / e2_*). event_time / conversionDateTime = момент зміни статусу в CRM (не дата замовлення), тому подія завжди свіжа.

5. Ідентифікатори подій і конверсійні дії

Подія 1Подія 2
Meta event_namePurchaseConfirmed_POSTQualifiedPurchase_POST
Meta event_idpurchase_confirmed_<order_id>qualified_purchase_<order_id>
GA4 eventpurchase_confirmed_postqualified_purchase_post
GA4 transaction_id<order_id><order_id>
Google conversionAction76608035527660805253
valuevalue_processingvalue_final
Google Ads (створено через API 24.06.2026): дві дії типу UPLOAD_CLICKS, PURCHASE, counting Every, вікно 90 днів, value по завантаженню. Обидві Secondary (primary_for_goal=false), у ставки не входять (бідинг на wGTM / Purchase 7590805370 не чіпаємо). Стара POST / Qualified Purchase (7606114302) = WEBPAGE, для OCI не годиться. ID 11022164503 з v1 = AW- gtag id, не conversion action.

6. Захоплення атрибуції

6.1 Сайт: UTM Keeper через GTM (lm-utm-keeper-gtm.js)

Ловить utm_* + click ID (gclid/gbraid/wbraid/fbclid/igclid/ttclid/msclkid) + ga_client_id з _ga. Фолбек gclid з _gcl_aw, відновлює _fbc. TTL 90 днів, переживає навігацію. Віддає мітки через window.lmGetTracking() для прихованих полів форми OpenCart.

6.2 Telegram (lm-telegram-buttons.js, заміна старого)

Знаходить посилання на бота по href (t.me/Molfar_Support_Bot, клас не потрібен), переписує на tg.pulse.is з мітками. Канал та інші боти не чіпає. SendPulse: завести змінні контакту gbraid, wbraid, fbclid, ga_client_id, fbc (на додачу до utm + gclid). Менеджер переносить мітки в CRM (поки руками).

Перевірено вживу (Playwright, 24.06.2026): Keeper читає реальні _ga / _gcl_aw / _fbc, усі гілки логіки працюють; TG-скрипт переписав 7/7 бот-посилань, ланцюг доїхав до Telegram через SendPulse. Старий скрипт цілився в клас .tg-button, якого на сайті 0.

7. Що зберігаємо в CRM

7.1 Ідентифікатори та атрибуція

ПолеДжерелоНавіщо
order_idCRMGA4 transaction_id; Meta event_id; Ads orderId
created_at, statusCRMконтроль затримок; тригер Подій 1/2
ga_client_id_gaобовʼязково для GA4 MP
gclid / gbraid / wbraidURL / cookieтільки для Ads OCI
fbp, fbc, fbclidcookie / URLMeta match (fbc з fbclid якщо нема)
utm_*URLаналітика
event_source_url, user_agent, ipсайт / headerMeta (website)

7.2 PII для Meta user_data

email, phone, first_name, last_name, city, state, zip, country, customer_idнормалізуємо → SHA-256 (lowercase/trim; телефон строго E.164).

7.3 Склад замовлення + флаги

currency (UAH), value_processing (Подія 1), value_final з допродажами (Подія 2), items[] (GA4), contents[] (Meta). Флаги: e1_meta_sent / e1_ga4_sent / e1_ads_sent / e2_meta_sent / e2_ga4_sent / e2_ads_sent.

7.4 Карточка ліда (еталон запису в CRM)

{
  "order_id": "LM-100500",
  "created_at": "2025-10-12T16:22:31Z",
  "status": "confirmed",
  "currency": "UAH",
  "value_processing": 1490.00,
  "value_final": 1890.00,
  "items": [
    {"id": "112", "name": "Гриб Левиний Гриб 60 кап",   "quantity": 1, "price": 890.00},
    {"id": "88",  "name": "Адаптоген Ашваганда 30 кап", "quantity": 1, "price": 600.00}
  ],
  "customer_raw": {
    "email": "client@example.com", "phone": "+380991234567",
    "first_name": "Олена", "last_name": "Коваль",
    "city": "Київ", "state": "", "zip": "04050", "country": "UA",
    "customer_id": "CUST-100500"
  },
  "attribution": {
    "ga_client_id": "1865432100.987654321",
    "gclid": "EAIaIQ...", "gbraid": null, "wbraid": null,
    "fbp": "fb.1.1728735751000.3456789012",
    "fbc": "fb.1.1728735755000.AbCdEfGhIjKlMnOp",
    "fbclid": "AbCdEfGhIjKlMnOp",
    "event_source_url": "https://lavka-molfara.com.ua/checkout/success/",
    "landing_page": "https://lavka-molfara.com.ua/",
    "referrer": "https://www.facebook.com/",
    "utm_source": "facebook", "utm_medium": "cpc", "utm_campaign": "lm_conversion",
    "user_agent": "Mozilla/5.0 ...", "ip": "203.0.113.10"
  },
  "flags": {
    "e1_meta_sent": false, "e1_ga4_sent": false, "e1_ads_sent": false,
    "e2_meta_sent": false, "e2_ga4_sent": false, "e2_ads_sent": false
  }
}

8. Повні payload-и

Приклади для Події 2 (QualifiedPurchase). Для Події 1 підставити значення Події 1 з таблиці розділу 5 (event_name/event_id/name/conversionAction/value).

8.1 Meta Conversions API (CAPI)

curl -X POST "https://graph.facebook.com/v21.0/1849940369742660/events?access_token={{META_ACCESS_TOKEN}}" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [{
      "event_name": "QualifiedPurchase_POST",
      "event_time": 1761440100,
      "action_source": "website",
      "event_source_url": "https://lavka-molfara.com.ua/checkout/success/",
      "event_id": "qualified_purchase_LM-100500",
      "user_data": {
        "em": ["<sha256(client@example.com)>"],
        "ph": ["<sha256(+380991234567)>"],
        "fn": ["<sha256(олена)>"], "ln": ["<sha256(коваль)>"],
        "ct": ["<sha256(київ)>"], "zp": ["<sha256(04050)>"],
        "country": ["<sha256(ua)>"],
        "external_id": ["<sha256(1865432100.987654321)>"],
        "client_ip_address": "203.0.113.10",
        "client_user_agent": "Mozilla/5.0 ...",
        "fbp": "fb.1.1728735751000.3456789012",
        "fbc": "fb.1.1728735755000.AbCdEfGhIjKlMnOp"
      },
      "custom_data": {
        "currency": "UAH", "value": 1890.00, "content_type": "product",
        "contents": [
          {"id": "112", "quantity": 1, "item_price": 890.00},
          {"id": "88",  "quantity": 1, "item_price": 600.00}
        ]
      }
    }]
  }'

Подія 1: event_name=PurchaseConfirmed_POST, event_id=purchase_confirmed_LM-100500, value=value_processing. Для TG-замовлень ip/ua/fbp можуть бути відсутні: матч по PII + fbc.

8.2 GA4 Measurement Protocol

curl -X POST "https://www.google-analytics.com/mp/collect?measurement_id=G-CQYZHNRVDB&api_secret={{GA4_API_SECRET}}" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "1865432100.987654321",
    "timestamp_micros": 1761440100000000,
    "events": [{
      "name": "qualified_purchase_post",
      "params": {
        "transaction_id": "LM-100500",
        "currency": "UAH", "value": 1890.00, "engagement_time_msec": 1,
        "items": [
          {"item_id": "112", "item_name": "Гриб Левиний Гриб 60 кап",   "price": 890.00, "quantity": 1},
          {"item_id": "88",  "item_name": "Адаптоген Ашваганда 30 кап", "price": 600.00, "quantity": 1}
        ]
      }
    }]
  }'

Подія 1: name=purchase_confirmed_post, value=value_processing. client_id обовʼязковий. timestamp_micros лише якщо ≤72год, інакше без нього.

8.3 Google Ads (OCI / Upload Click Conversions)

curl -X POST "https://googleads.googleapis.com/v22/customers/7699145794:uploadClickConversions" \
  -H "Authorization: Bearer {{ACCESS_TOKEN}}" \
  -H "developer-token: {{GOOGLE_ADS_DEVELOPER_TOKEN}}" \
  -H "login-customer-id: 1914648688" \
  -H "Content-Type: application/json" \
  -d '{
    "conversions": [{
      "gclid": "EAIaIQobChMIvJZz...",
      "conversionAction": "customers/7699145794/conversionActions/7660805253",
      "conversionDateTime": "2025-10-26 10:15:00+03:00",
      "currencyCode": "UAH",
      "conversionValue": 1890.00,
      "orderId": "LM-100500"
    }],
    "partialFailure": true
  }'

Подія 1: conversionAction=.../7660803552, conversionValue=value_processing. Рівно один з gclid / gbraid / wbraid.

8.4 Отримання access_token (перед кожним batch, токен живе ≤1 год)

curl -X POST "https://oauth2.googleapis.com/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id={{GOOGLE_ADS_CLIENT_ID}}&client_secret={{GOOGLE_ADS_CLIENT_SECRET}}&refresh_token={{GOOGLE_ADS_REFRESH_TOKEN}}&grant_type=refresh_token"

9. Маршрутизація та вікна

СистемаКолиУмоваКлюч дедупуВікно
Meta CAPIзавждибудь-яке підтвердженняevent_id (різний П1/П2)≤7 днів (event_time = момент статусу)
GA4 MPзавждибудь-яке підтвердженняtransaction_id = order_idbackdate ≤72год
Google Ads OCIумовноє gclid / gbraid / wbraidorderId = order_idклік ≤90 днів

10. Sender

11. Крайові сценарії

СценарійРішення
Подія 2: статус «Оплачено» → потім «Доставлено»Подія 2 відправляється на першому з них, флаг e2_* ставиться. На другому статусі флаг уже стоїть, пропускаємо (як у v1).
Тільки накладений платіж, статус «Доставлено»Подія 2 відправляється на «Доставлено».
Подія 1 надіслана, далі статус Події 2Це дві РІЗНІ події, обидві шлються (різні event_id / conversionAction). Флаги не дають дублів у межах однієї події.
Telegram без gclid (напр. Facebook)Google OCI не шлемо. Meta (PII + fbc) і GA4 (ga_client_id) шлемо.
Немає ga_client_id на TG-замовленніГенеруємо синтетичний client_id, фіксуємо в CRM.
Немає fbcВідновлюємо з fbclid: fb.1.<ts>.<fbclid>.
Підтвердження через 2+ тижні від замовленняMeta: event_time = момент підтвердження (не дата замовлення) → завжди в межах 7 днів, шлемо (виправлення проти v1). GA4: без timestamp_micros. Google: лише якщо клік ≤90 днів.
Допродаж після Події 1Подія 2 несе value_final. Подія 1 лишається зі своєю value_processing.

12. Технічні нотатки

13. Питання до вас (без них не фіналізуємо)

  1. Назви статусів у SuiteCRM під дві події: який = Подія 1 (в обробці), який = Подія 2 (викуп)?
  2. Де фіксується фінальна сума з допродажами: OpenCart чи SuiteCRM? (джерело value_final)
  3. Звʼязок OpenCart і SuiteCRM: є синхронізація і спільний order_id? (ключ дедупу)
  4. Хто веде CRM і чи може CRM-сервер робити вихідні HTTP (хук/cron), чи потрібен мікросервіс?
  5. Інтеграція SendPulse → SuiteCRM: є штатна? Якщо так, перенос міток автоматизуємо.

14. Конфіг (env, після ротації токенів)

# Meta
META_PIXEL_ID=1849940369742660
META_ACCESS_TOKEN=<ротувати, з env>
# Google Ads
GOOGLE_ADS_DEVELOPER_TOKEN=<ротувати>
GOOGLE_ADS_CLIENT_ID=<ротувати>
GOOGLE_ADS_CLIENT_SECRET=<ротувати>
GOOGLE_ADS_REFRESH_TOKEN=<ротувати>
GOOGLE_ADS_CUSTOMER_ID=7699145794
GOOGLE_ADS_LOGIN_CUSTOMER_ID=1914648688
GOOGLE_ADS_CONV_ACTION_E1=customers/7699145794/conversionActions/7660803552
GOOGLE_ADS_CONV_ACTION_E2=customers/7699145794/conversionActions/7660805253
# стара POST/Qualified Purchase 7606114302 = WEBPAGE, для OCI не годиться
# GA4
GA4_MEASUREMENT_ID=G-CQYZHNRVDB
GA4_API_SECRET=<ротувати>
# CRM
CRM_STATUS_EVENT1=<заповнити>
CRM_STATUS_EVENT2=<заповнити>
# SendPulse
SENDPULSE_FLOW_ID=69a18b210993aea5530d6faf
SENDPULSE_BOT=Molfar_Support_Bot

15. Поетапний план

1
Захоплення атрибуції. GTM-тег UTM Keeper; TG-скрипт інлайн (заміна старого); змінні в SendPulse.
2
Сховище в CRM. Поля розділу 7, спільний order_id з OpenCart.
3
Sender. На статусах Подій 1 і 2 шле Meta + GA4 + Google (payload розділу 8), флаги, ретраї.
4
Google Ads. Конверсії створено (7660803552, 7660805253).
5
Спостереження. Звіряємо обсяг і суми з реальним викупом.
6
Перемикання оптимізації на реальну / маржинальну цінність.
Лавка Молфара · ТЗ v2 «Наскрізні конверсії» · 24.06.2026. Поля ЗАПОВНИТИ заповнюються після відповідей на питання розділу 13. Усі токени ротувати й тримати в secret-менеджері.