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

# Targetings

> List, get, create, rename, and delete context targetings with the Context Targeting API.

A targeting holds the targeting options that advertisers choose from when they book a campaign. Use these endpoints to manage targetings. To manage the options inside a targeting, see [Targeting Options](/integrations/context-targeting/options).

* Read endpoints require the `context-targeting:read` scope, and write endpoints require `context-targeting:write`. See [Prerequisites](/integrations/context-targeting/overview#prerequisites).
* Your API key determines the project, so paths don't include a project ID.
* Each endpoint lists only its own errors. For errors that apply to all endpoints, see [Error Codes](/integrations/context-targeting/errors#error-codes).

***

## Targeting Object

The list, get, create, and rename endpoints return targetings in the following format. Delete endpoints return only `_id`. In API fields, options are called `categories`.

| Field | Type | Description |
| - | - | - |
| `_id` | string | Targeting ID (26-character ULID). The server generates it. |
| `name` | string | Targeting name |
| `categories` | object\[] | All options in the targeting, including option groups and their sub-options. Each item is an [option object](/integrations/context-targeting/options#option-object) that has the number of Context IDs (`contextCount`) but not the Context IDs themselves. |
| `categoryCount` | number | Number of options in the targeting, including sub-options. Always included. |
| `syncedAt` | number | Time the most recent load of this targeting into ad serving started, in epoch milliseconds. Changes that succeeded at or before this time have been loaded. |
| `createdAt` | string | Time the targeting was created (ISO 8601, UTC) |
| `updatedAt` | string | Time the targeting was last updated (ISO 8601, UTC). It also changes when the targeting is loaded into ad serving. |

`categories` and `syncedAt` aren't included in every response:

| Response | `categories` | `syncedAt` |
| - | - | - |
| [List Targetings](#list-targetings), [Get a Targeting](#get-a-targeting) | Included by default. Omitted with `includeCategories=false`. | Included when available |
| [Create a Targeting](#create-a-targeting), [Create Targetings in Bulk](#create-targetings-in-bulk) | Included | Omitted, because a new targeting hasn't been loaded yet |
| [Rename a Targeting](#rename-a-targeting), [Rename Targetings in Bulk](#rename-targetings-in-bulk) | Omitted | Included when available |

`syncedAt` is omitted until the targeting's first load finishes. After you change Context IDs, add an option, or move or detach an option, it's usually omitted until the next load finishes.

<Note>
  To check whether a change has been loaded, compare the time the change succeeded with `syncedAt`. Don't rely on whether `syncedAt` is present. See [When Changes Take Effect](/integrations/context-targeting/overview#when-changes-take-effect).
</Note>

***

## List Targetings

Returns all context targetings in your project. Audience targetings aren't included, and the list isn't paginated.

### Request

```http theme={null}
GET /context-targeting
```

Requires the `context-targeting:read` scope.

### Query Parameters

| Parameter | Type | Required | Default | Description |
| - | - | :-: | - | - |
| `includeCategories` | boolean | No | `true` | Whether to include `categories`. With `false`, `categories` is omitted, and `categoryCount` still shows the number of options. Use `false` when your targetings have many options, and read the options page by page with [List Options](/integrations/context-targeting/options#list-options). Values other than `true` and `false` return `400`. |

### Example Request

```bash theme={null}
curl "https://lake.adrop.io/context-targeting?includeCategories=false" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

### Example Response

`200` with an array of [targeting objects](#targeting-object):

```json theme={null}
[
  {
    "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y",
    "name": "News Sections",
    "categoryCount": 2,
    "syncedAt": 1791854650000,
    "createdAt": "2026-10-13T01:23:45.000Z",
    "updatedAt": "2026-10-13T01:24:12.000Z"
  }
]
```

***

## Get a Targeting

Returns one context targeting.

### Request

```http theme={null}
GET /context-targeting/{targetingId}
```

Requires the `context-targeting:read` scope.

### Path Parameters

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `targetingId` | string | Yes | Targeting ID |

### Query Parameters

| Parameter | Type | Required | Default | Description |
| - | - | :-: | - | - |
| `includeCategories` | boolean | No | `true` | Whether to include `categories`. With `false`, `categories` is omitted, and `categoryCount` still shows the number of options. Values other than `true` and `false` return `400`. |

### Example Request

```bash theme={null}
curl "https://lake.adrop.io/context-targeting/01JAB3XK5Q8V7M2N4P6R9T0W1Y" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

### Example Response

`200` with a [targeting object](#targeting-object):

```json theme={null}
{
  "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y",
  "name": "News Sections",
  "categories": [
    {
      "_id": "01JAB3XK5RA1B2C3D4E5F6G7H8",
      "name": "Sports",
      "type": "atomic",
      "contextCount": 3,
      "createdAt": "2026-10-13T01:23:45.000Z",
      "updatedAt": "2026-10-13T01:23:45.000Z"
    },
    {
      "_id": "01JAB3XK5RA1B2C3D4E5F6G7H9",
      "name": "Tech",
      "type": "atomic",
      "contextCount": 3,
      "createdAt": "2026-10-13T01:23:45.000Z",
      "updatedAt": "2026-10-13T01:23:45.000Z"
    }
  ],
  "categoryCount": 2,
  "syncedAt": 1791854650000,
  "createdAt": "2026-10-13T01:23:45.000Z",
  "updatedAt": "2026-10-13T01:24:12.000Z"
}
```

To read the Context IDs of an option, use [Get an Option](/integrations/context-targeting/options#get-an-option).

**Errors**

| Status | `errorCode` | When |
| - | - | - |
| 404 | `TARGETING_NOT_FOUND` | Your project has no context targeting with this ID. The ID of an audience targeting also returns this error. |

***

## Create a Targeting

Creates a context targeting. You can create its options in the same request.

### Request

```http theme={null}
POST /context-targeting
```

Requires the `context-targeting:write` scope.

### Request Body

| Field | Type | Required | Default | Description |
| - | - | :-: | - | - |
| `name` | string | Yes | — | Targeting name, 2–36 characters. Must be unique among all targetings in your project, including audience targetings. See [Name Rules](/integrations/context-targeting/errors#name-rules). |
| `categories` | object\[] | No | — | Options to create with the targeting. Up to 100 options per request, counting sub-options. |

Each item in `categories` takes the following fields:

| Field | Type | Required | Default | Description |
| - | - | :-: | - | - |
| `name` | string | Yes | — | Option name, 2–36 characters. Must be unique within the targeting, including option groups and sub-options. |
| `contexts` | string\[] | No | — | Context IDs of the option. For an option group, the option group's own Context IDs. See [Context ID Rules](/integrations/context-targeting/options#context-id-rules). |
| `type` | string | No | See description | `atomic` (a regular option) or `collection`. If omitted, the option is an option group when `children` is present, even as an empty array, and `atomic` otherwise. |
| `children` | object\[] | No | — | Option group only. Sub-options to create, each with `name` (required) and `contexts`. |
| `exposeChildren` | boolean | No | `false` | Option group only. Whether to show sub-options to advertisers. See [Show Sub-options to Advertisers](/integrations/context-targeting/option-groups#show-sub-options-to-advertisers). |

* A request can include up to 10,000 Context IDs in total, including those of sub-options.
* The server generates all IDs. A request that includes `_id` fails with `400`.
* Items in `categories` can't include `parent`. A request that includes it fails with `400`. To add an option to an existing option group, see [Add an Option to an option group](/integrations/context-targeting/option-groups#add-an-option-to-an-option-group).
* To create more than 100 options, create the targeting first, and then use [Add Options in Bulk](/integrations/context-targeting/options#add-options-in-bulk).

For how option groups work, see [Create an option group](/integrations/context-targeting/option-groups#create-an-option-group).

### Example Request

```bash theme={null}
curl -X POST https://lake.adrop.io/context-targeting \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "News Sections",
    "categories": [
      { "name": "Sports", "contexts": ["sport", "baseball", "soccer"] },
      { "name": "Tech", "contexts": ["tech", "ai", "mobile"] }
    ]
  }'
```

### Example Response

`201` with the new [targeting object](#targeting-object), including its options:

```json theme={null}
{
  "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y",
  "name": "News Sections",
  "categories": [
    {
      "_id": "01JAB3XK5RA1B2C3D4E5F6G7H8",
      "name": "Sports",
      "type": "atomic",
      "contextCount": 3,
      "createdAt": "2026-10-13T01:23:45.000Z",
      "updatedAt": "2026-10-13T01:23:45.000Z"
    },
    {
      "_id": "01JAB3XK5RA1B2C3D4E5F6G7H9",
      "name": "Tech",
      "type": "atomic",
      "contextCount": 3,
      "createdAt": "2026-10-13T01:23:45.000Z",
      "updatedAt": "2026-10-13T01:23:45.000Z"
    }
  ],
  "categoryCount": 2,
  "createdAt": "2026-10-13T01:23:45.000Z",
  "updatedAt": "2026-10-13T01:23:45.000Z"
}
```

Save the `_id` of the targeting and of each option. You need them to change the targeting later.

**Errors**

| Status | `errorCode` | When |
| - | - | - |
| 409 | `TARGETING_NAME_DUPLICATE` | A targeting in your project already uses `name`. If it's a context targeting, `detail.existingId` is its ID. Otherwise, `detail` is omitted. |
| 409 | `TARGETING_CATEGORY_NAME_DUPLICATE` | Two options in `categories`, including sub-options, have the same name. |
| 400 | `TARGETING_CATEGORY_NOT_SUPPORTED` | An option's fields don't match its type. For example, an option group has neither sub-options nor Context IDs of its own, `children` is sent with `type: "atomic"`, or `exposeChildren` is sent for a regular option. The targeting isn't created. |
| 400 | `TARGETING_CONTEXT_LIMIT_EXCEEDED` | The project would exceed its total number of Context IDs. See [Limits](/integrations/context-targeting/errors#limits). |
| 400 | `TARGETING_COLLECTION_CONTEXT_DUPLICATED` | An option group's own Context ID is already an own Context ID of another option group in the project or in the same request. `detail.conflicts` lists the duplicates. See [Constraints](/integrations/context-targeting/option-groups#constraints). |

If the name is already in use, the response looks like this:

```json theme={null}
{
  "statusCode": 409,
  "errorCode": "TARGETING_NAME_DUPLICATE",
  "detail": {
    "existingId": "01JAB3XK5Q8V7M2N4P6R9T0W1Y"
  }
}
```

<Tip>
  Creating isn't idempotent. If a create request times out or fails with a `5xx` error, you can send it again. If the first request had succeeded, the resend fails with `409 TARGETING_NAME_DUPLICATE`, and `detail.existingId` is the ID of the targeting that the first request created. See [Retries and Duplicate Requests](/integrations/context-targeting/errors#retries-and-duplicate-requests).
</Tip>

***

## Rename a Targeting

Changes the name of a targeting. Its options and Context IDs don't change.

### Request

```http theme={null}
PATCH /context-targeting/{targetingId}
```

Requires the `context-targeting:write` scope.

### Path Parameters

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `targetingId` | string | Yes | Targeting ID |

### Request Body

| Field | Type | Required | Description |
| - | - | :-: | - |
| `name` | string | Yes | New targeting name, 2–36 characters. Must be unique among all targetings in your project, including audience targetings. You can send the current name. See [Name Rules](/integrations/context-targeting/errors#name-rules). |

### Example Request

```bash theme={null}
curl -X PATCH https://lake.adrop.io/context-targeting/01JAB3XK5Q8V7M2N4P6R9T0W1Y \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Article Sections" }'
```

### Example Response

`200` with the renamed [targeting object](#targeting-object), without `categories`. To read its options, use [Get a Targeting](#get-a-targeting) or [List Options](/integrations/context-targeting/options#list-options).

```json theme={null}
{
  "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y",
  "name": "Article Sections",
  "categoryCount": 2,
  "syncedAt": 1791854650000,
  "createdAt": "2026-10-13T01:23:45.000Z",
  "updatedAt": "2026-10-13T02:10:00.000Z"
}
```

**Errors**

| Status | `errorCode` | When |
| - | - | - |
| 404 | `TARGETING_NOT_FOUND` | Your project has no context targeting with this ID. |
| 409 | `TARGETING_NAME_DUPLICATE` | Another targeting in your project already uses `name`. If it's a context targeting, `detail.existingId` is its ID. |

***

## Delete a Targeting

Deletes a targeting and all of its options, including option groups and sub-options.

<Warning>
  You can't delete a targeting while an approved campaign that hasn't ended includes or excludes any of its options. The request fails with `400 TARGETING_LOCKED`, and nothing is deleted. Deleting individual options isn't blocked this way. See [Delete an Option](/integrations/context-targeting/options#delete-an-option).
</Warning>

### Request

```http theme={null}
DELETE /context-targeting/{targetingId}
```

Requires the `context-targeting:write` scope.

### Path Parameters

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `targetingId` | string | Yes | ID of the targeting to delete |

### Example Request

```bash theme={null}
curl -X DELETE https://lake.adrop.io/context-targeting/01JAB3XK5Q8V7M2N4P6R9T0W1Y \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

### Example Response

`200` with only the ID of the deleted targeting:

```json theme={null}
{
  "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y"
}
```

**Errors**

| Status | `errorCode` | When |
| - | - | - |
| 404 | `TARGETING_NOT_FOUND` | Your project has no context targeting with this ID. If you resent a delete request that had succeeded, the targeting is already deleted. |
| 400 | `TARGETING_LOCKED` | An approved campaign that hasn't ended includes or excludes one of the targeting's options. |

***

## Bulk Operations

Create, rename, or delete up to 100 targetings in one request.

* The request is checked as a whole first: the number of items (1–100), the format of each field, and the totals per request. If the check fails, the whole request fails with `400`, and nothing is applied.
* If another API write for your project is in progress, the whole request can fail with `409 CONTEXT_TARGETING_WRITE_IN_PROGRESS`, and nothing is applied. See [Concurrent Writes](/integrations/context-targeting/errors#concurrent-writes).
* Otherwise, the response is `200` with a result for each item, even if every item fails. Some items can succeed while others fail, so check `success` for each item.

| Field | Type | Description |
| - | - | - |
| `results` | object\[] | One result per item, in request order |
| `results[].index` | number | Position of the item in the request's `items` or `ids`, starting at 0 |
| `results[].success` | boolean | Whether the item succeeded |
| `results[].data` | object | Result of a successful item. Omitted for a failed item. |
| `results[].error` | object | Error of a failed item: `statusCode`, `errorCode`, and, for some errors, `detail`. Omitted for a successful item. |
| `succeeded` | number | Number of items that succeeded |
| `failed` | number | Number of items that failed |

Create and delete requests apply the items that pass their checks together. If an unexpected error occurs, nothing in the request is applied: items that failed their checks keep their errors, and the other items fail with `500 UNCATCHED`. Send the same request again. Rename requests apply each item separately, in request order. For details, see [Bulk Responses](/integrations/context-targeting/errors#bulk-responses).

### Create Targetings in Bulk

Creates up to 100 targetings, each with or without options.

#### Request

```http theme={null}
POST /context-targeting/bulk/create
```

Requires the `context-targeting:write` scope.

#### Request Body

| Field | Type | Required | Description |
| - | - | :-: | - |
| `items` | object\[] | Yes | Targetings to create, 1–100. Each item takes the same fields as the [Create a Targeting](#create-a-targeting) request body. |

Across all items, a request can include up to 100 options, counting sub-options, and up to 10,000 Context IDs.

#### Example Request

```bash theme={null}
curl -X POST https://lake.adrop.io/context-targeting/bulk/create \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "name": "Video Sections",
        "categories": [
          { "name": "Highlights", "contexts": ["highlight", "replay"] }
        ]
      },
      {
        "name": "Podcast Sections",
        "categories": [
          { "name": "Interviews", "contexts": ["interview", "talk"] }
        ]
      },
      { "name": "News Sections" }
    ]
  }'
```

#### Example Response

The `data` of a successful item is the new [targeting object](#targeting-object), including its options. In this example, the third item fails because a targeting named "News Sections" already exists.

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "success": true,
      "data": {
        "_id": "01JAB3XK5WE1F2G3H4J5K6M7N8",
        "name": "Video Sections",
        "categories": [
          {
            "_id": "01JAB3XK5XF1G2H3J4K5M6N7P8",
            "name": "Highlights",
            "type": "atomic",
            "contextCount": 2,
            "createdAt": "2026-10-13T02:20:00.000Z",
            "updatedAt": "2026-10-13T02:20:00.000Z"
          }
        ],
        "categoryCount": 1,
        "createdAt": "2026-10-13T02:20:00.000Z",
        "updatedAt": "2026-10-13T02:20:00.000Z"
      }
    },
    {
      "index": 1,
      "success": true,
      "data": {
        "_id": "01JAB3XK5WE1F2G3H4J5K6M7N9",
        "name": "Podcast Sections",
        "categories": [
          {
            "_id": "01JAB3XK5XF1G2H3J4K5M6N7P9",
            "name": "Interviews",
            "type": "atomic",
            "contextCount": 2,
            "createdAt": "2026-10-13T02:20:00.000Z",
            "updatedAt": "2026-10-13T02:20:00.000Z"
          }
        ],
        "categoryCount": 1,
        "createdAt": "2026-10-13T02:20:00.000Z",
        "updatedAt": "2026-10-13T02:20:00.000Z"
      }
    },
    {
      "index": 2,
      "success": false,
      "error": {
        "statusCode": 409,
        "errorCode": "TARGETING_NAME_DUPLICATE",
        "detail": {
          "existingId": "01JAB3XK5Q8V7M2N4P6R9T0W1Y"
        }
      }
    }
  ],
  "succeeded": 2,
  "failed": 1
}
```

Items fail with the same errors as [Create a Targeting](#create-a-targeting). When the name belongs to a targeting that an earlier item in the same request created, `TARGETING_NAME_DUPLICATE` has `detail.duplicateOfIndex`, the index of that item, instead of `detail.existingId`.

### Rename Targetings in Bulk

Renames up to 100 targetings.

#### Request

```http theme={null}
POST /context-targeting/bulk/update
```

Requires the `context-targeting:write` scope.

#### Request Body

| Field | Type | Required | Description |
| - | - | :-: | - |
| `items` | object\[] | Yes | Targetings to rename, 1–100 |
| `items[]._id` | string | Yes | Targeting ID |
| `items[].name` | string | Yes | New targeting name. Follows the same rules as [Rename a Targeting](#rename-a-targeting). |

#### Example Request

```bash theme={null}
curl -X POST https://lake.adrop.io/context-targeting/bulk/update \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y", "name": "Article Sections" }
    ]
  }'
```

#### Example Response

The `data` of a successful item is the renamed [targeting object](#targeting-object), without `categories`.

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "success": true,
      "data": {
        "_id": "01JAB3XK5Q8V7M2N4P6R9T0W1Y",
        "name": "Article Sections",
        "categoryCount": 2,
        "syncedAt": 1791854650000,
        "createdAt": "2026-10-13T01:23:45.000Z",
        "updatedAt": "2026-10-13T02:10:00.000Z"
      }
    }
  ],
  "succeeded": 1,
  "failed": 0
}
```

Items fail with the same errors as [Rename a Targeting](#rename-a-targeting).

### Delete Targetings in Bulk

Deletes up to 100 targetings and all of their options.

#### Request

```http theme={null}
POST /context-targeting/bulk/delete
```

Requires the `context-targeting:write` scope.

#### Request Body

| Field | Type | Required | Description |
| - | - | :-: | - |
| `ids` | string\[] | Yes | IDs of the targetings to delete, 1–100 |

#### Example Request

```bash theme={null}
curl -X POST https://lake.adrop.io/context-targeting/bulk/delete \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["01JAB3XK5Q8V7M2N4P6R9T0W1Y"]
  }'
```

#### Example Response

The `data` of a successful item has only the `_id` of the deleted targeting. In this example, an approved campaign that hasn't ended includes one of the targeting's options, so the targeting isn't deleted.

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "success": false,
      "error": {
        "statusCode": 400,
        "errorCode": "TARGETING_LOCKED"
      }
    }
  ],
  "succeeded": 0,
  "failed": 1
}
```

Items fail with the same errors as [Delete a Targeting](#delete-a-targeting).


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