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

# X (Twitter) Ads

> Connect an X (Twitter) Ads account to manage campaigns, line items, and promoted tweets, upload media into the media library, pull stats, and run multi-line-item creative experiments from the dashboard.

## Overview

Connecting X Ads lets the dashboard:

* Create, update, pause, resume, and delete **campaigns** and **line items** (X's term for ad sets).
* Upload **image** and **video** media into the connected account's media library.
* Create and manage **promoted tweets** that reference an existing tweet plus a line item.
* Pull spend, impressions, engagements, and conversions from `/stats/accounts`.
* Run creative experiments by rotating multiple line items under one campaign.

The integration uses the **X Ads API v12** with **OAuth 2.0 PKCE** authentication.

## Prerequisites

Before connecting, make sure you have:

1. An active X Ads account with developer / API access.
2. **Approved access to the X Ads API** — gated behind partner review. Live write access is enabled once X partner approval is granted for your account.
3. An OAuth 2.0 application configured for the dashboard's redirect URI, with OAuth credentials configured by your administrator.

## OAuth scopes

The connection requests the following scopes:

```
tweet.read
users.read
offline.access
ads.read
ads.write
```

`offline.access` is required for refresh tokens. `ads.read` covers list and report operations; `ads.write` covers all create / update / delete writes.

## PKCE flow

X Ads requires **PKCE** (Proof Key for Code Exchange — RFC 7636). The dashboard:

1. Generates a 32-byte random `code_verifier` at start time and stores it server-side for the duration of the round-trip.
2. Computes `code_challenge = base64url(sha256(code_verifier))` and emits `code_challenge` + `code_challenge_method=S256` on the authorize URL.
3. Sends the matching `code_verifier` on the token-exchange call so the platform can verify the relationship.

This is handled transparently — there is no manual setup beyond the standard "Connect" click.

## Connect

1. Open the **Paid UA → Integrations** page in the dashboard.
2. Click **Connect** on the X (Twitter) Ads tile.
3. Sign in with the X account that has access to your ads account.
4. Approve the requested scopes.
5. After redirect, the dashboard exchanges the auth code (with the PKCE verifier) for tokens and probes `/accounts` to confirm access.

Access tokens are rotated automatically before expiry using the refresh token.

## What happens behind the scenes

| Operation                                 | API endpoint                                                           |
| ----------------------------------------- | ---------------------------------------------------------------------- |
| List ad accounts the user can access      | `GET /accounts`                                                        |
| Create / list campaigns                   | `POST` / `GET /accounts/{id}/campaigns`                                |
| Update / pause / resume / delete campaign | `PUT` / `DELETE /accounts/{id}/campaigns/{id}`                         |
| Create / update line items                | `POST` / `PUT /accounts/{id}/line_items[/{id}]`                        |
| Create / update promoted tweets           | `POST` / `PUT /accounts/{id}/promoted_tweets[/{id}]`                   |
| Upload media library entry                | `POST /accounts/{id}/media_library`                                    |
| Pull stats                                | `GET /stats/accounts/{id}?entity=...&entity_ids=...&metric_groups=...` |

Pause / resume operations send `{ paused: true | false }` instead of a status enum.

Every write request carries an `Idempotency-Key` HTTP header so retries do not produce duplicate resources, even if the platform connection drops mid-request.

## Rate limiting

Requests are throttled per account using a sliding-window rate limiter, and rate limits apply. If the platform reports HTTP 429, the request is automatically retried with exponential backoff. X also surfaces sliding-window limits in its response headers.

## Reporting

Metrics are pulled hourly (or on demand) from the stats endpoint. Default columns include engagement metrics (impressions, clicks, retweets, likes) and billing metrics (spend, billable cost). Stats are pulled per `entity=CAMPAIGN` (or `LINE_ITEM` for split tests) with the campaign id forwarded as `entity_ids`.

Spend is converted from native currency to USD on ingestion. The native currency, the FX rate used, and the local-currency spend are kept alongside the USD value for downstream analytics.

## Experiments (multi-line-item rotation)

X Ads does not expose a native experiment primitive. The dashboard maps experiment variants onto **multiple line items** under a single campaign, with each variant carrying its own targeting and creative tweet. The control variant ships **unpaused**; treatments ship **paused** until the experiment runner toggles them. Per-variant performance is read back from the stats endpoint with `entity=LINE_ITEM`.

## Live write access

X Ads API access is gated behind partner review. Live write access is enabled once X partner approval is granted for your account. Until then, write operations are not sent to X.

## Disconnect

Click **Disconnect** on the integration tile. The OAuth refresh token is removed from the dashboard. To fully revoke access, also remove the third-party app authorisation from your X account's connected apps list.

## Troubleshooting

* **"X Ads /accounts returned 401"** — the OAuth token has been revoked or has expired without a valid refresh token. Re-connect the integration.
* **"X Ads create\_campaign: 429 — ..."** — your account's per-minute API quota was breached. The dashboard backs off automatically; if the error persists, lower campaign-mutation frequency.
* **"webhooks not supported on x\_ads"** — X's Account Activity API is gated separately from the Ads API and out of scope. State changes are detected via the hourly metrics-sync job instead.
* **Writes are not reaching X** — live write access is enabled once X partner approval is granted for your account. Contact your administrator if writes are not taking effect after approval.
* **Token exchange returns 400 on PKCE flow** — the `code_verifier` did not match the `code_challenge` sent during authorize. The state TTL is 10 minutes; if the user took longer than that, restart the connect flow.
