M25 · Destinations

目的地

一键把受众推送到 Meta Ads、Google Ads、自定义 webhook。凭据存储在 KMS envelope 中。

3 个通道

Meta CAPI · Google Ads · Webhook

三种 destination 类型。共享同一套 audience 绑定 + dispatch 日志 + dedup 基础设施。

Meta CAPI

Meta CAPI

把哈希后的 email + phone 推送到 Custom Audience。SHA-256 小写 trim + E.164 — 完全符合 Meta 规范。

Google Ads Customer Match

Google Ads

OAuth 2.0 流程 + 平台级 developer_token。通过 Customer Match API 管理哈希用户列表。

Webhook(自定义)

Custom webhook

推送到你自己的系统。HMAC-SHA256 签名头 + JSON body + retry/dedup 支持。

Meta CAPI 接入

分步接入

从 Facebook Business Manager 获取 Pixel ID + Access Token + Test Event Code — 4 步上线。

  1. 01

    准备 Pixel + Business Manager

    Facebook Business Manager → Events Manager → 复制 Pixel ID。确认你拥有 Custom Audience 创建权限。

  2. 02

    生成 System User Access Token

    Business Settings → Users → System Users → 「生成 Token」→ scopes 选 ads_management + business_management。Token 只显示一次,立刻复制。

  3. 03

    在 Gurulu 中添加凭据

    /app/destinations → 「新建 Meta CAPI」→ Pixel ID + Access Token +(可选)Test Event Code。Gurulu 把凭据存进 KMS envelope,UI 只显示末 4 位掩码。

  4. 04

    绑定受众 + dispatch

    把 destination 和 audience 配对。首次 dispatch 时若 Custom Audience 不存在则会创建;之后每小时增量推送。

// Hash format: lowercase, trim, SHA-256
// E.164 phone: '+901234567890' → sha256 hex
import { createHash } from 'node:crypto';

function hashPii(value: string): string {
  return createHash('sha256').update(value.trim().toLowerCase()).digest('hex');
}

// Audience üye listesi push
await fetch('https://graph.facebook.com/v18.0/{pixel_id}/users', {
  method: 'POST',
  headers: { Authorization: 'Bearer ' + ACCESS_TOKEN },
  body: JSON.stringify({
    payload: {
      schema: ['EMAIL_SHA256', 'PHONE_SHA256'],
      data: members.map((m) => [hashPii(m.email), hashPii(m.phone)]),
    },
  }),
});

Google Ads OAuth

OAuth 流程 + developer token

在 Google Cloud Console 创建 OAuth Client,申请 developer_token — 即可开通 Customer Match API。

  1. 01

    Google Cloud Console — OAuth Client

    APIs & Services → Credentials → 「Create OAuth Client ID」→ Application type: Web。redirect URI 必须与 Gurulu 的回调完全一致。

  2. 02

    申请 Developer Token

    Google Ads → Tools → API Center → 申请 Developer Token。Standard Access 通常需 2-3 天。

  3. 03

    从 Gurulu 启动 OAuth

    /app/destinations → 「新建 Google Ads」→ 「用 Google 连接」→ 同意页 → 回调时 refresh_token 存进 KMS envelope。

# OAuth callback URI (Google Cloud Console'a kayıtla):
https://api.gurulu.io/v1/destinations/oauth/google/callback

# Developer token başvurusu — Google Ads API erişimi için
# https://developers.google.com/google-ads/api/docs/first-call/dev-token

Webhook 接入

HMAC-SHA256 验签 + retry

在你的服务器验签、dedup、ack。Gurulu 负责 retry。

Node.js / Bun / TypeScript

// Node.js — HMAC-SHA256 verify
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyGuruluSignature(
  rawBody: string,
  header: string | undefined,
  secret: string,
): boolean {
  if (!header?.startsWith('sha256=')) return false;
  const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
  const received = header.slice(7);
  return (
    expected.length === received.length &&
    timingSafeEqual(Buffer.from(expected), Buffer.from(received))
  );
}

Python 3.10+

# Python — HMAC-SHA256 verify
import hmac, hashlib

def verify_gurulu_signature(raw_body: bytes, header: str | None, secret: str) -> bool:
    if not header or not header.startswith("sha256="):
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    received = header[7:]
    return hmac.compare_digest(expected, received)

Payload 示例

{
  "audience_id": "aud_01H8XYZ",
  "tenant_id": "tnt_01H8ABC",
  "members": [
    { "person_id": "per_01H8DEF", "email_sha256": "…", "joined_at": "2026-05-29T06:00:00Z" }
  ],
  "delta": "joined",
  "dispatched_at": "2026-05-29T07:00:00Z"
}

KMS 加密

凭据透明度

Meta access token、Google refresh token、webhook secret — 全部存在 KMS envelope 中。

存储方式

每个凭据用 AES-GCM 数据加密密钥(DEK)加密;DEK 由根 KMS 密钥包裹。只有 worker 解密 — UI 永远不接触明文。

  • docsModules.destinations.kms.how.bullets.envelope
  • Worker 仅服务端解密 — UI 与 API 永远见不到明文
  • UI 凭据列表只显示末 4 位掩码(例如 '••••••a8f3')
{
  "kid": "kms_2026_q2_primary",
  "encrypted_dek": "AQEDAH4...",
  "iv": "5b9e8c7a4f3d2e1b6c0a9d8e",
  "tag": "a1b2c3d4...",
  "ciphertext": "f7e8d9..."
}

Dispatch + dedup

24 小时 dedup + 指数退避 retry

同一个(audience、member、payload)24 小时内不会被发送两次。失败时指数退避 retry。

Payload-hash dedup

每次 dispatch 计算 payload_hash + 保持 24h dedup 窗口。同 hash → 跳过(幂等)。

指数退避 retry

30s → 2m → 10m → 1h → 6h。5 次后:DLQ。dispatches 表会显示每次尝试 + 错误码。

相关文档

下一步阅读

先创建受众,再接入 destination。想更深入请看 API Reference。

目的地 — Gurulu 文档