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

> ## Agent Instructions
> These docs describe the Ancha CLI, npm package @ancha-labs/cli version 0.1.4, and the hosted workspace at app.ancha.io. Coding agents should start at https://docs.ancha.io/coding-agents. Run the CLI as `ancha` after `npm install -g @ancha-labs/cli`, or as `npx -y @ancha-labs/cli@0.1.4` without installing. Pass --json for machine-readable output, or set ANCHA_JSON=1. Every command ends with a `next:` line naming the next command. Exit codes: 0 pass, 1 a check failed or a comparison regressed, 2 usage, config or authentication error, 3 infrastructure error, 4 unimplemented endpoint with --strict.

# LinkedIn Ads

> A stateful replica of LinkedIn's Marketing API version 202610: ad accounts, campaign groups, campaigns, creatives, targeting facets and campaign analytics.

The LinkedIn Ads replica implements 17 endpoints of the Marketing API, version 202610, with Rest.li 2.0 conventions. Its key is `linkedin-ads`.

## Connect

| Variable | Value |
| - | - |
| `LINKEDIN_ADS_API_URL` | Base URL. Paths start with `/rest/`. |
| `LINKEDIN_ADS_TOKEN` | Fake OAuth token. Send `Authorization: Bearer <token>`. |

Every request also needs `LinkedIn-Version: 202610` and `X-Restli-Protocol-Version: 2.0.0`, and writes need `Content-Type: application/json`.

```js Node theme={null}
const response = await fetch(process.env.LINKEDIN_ADS_API_URL + '/rest/adAccounts?q=search', { headers: { Authorization: 'Bearer ' + process.env.LINKEDIN_ADS_TOKEN, 'LinkedIn-Version': '202610', 'X-Restli-Protocol-Version': '2.0.0' } });
const accounts = await response.json();
```

This is what `ancha connect linkedin-ads --lang ts` prints.

## Endpoints

All endpoints are partial. Any other route returns HTTP 501 with `x-ancha-gap: 1`.

### Accounts

| Method | Path |
| - | - |
| `GET` | `/rest/adAccounts` |
| `GET` | `/rest/adAccounts/:accountId` |

### Campaign groups

| Method | Path |
| - | - |
| `GET` | `/rest/adAccounts/:accountId/adCampaignGroups` |
| `GET` | `/rest/adAccounts/:accountId/adCampaignGroups/:id` |
| `POST` | `/rest/adAccounts/:accountId/adCampaignGroups` |
| `POST` | `/rest/adAccounts/:accountId/adCampaignGroups/:id` |

### Campaigns

| Method | Path |
| - | - |
| `GET` | `/rest/adAccounts/:accountId/adCampaigns` |
| `GET` | `/rest/adAccounts/:accountId/adCampaigns/:id` |
| `POST` | `/rest/adAccounts/:accountId/adCampaigns` |
| `POST` | `/rest/adAccounts/:accountId/adCampaigns/:id` |

### Creatives

| Method | Path |
| - | - |
| `GET` | `/rest/adAccounts/:accountId/creatives` |
| `GET` | `/rest/adAccounts/:accountId/creatives/:id` |
| `POST` | `/rest/adAccounts/:accountId/creatives` |
| `POST` | `/rest/adAccounts/:accountId/creatives/:id` |

### Targeting and analytics

| Method | Path |
| - | - |
| `GET` | `/rest/adTargetingFacets` |
| `GET` | `/rest/adTargetingEntities` |
| `GET` | `/rest/adAnalytics` |

## Behavior

* **Creating** returns an empty 201 response with the new ID in `x-restli-id`.
* **Updating** is a `POST` to the record with `X-RestLi-Method: PARTIAL_UPDATE` and a body of `{"patch": {"$set": {...}}}`. It returns an empty 204. Read the record again to see the result.
* **Finders** take `q=search` (accounts, campaign groups, campaigns) or `q=criteria` (creatives) with a bounded `search` expression, cursor pagination and `fields` projection. Batch gets report per-ID errors.
* **Creatives** reference the one seeded single-image post. New creatives stay pending review; nothing uploads an image or creates a post.
* **Analytics** support the `CAMPAIGN` pivot with `DAILY` or `ALL` granularity over an explicit date range, from historical rows.

To pause campaign 701001:

```bash theme={null}
curl -X POST "$LINKEDIN_ADS_API_URL/rest/adAccounts/501001/adCampaigns/701001" \
  -H "Authorization: Bearer $LINKEDIN_ADS_TOKEN" \
  -H "LinkedIn-Version: 202610" -H "X-Restli-Protocol-Version: 2.0.0" \
  -H "X-RestLi-Method: PARTIAL_UPDATE" -H "Content-Type: application/json" \
  -d '{"patch":{"$set":{"status":"PAUSED"}}}'
```

## Starter data

The `linkedin-ads-starter` dataset belongs to Acme.

| Record | ID | Detail |
| - | - | - |
| Ad account | `501001` | "Acme · US growth", USD. The token manages it. |
| Ad account | `501002` | "Acme · Europe (restricted)", EUR. Not accessible. |
| Campaign group | `601001` | "Q4 enterprise pipeline", active, total budget 12000 USD. |
| Campaign | `701001` | "Ridgeway Robotics · operations leaders", active, targeting Ridgeway Robotics employees in the United States. |
| Campaign | `701002` | "Enterprise playbook · retest", paused. |
| Creative | `urn:li:sponsoredCreative:901001` | "Ridgeway operations guide", active and approved. |
| Creative | `urn:li:sponsoredCreative:901002` | "Pipeline guide revision", active, review pending. |

Both creatives reference one sponsored post, "A clearer operations pipeline for Ridgeway". Daily analytics cover 2026-10-24 and 2026-10-25, for example 14,200 impressions, 117 clicks and 132.40 USD for campaign 701001 on 2026-10-24.

## Checks

LinkedIn Ads has no state checks. Use trace checks, for example `{ called: "POST /rest/adAccounts/501001/adCampaigns/701001" }`.

## Limits

* Single-image sponsored content only; no image upload, video, lead forms or audiences.
* Historical analytics only; no auction or delivery.


## Related topics

- [Worlds](https://docs.ancha.io/concepts/worlds.md)
- [Tools](https://docs.ancha.io/tools/overview.md)
- [Troubleshooting](https://docs.ancha.io/troubleshooting.md)
- [Introduction](https://docs.ancha.io/index.md)
- [Changelog](https://docs.ancha.io/changelog.md)


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