> ## 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.

# Ads API

> Connect a Meta Ad Account, manage click-to-chat campaigns, forward Conversions API events, ingest Lead Ads, and activate CDP segments as Custom Audiences.

# Ads API

Connect a Meta Ad Account and run the full advertising loop from Orbit: create click-to-chat campaigns, forward conversions back to Meta for closed-loop attribution, turn Meta Lead Ads into contacts, and activate CDP segments as hashed Custom Audiences.

**Base path:** `/api/v1/ads`

**Authentication:** API key (`X-API-Key`) or session JWT. Every endpoint requires authentication.

**Roles:** read endpoints (connection status, campaign list/detail, audience list) are open to any authenticated role. Every write — connecting, disconnecting, campaign create/update/delete, Conversions API calls, Lead Ads ingestion, and audience create/sync/delete — requires the **owner** or **admin** role.

A single Meta Ad Account is stored per organization. Connect it first; the other endpoints return `CHANNEL_UNAVAILABLE` until a connection (and, for Conversions, a dataset ID) exists.

## Connection

Connect via the hosted OAuth flow (`/oauth/exchange`, used by the in-app callback) or by posting an access token and ad account id directly (`/connect`).

| Method   | Path                         | Purpose                                                                                  | Role          |
| -------- | ---------------------------- | ---------------------------------------------------------------------------------------- | ------------- |
| `POST`   | `/api/v1/ads/oauth/exchange` | Exchange a Facebook OAuth `code` for a long-lived token and connect the first ad account | owner / admin |
| `POST`   | `/api/v1/ads/connect`        | Connect using an existing `access_token` and `ad_account_id`                             | owner / admin |
| `GET`    | `/api/v1/ads/status`         | Connection summary: `connected`, `ad_account_id`, `connected_at`, account `currency`     | any role      |
| `DELETE` | `/api/v1/ads/disconnect`     | Remove the Meta Ad Account connection                                                    | owner / admin |

Tokens are encrypted at rest. The `status` response surfaces the selected ad account's currency so budgets and spend render in the account's own currency rather than defaulting to USD.

## Campaigns

Click-to-chat campaigns drive WhatsApp, Messenger, or Instagram Direct conversations. New campaigns are created in `PAUSED` state so you can review them in Meta before they spend.

| Method   | Path                         | Purpose                                                                                                             | Role          |
| -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------- |
| `GET`    | `/api/v1/ads/campaigns`      | List campaigns for the connected ad account (cursor-paginated). Returns an empty list when no account is connected. | any role      |
| `POST`   | `/api/v1/ads/campaigns`      | Create a click-to-chat campaign (`destination`: `WHATSAPP`, `MESSENGER`, or `INSTAGRAM_DIRECT`)                     | owner / admin |
| `GET`    | `/api/v1/ads/campaigns/{id}` | Campaign detail with Meta insights                                                                                  | any role      |
| `PUT`    | `/api/v1/ads/campaigns/{id}` | Update name, status (`ACTIVE`/`PAUSED`/`ARCHIVED`), daily budget, or targeting                                      | owner / admin |
| `DELETE` | `/api/v1/ads/campaigns/{id}` | Delete a campaign                                                                                                   | owner / admin |

## Conversions API

Forward business outcomes (lead, purchase, registration, appointment) from WhatsApp conversations that started on a click-to-WhatsApp ad back to Meta, closing the attribution loop. Email and phone are SHA-256 hashed before they leave Orbit — raw PII is never sent to Meta.

Set a `dataset_id` once; the test and live endpoints both read it.

| Method | Path                              | Purpose                                                               | Role          |
| ------ | --------------------------------- | --------------------------------------------------------------------- | ------------- |
| `PUT`  | `/api/v1/ads/conversions/dataset` | Set or replace the Conversions API `dataset_id`                       | owner / admin |
| `POST` | `/api/v1/ads/conversions/test`    | Send a test event to verify the integration                           | owner / admin |
| `POST` | `/api/v1/ads/conversions`         | Post a real conversion event (include `ctwa_clid` for ad attribution) | owner / admin |

A conversion must carry at least one identifier in `user_data` — `phone`, `email`, `external_id`, or `ctwa_clid` — for Meta to match it.

## Lead Ads ingestion

Turn a Meta `leadgen` webhook batch into tenant contacts. Each lead's instant-form answers are fetched from the Graph API and upserted through the same dedup, compliance, and required-field machinery as a CSV import. Leads with no email and no phone are skipped; one failed fetch never drops the rest of the batch.

| Method | Path                       | Purpose                                               | Role          |
| ------ | -------------------------- | ----------------------------------------------------- | ------------- |
| `POST` | `/api/v1/ads/leads/ingest` | Ingest one Meta `leadgen` webhook batch into contacts | owner / admin |

The response reports `received`, `fetched`, `fetch_failures`, `skipped_no_contact`, `created`, `updated`, and `duplicates`.

## Custom Audiences

Activate a first-party CDP segment to Meta as a hashed customer-list Custom Audience for targeting or suppression, then keep it in sync as the segment recomputes. Membership is SHA-256 hashed before upload.

| Method   | Path                                      | Purpose                                                                                             | Role          |
| -------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------- |
| `POST`   | `/api/v1/ads/audiences`                   | Create a Custom Audience, optionally linked to a CDP `segment_id`                                   | owner / admin |
| `GET`    | `/api/v1/ads/audiences`                   | List the audiences this org has activated, with segment links and sync metadata                     | any role      |
| `POST`   | `/api/v1/ads/audiences/{audienceId}/sync` | Sync segment membership — `mode: "add"` (default) uploads members, `mode: "remove"` suppresses them | owner / admin |
| `DELETE` | `/api/v1/ads/audiences/{audienceId}`      | Delete the audience from Meta and drop the stored mapping                                           | owner / admin |

A sync resolves up to 100,000 members per call; larger segments are truncated and the response sets `truncated: true`.

## Example — check connection status

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

## See also

* [CDP API](/api-reference/endpoints/cdp) — build the segments you activate as Custom Audiences
* [Contacts API](/api-reference/endpoints/contacts) — where ingested Lead Ads land
* [Channels → WhatsApp guide](/channels/whatsapp) — click-to-WhatsApp setup and templates
