> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Audience activation to ad networks: the operator walkthrough

> Walk a saved Orbit segment into Meta Custom Audiences, Google Customer Match, TikTok, and LinkedIn end to end — pre-flight consent gate, destination configuration, PII tokenization, the push pipeline, and sync monitoring with DLQ recovery.

# Audience activation to ad networks: the operator walkthrough

A saved segment answers *who*; an activation answers *where that audience keeps landing*. This guide walks the full operator journey for the four paid-media networks that take a hashed audience list — Meta Custom Audiences, Google Customer Match, TikTok, and LinkedIn — from the consent gate through destination configuration, PII tokenization, the push pipeline, and sync monitoring. Each step links the capability page that carries the detail, so this page is the through-line, not a re-derivation.

The pieces this guide stitches together live across three surfaces: the [audience activation pipeline](/guides/audience-activation-pipeline) (the scheduled publish), the [CDP destinations catalog](/guides/cdp-destinations) (the per-network receiver shape), and the [PII tokenization and vault](/guides/cdp-pii-tokenization-and-vault) (the hash-before-egress contract). Read this page first; drill into a capability page when a step needs the full endpoint reference.

## 1. Outcome: a PII-safe activation

By the end of this walkthrough a saved segment is publishing into an ad-network audience list on a cadence you control, with every member hashed server-side before it leaves Orbit, every opted-out contact fenced out before dispatch, and every sync run visible in a run log you can audit. Raw PII never reaches a network — hashed identifiers and counts only — and a revoke recorded mid-flight stops the next run, not just the next send.

Preview, push, then monitor: dry-run the batch with preflight, push the live membership, and read the sync run log to reconcile. That order is the whole shape — never push a segment you have not previewed, and never declare a sync healthy without reading the run history.

## 2. Prerequisites

Before the first activation, gather:

* A **saved segment** (`POST /api/v1/contacts/segments`) with `auto_refresh` on, so the membership the activation re-reads is current. Build it in [CDP audiences: build segments](/guides/cdp-segments).
* A **destination account** on the ad network you are activating into — a Meta Ad Account, a Google Ads account, a TikTok Ads account, or a LinkedIn Campaign Manager — with the OAuth connection wired as a Nango connection id in Orbit. See [audience activation pipelines](/guides/audience-activation-pipeline) for the connection shape.
* An **owner, admin, or developer** role on the API key for every config and activate call. Reads are open to any role; writes are gated.
* Consent and suppression hygiene: members flagged `consent: false` or `suppressed: true` fail the pre-activation gate below its thresholds. Keep those flags honest at ingest — see the [opt-outs console](/guides/audience-opt-outs-console).
* If the destination is **Klaviyo** instead of an ad network, follow the [Klaviyo destination walkthrough](/guides/cdp-klaviyo-destination-walkthrough) — the martech object-sync shape, not the hashed-audience shape this guide covers.

## 3. The consent and suppression gate

Every activation runs through a pre-flight gate that reads the consent ledger and the suppression list before a single member is dispatched. The gate is a hard STOP fence: a member who has opted out of the channel the activation targets, or who is on the suppression list, is removed from the batch before it leaves Orbit — not flagged downstream, removed upstream.

The gate reads the same consent records the [opt-outs console](/guides/audience-opt-outs-console) renders: a per-contact, per-channel revoke written by an inbound STOP keyword, a preference-center toggle, the Consent API, a manual create, or a CSV import. Because all five writers converge on one consent ledger, a revoke recorded through any of them is visible to the gate on the next run — there is a single source of truth and a single fence.

Two gate behaviors to plan around:

* **A batch below the preflight threshold is blocked.** If the gate rejects the batch — too small after consent filtering, low identifier coverage, or too many consent violations — the activation returns `422 AUDIENCE_PREFLIGHT_BLOCKED` with the failing check ids in the response. Dry-run with `POST /api/v1/cdp/audience/preflight/:platform` first; adjust the segment or the thresholds, or send `override_preflight: true` (audited) when the threshold is genuinely fine for the destination.
* **A revoke mid-flight stops the next run.** A contact who opts out between two scheduled syncs is fenced out of the second run, not the in-flight first one. The STOP fence sets a fast-path flag on opt-out, so in-flight campaign batches see the revoke before the slower database suppression propagates — but a batch already dispatched to the network is not recalled. Plan a `remove` (suppression) sync on the cadence that follows a revoke wave, so the network-side audience list drops the revoked members on the next pass.

Tenant-owned controls like consent checks and suppression lists gate every activation; the posture is your organization's to set. See [compliance](/compliance/send-gates) for the send-gate contract.

## 4. Configure the destination

Wire each network once; only supplied keys change on later runs. The config is a single row per destination with the connection, the audience id, the segment source, and the cadence:

```bash theme={null}
curl -X PATCH https://api.orbit.devotel.io/api/v1/cdp/audience/config/google \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "nango_connection_id": "conn_googleads_7d2e",
    "audience_id": "ul_91428",
    "segment_id": "seg_churn_tier1",
    "schedule_minutes": 1440
  }'
```

Per-network configuration decisions:

* **Hash algorithm.** Meta Custom Audiences, Google Customer Match, TikTok, and LinkedIn all take SHA-256-hashed identifiers. Orbit normalizes and hashes server-side before dispatch (see the next section), so the hash algorithm is not a per-network knob you set — it is the platform default each network expects. A network that rejects the hash shape returns a `validation` failure class in the run log (see section 7).
* **Ad-audience naming.** Name the destination audience list on the network side so it maps cleanly to the Orbit segment — the `audience_id` is the link. A name like `Orbit — churn-tier-1 — prospecting` keeps the source, the segment, and the use (targeting vs suppression) legible on the network's own console.
* **Cadence — real-time vs nightly.** Set `schedule_minutes` for a recurring publish (daily = 1440, hourly = 60); omit it for manual-only runs. The scheduled sweep ticks every 15 minutes and runs a destination when its cadence has elapsed, so set `segment auto_refresh` so a scheduled run re-resolves fresh membership rather than re-pushing a stale snapshot. Real-time is not per-event — the hashed-audience shape is a batch publish, not a streaming dispatch; for per-event forwarding see [conversion forwarding](/guides/cdp-meta-tiktok-conversion-forwarding).

Going live without `audience_id` and `nango_connection_id` is rejected with `409 CONNECTION_NOT_CONFIGURED` — the same precondition the dashboard enforces. See [audience activation pipelines](/guides/audience-activation-pipeline) for the full config field reference.

## 5. PII tokenization: what is hashed before it leaves

Before any member reaches a network, the activation pipeline normalizes and SHA-256-hashes the identifiers each network accepts. Email and phone are the primary match keys; the network receives a digest, never cleartext.

The tokenization contract is the same one the [PII tokenization and vault](/guides/cdp-pii-tokenization-and-vault) surface governs:

* **Normalization first.** Email is lower-cased and trimmed so casing variants hash to one digest; phone is normalized to E.164. A `Ada@Example.com` and `ada@example.com` resolve to the same hash, so the network sees one member, not two.
* **SHA-256 server-side.** The hash runs inside Orbit before dispatch. The network's audience list receives the digest column; the cleartext never crosses the egress boundary.
* **What gets hashed.** The strong identifiers each network match-keys on — email, phone, and (where the network accepts it) mobile advertising id (`madid`). Rows with only a name and address are rejected before dispatch, not silently dropped — a member needs at least one strong identifier to be matchable on the network side.
* **Counts only in the log.** The sync run log carries `requested` / `matched` / `skipped` / `failed` counts and per-batch error classes — never the hashed values, never the cleartext. A breached log carries pseudonymous counts, not identifiers.

If your tenant has tokenization policy enabled on a type (email, phone), segmentation and activation run on tokens instead of cleartext internally, and the hash-before-egress step composes with that policy — the network still receives the SHA-256 digest it expects. Configure the standing posture on the PII tokenization tab; this guide does not change it.

## 6. The push pipeline: pull, normalize, hash, batch, sync

A run pulls the current segment membership, normalizes each member's identifiers, hashes them, batches them, and dispatches to the network. Trigger a push explicitly:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/cdp/audience/activate/google \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "segment_id": "seg_churn_tier1",
    "operation": "add",
    "members": [
      { "email": "ada@example.com", "phone": "+14155550123" },
      { "madid": "a1b2c3d4-e5f6-47a2-91c1-55d0ab2d9c01" }
    ]
  }'
```

The request and response shape, quoted from the [audience activation pipeline](/guides/audience-activation-pipeline) reference:

* **`segment_id`** — the saved segment the run reads. Optional per-run override; the config's `segment_id` is the default.
* **`operation`** — `add` (newest members; acquisition or seeding a lookalike) or `remove` (suppression; drop existing customers from prospecting spend). Lean on successive `add`/`remove` deltas rather than full re-uploads — the destination stays diff-shaped.
* **`members`** — up to 10,000 per call. Each member resolves to this profile shape: `email`, `email_work`, `phone`, `first_name`, `last_name`, `city`, `state`, `zip`, `country`, `madid`. A segmentation job sends batchfuls in one run.
* **Response** — `requested` / `matched` / `skipped` member counts, `batches` dispatched, an `error` message when a dispatch call failed, and per-member rejections (index + reason, never PII).

Dry-run first with `POST /api/v1/cdp/audience/preflight/:platform` — same verdict, nothing dispatched. If maker-checker is on for your org, the run queues for approval: submit without an `approval_id`, an owner/admin approves via `POST /api/v1/cdp/audience/approvals/:id/decision`, then re-submit with the returned `approval_id`.

For suppression — dropping won-back customers out of prospecting spend — run the same endpoint with `operation: "remove"`. A suppression run is the cleanest way to stop spend on customers you already have.

## 7. Monitor and reconcile

Every run lands in a capped history (newest first, 50 entries) and in the [sync run log](/guides/cdp-sync-run-log). Read the activation history and one run's detail:

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/cdp/audience/activations \
  -H "X-API-Key: dv_live_sk_your_key_here"

curl https://api.orbit.devotel.io/api/v1/cdp/audience/activations/4e3b9c1d-... \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

Status meanings across every network:

* `ok` — every batch the network accepted.
* `partial` — some batches failed; the member-level detail names why.
* `failed` — nothing accepted (quota breach, revoked token).
* `skipped` — nothing matchable, or no connection wired at dispatch time.

Retry a non-`ok` run with `POST /api/v1/cdp/audience/activations/:id/retry` and a corrected member batch — it is recorded as a new run linked to the original. Only `ok` runs are refused as already-dispatched.

### DLQ fallback

When a dispatch fails the destination (non-2xx, timeout, connection or TLS error), the failed delivery lands in the [CDP DLQ](/guides/cdp-event-debugger-and-dlq), grouped by destination, with the HTTP status or transport error per row. After enough consecutive failures the destination's circuit breaker trips and new dispatches skip it until you reset. The recovery is two halves: reset the circuit (`Reset` on the row) to re-open the gate, then replay the failed backlog (`Replay failed` on the destination group header, up to 50 per run) to re-drive what queue-built during the outage.

### Audience refresh windows per ad network

Each network refreshes its audience list on its own cadence after Orbit pushes the batch — a pushed member is not instantly targetable in the network's campaign tooling. Plan the Orbit cadence against the network's refresh window:

| Network | Audience refresh window |
| - | - |
| Meta Custom Audiences | Within \~1 hour of push; members are matchable as the audience updates |
| Google Customer Match | Up to 6–12 hours; Google hashes and matches on its own schedule |
| TikTok Custom Audience | Within \~1–3 hours of push |
| LinkedIn Matched Audiences | Up to 24 hours; LinkedIn batches the match overnight |

Set the Orbit `schedule_minutes` comfortably inside the network's refresh window — a hourly Orbit push into a network that updates overnight wastes runs without changing who is targetable. For a nightly Google or LinkedIn audience, a daily Orbit cadence is the right shape.

## 8. Failure modes

| Failure | What happens | What to do |
| - | - | - |
| **API quota** | The network throttles the batch (429); the run lands `partial` or `failed` with a `rate_limit` error class | Slow the cadence (`schedule_minutes`), then `POST .../retry`. Do not hammer retries against a quota window. |
| **Schema drift** | The network changes its accepted field shape, or a field map drifts; the run lands `failed` with a `validation` error class, sample "Row dropped: missing or empty upsert identifier value" | Fix the field mapping or the record at the source, then re-run. A `validation` failure is not retryable — retrying just fails again. |
| **Consent revocation mid-flight** | A contact opts out between two scheduled syncs | The next scheduled run fences them out (the STOP fence reads the consent ledger before dispatch). Run a `remove` (suppression) sync so the network-side audience list drops them on the next pass — a batch already dispatched is not recalled. |
| **Expired OAuth token** | The Nango connection token expired; the run lands `failed` with an `auth` error class | Reconnect the destination with fresh credentials from the CDP integrations page, then re-run. `auth` is not retryable without the reconnection. |
| **Truncated membership** | The segment exceeded the 100,000-member per-call window; the response marks `truncated: true` | Split the segment or sync in successive paginated calls. |

See the [sync run log](/guides/cdp-sync-run-log) failure-class table for the full retryability matrix — retry `rate_limit`, `network`, `timeout`, `server`, and (once) `unknown`; fix `auth`, `permission`, `validation`, and `not_found` at the destination or the mapping, then re-run.

## 9. See also

* [Audience activation pipelines](/guides/audience-activation-pipeline) — the scheduled publish surface this walkthrough drives
* [CDP destinations](/guides/cdp-destinations) — the per-network receiver catalog
* [CDP PII tokenization and vault](/guides/cdp-pii-tokenization-and-vault) — the hash-before-egret contract
* [Opt-outs console](/guides/audience-opt-outs-console) — the consent ledger the gate reads
* [CDP sync run log](/guides/cdp-sync-run-log) — the per-destination run history and failure-class drilldown
* [CDP event debugger and DLQ](/guides/cdp-event-debugger-and-dlq) — the failed-delivery backlog and replay
* [Activate segments into Braze, Iterable, and Customer.io](/guides/cdp-martech-destinations-braze-iterable-customerio) — the martech object-sync walkthrough (not the hashed-audience shape)
* [CDP conversion forwarding: Meta, TikTok, and the multi-platform hub](/guides/cdp-meta-tiktok-conversion-forwarding) — server-side conversion events back to ad networks
* [CDP audiences: build segments](/guides/cdp-segments) — the segment recipe every activation reads


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.