Bulk Edit Targeting

📘

Migration Notes from 0.5 API

While the Buzz 0.5 and 2.0 APIs co-exist, your individual account must be set to work with one or the other APIs with regard to targeting. If you are not sure whether your account is ready to work with the new targeting-expressions resources please contact your account manager. Note, the bulk edit functionality is only available for the 2.0 API.

Bulk Edit Concepts

You can edit targeting expressions in bulk using the /line-items/bulk-targeting resource. There are three actions supported and multiple actions and values can be included in one request.

ActionBehavior
AddAdd combinations of predicate and value to a targeting key within an existing expression.
RemoveRemove combinations of predicate and value within a targeting key with.
ReplaceReplace combinations of predicate and value within a targeting key with combinations defined.

A bulk edit request consists of an ids field containing a list of line item IDs and a commands field containing a list of command objects. A command object consists of a required key for targeting key, a required action field, and action-specific fields to_group, from_groups, add, remove described below. In addition to the validation described below, a command object should either have from_groups or have to_group set each containing the key group, predicate group, and pairs to instruct the application where to remove predicates from and where to add predicates to. See the targeting doc for detailed explanation on predicate groups.

Example Requests

Below are some truncated snippet examples of a bulk edit request:

{
  // Specify Line Item IDs
  "ids": [
    2782,
    2712,
    2679,
    2677
  ],
  "commands": [
    // Add "GBR" in the country targeting key to the "none" key group and "any" predicate group.
    {
      "action": "add",
      "key": "country",
      "to_group": [
        "none",
        "any"
      ],
      "add": [
        {
          "value": "GBR",
          "comparator": "equals"
        }
      ]
    },
   // Remove all Deal IDs 
   {
      "action": "remove",
      "key": "deal_id",
      "from_groups": [
        [
          "all",
          "any"
        ],
        [
          "none",
          "any"
        ],
        [
          "all",
          "all"
        ]
      ]
    },
    // Remove placement IDs "adx/1", "stv/agltb3B1Yi1w" from the "all" key group and "any" predicate group. 
    {
      "action": "remove",
      "key": "placement",
      "from_groups": [
        [
          "all",
          "any"
        ]
      ],
      "remove": [
        {
          "value": "adx/1",
          "comparator": "equals"
        },
        {
          "value": "stv/agltb3B1Yi1w",
          "comparator": "equals"
        }
      ]
    },
    // Replace the city "2643743" with "5128581" wihin the "all" key group and "any" predicate group. 
    {
      "action": "replace",
      "key": "city",
      "from_groups": [
        [
          "all",
          "any"
        ]
      ],
      "to_group": [
        "all",
        "any"
      ],
      "add": [
        {
          "value": "2643743",
          "comparator": "equals"
        }
      ],
      "remove": [
        {
          "value": "5128581",
          "comparator": "equals"
        }
      ]
    }
  ]
}

If no values are passed in the remove field on a command with action remove, all targeted values within the key group-predicate group pairs passed in the from_groups of the targeting key will be removed. A combination of remove and add actions can be used to conduct a "Replace all values with" / "Set targeting key to" functionality. If action is set to replace, both add and remove fields are required. In a replace command, predicates in add will be added to a targeting expression if and only if the targeting expression had any matching predicates in the remove field.

See examples below:

{
  "ids": [
    2782,
    2712,
    2679,
    2677
  ],
  "commands": [
    {
      "action": "remove",
      "key": "city",
      "from_groups": [
        [
          "all",
          "any"
        ],
        [
          "none",
          "any"
        ],
        [
          "all",
          "all"
        ]
      ]
    },
    {
      "action": "add",
      "key": "city",
      "to_group": [
        "all",
        "any"
      ],
      "add": [
        {
          "value": "2643743",
          "comparator": "equals"
        }
      ]
    }
  ]
}

Range Targeting and Time Targeting Key

For non-time targeting keys that use the in_range (currently, only ip_address), the only available options will be remove without values specified (equivalent to "clear all values". Optionally an add action can be conducted following the remove action (equivalent to "Replace all values with").

This applies to the time targeting keys time_of_week and user_time_of_week as well. In addition, any remove action will translate to two remove commands, one for user_time_of_week and one for time_of_week, followed by an optional add command.

Segment Recency

When using the bulk edit feature on segment targeting, options for setting segment recency differ between the edit actions.

For any remove or replace action, a recency value is neither required nor accepted in the remove field. The remove in the operation will simply look up the segment irrespective of any recency value it may have applied.

For any actions where a segment is added to targeting through an add or replace, a recency value may be defined in the add field.

The Targeting guide have a detailed explanation on how segment recency works. Here's a bulk edit example:

{
  "ids": [
    3023
  ],
  "commands": [
    {
      "action": "replace",
      "key": "segment",
      "from_groups": [
        [
          "all",
          "any"
        ]
      ],
      "to_group": [
        "all",
        "any"
      ],
      "add": [
        {
          "value": "canary2-123",
          "comparator": "equals",
          "recency": {
            "start": null,
            "end": 480
          }
        }
      ],
      "remove": [
        {
          "value": "canary2-15137",
          "comparator": "equals"
        }
      ]
    }
  ]
}

Processing Rules

The entire bulk edit operation is conducted within a single transaction. Prior to applying the bulk edit commands, the API will iterate over all of the Line Items for the IDs provided and check for existing targeting expressions. If any line items are missing targeting expressions, new, empty targeting expressions will be created and assigned to the line items. All of this will be done within the transaction and will be rolled back if validation errors are detected after applying the bulk edit commands.

Success Response

The successful response body will be a list of objects each with id, targeting_expression_id, and created field indicating whether or not a new targeting expression was created for the line item. Example:

[
    {
        "id": 1,
        "targeting_expression_id": 1,
        "created": false
    },
    {
        "id": 2,
        "targeting_expression_id": 2,
        "created": true
    },
    {
        "id": 3,
        "targeting_expression_id": 3,
        "created": false
    }
]

Error Response

There are 2 classes of possible validation errors:

  1. Badly formatted input
  2. The bulk operations left targeting expression(s) in an invalid state.

For badly formatted input, the error response will mirror the request. For example: if more than the maximum number of ids allowed are provided:

{
    "ids": [
        "Ensure this field has no more than 1000 elements."
    ]
}

When the bulk operations left targeting expressions in an invalid state, the error response body will mirror the success response body. It will be a list of dicts containing line_item_id, targeting_expression_id and any surfaced errors. The errors object will be the same field-level validation errors object that is returned from unsuccessful requests to the targeting-expressions endpoint. For example, if a bulk edit left modules empty for one of the targeting expressions:

[
    {
        "id": 123,
        "targeting_expression_id": 345,
        "errors": null,
    },
    {
        "id": 234,
        "targeting_expression_id": 456,
        "errors": {
            "modules": [
                "This dictionary may not be empty."
            ]
        }
    }
]

What’s Next