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

# Keywords

export const EndpointBadge = ({method = "GET", children}) => {
  const METHOD_STYLES = {
    GET: {
      bg: "mint-bg-[#2AB673]"
    },
    POST: {
      bg: "mint-bg-[#3064E3]"
    },
    PUT: {
      bg: "mint-bg-[#C28C30]"
    },
    PATCH: {
      bg: "mint-bg-[#DA622B]"
    },
    DELETE: {
      bg: "mint-bg-[#CB3A32]"
    },
    API: {
      bg: "mint-bg-black"
    }
  };
  const key = method.toUpperCase();
  const styles = METHOD_STYLES[key] ?? METHOD_STYLES.API;
  return <div className="relative mt-7">
      <span className={`absolute -top-2 -left-2 z-10 ${styles.bg} text-white px-2.5 py-0.5 rounded-full text-xs font-bold tracking-wide`}>
        {key}
      </span>
      {children}
    </div>;
};

<Info>
  **A Few Things to Know**

  Shoppers browsing through the retailer's search page may utilize search for phrases associated with line item products where the line item may not be allowed to search on that page. Similar to this scenario, the shopper can also enter search phrases that align with products permitted to serve on a page. The keyword API endpoint allows you to control your Onsite Sponsored Products line item by providing visibility to users what keywords are applied to line items, and also allows for users to determine which keyword to target positively or negatively. The endpoint can also provide keyword bidding capabilities to optimize line items based on relevant keywords.

  Check out the [**Onsite Sponsored Products**](/retail-media/v2025.01/docs/onsite-sponsored-products) page for a complete summary of Criteo's keyword service.
</Info>

## **Endpoints**

| Verb     | Endpoint                                        | Description                                                      |
| -------- | ----------------------------------------------- | ---------------------------------------------------------------- |
| **GET**  | `/line-items/{lineItemId}/keywords`             | Retrieve a set of positive and negative keywords for a line item |
| **GET**  | `/line-items/{lineItemId}/keywords/recommended` | Retrieve a collection of recommended keywords for a line item    |
| **POST** | `/line-items/{lineItemId}/keywords/add-remove`  | Add or remove keywords from a line item                          |
| **POST** | `/line-items/{lineItemId}/keywords/set-bid`     | Set a bid override at keyword level                              |

## **Attributes**

<ResponseField name="id" required>
  **Data Type:** string

  **Default:** Computerized value

  **Description:** The external line item id
</ResponseField>

<ResponseField name="reviewState">
  **Data Type:** enum

  **Default:** `InReview`

  **Description:** Review the keyword's status, only applicable for `PositiveExactMatch` keywords.

  **Values:** Keywords not reviewed by the automatic keyword service will be reviewed and approved by the retailer.

  * `InReview` - keyword has been submitted manually, and the review is still pending
  * `Approved` - keyword was approved manually
  * `AutoApproved` - keyword was approved automatically
  * `Rejected` - keyword was rejected manually
  * `AutoRejected` - keyword was rejected automatically
  * `Recommended` - keyword was recommended by our keyword model
</ResponseField>

<ResponseField name="matchType" required>
  **Data Type:** enum

  **Default:** `PositiveExactMatch`

  **Description:** The matching algorithm to be used when comparing this keyword with shopper search phrases.

  **Values:**

  * `PositiveExactMatch` - normalized keyword is an exact match for the normalized search phrase bid
  * `NegativeExactMatch` - normalized keyword is an exact match for the normalized search phrase do not bid
  * `NegativeBroadMatch` - normalized keyword is a substring of the normalized search phrase do not bid
</ResponseField>

<ResponseField name="bid">
  **Data Type:** decimal

  **Default:** `null`

  **Description:** The bid override for the positive keyword. The keyword will use the default line item bid if the value is `null`. The currency of the bid is the default currency for the retailer.

  **Values:** decimal value

  * Keyword bids must be **equal or greater than** the retailer `minBid` and **equal or less than** the line item `maxBid`.
  * You may use the [Open Auction Line Item ](/retail-media/docs/onsite-sponsored-products-line-items)API to view and check if you're setting a keyword bid that is more than the allowed amount. You may also reference the [Catalog](/retail-media/docs/catalog-endpoints) API to check for the product sku minimum bid, which offers the retailer min. bid value.
</ResponseField>

<ResponseField name="isDeleted">
  **Data Type:** boolean

  **Default:** `null`

  **Description:** Controls if the keyword will be added or removed from the line item.

  **Values:** `true`, `false`
</ResponseField>

<ResponseField name="inputKeywords" required>
  **Data Type:** number

  **Default:** N/A

  **Description:** Keywords supplied by the user matching this normalized keyword phrase binned by match type.

  **Values:**

  * `negativeBroad` - collection of supplied negative broad phrases
  * `negativeExact` - collection of supplied negative exact phrases
  * `positiveExact` - collection of supplied positive exact phrases
</ResponseField>

<ResponseField name="createdAt">
  **Data Type:** date-time

  **Default:** Computerized value

  **Description:** Date keyword was created in the line item (or recommended to line item)

  **Values:** yyyy-mm-dd T hh:mm:ss
</ResponseField>

<ResponseField name="updatedAt">
  **Data Type:** date-time

  **Default:** Computerized value

  **Description:** Last date keyword was updated in the line item (or recommended to line item)

  **Values:** yyyy-mm-dd T hh:mm:ss
</ResponseField>

<ResponseField name="phrase">
  **Data Type:** string

  **Default:** `null`

  **Description:** Raw text of the keyword to be added or removed.

  **Values:** minLength: 0, maxLeght: 255
</ResponseField>

## **Get Keywords by Line Item Id**

<EndpointBadge method="get">
  ```http theme={null}
  https://api.criteo.com/{version}/retail-media/line-items/{lineItemId}/keywords
  ```
</EndpointBadge>

**Sample Request**

<CodeGroup>
  ```bash cURL theme={null}
  curl -L -X GET 'https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords' \
    -H 'Accept: application/json' \
    -H 'Authorization: Bearer <MY_ACCESS_TOKEN>'
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("api.criteo.com")
  payload = ''
  headers = {
    'Accept': 'application/json',
    'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
  }
  conn.request("GET", "/{version}/retail-media/line-items/358669652976373760/keywords", payload, headers)
  res = conn.getresponse()
  data = res.read()
  print(data.decode("utf-8"))
  ```

  ```java Java theme={null}
  OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
  MediaType mediaType = MediaType.parse("text/plain");
  RequestBody body = RequestBody.create(mediaType, "");
  Request request = new Request.Builder()
    .url("https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
    .build();
  Response response = client.newCall(request).execute();
  ```

  ```php PHP theme={null}
  <?php
  require_once 'HTTP/Request2.php';
  $request = new HTTP_Request2();
  $request->setUrl('https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords');
  $request->setMethod(HTTP_Request2::METHOD_GET);
  $request->setConfig(array(
    'follow_redirects' => TRUE
  ));
  $request->setHeader(array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
  ));
  try {
    $response = $request->send();
    if ($response->getStatus() == 200) {
      echo $response->getBody();
    }
    else {
      echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
      $response->getReasonPhrase();
    }
  }
  catch(HTTP_Request2_Exception $e) {
    echo 'Error: ' . $e->getMessage();
  }
  ```
</CodeGroup>

**Sample Response**

<CodeGroup>
  ```json JSON expandable theme={null}
  {
      "data": {
          "id": "358669652976373760",
          "type": "RetailMediaKeywordsModel",
          "attributes": {
              "keywords": {
                  "vegetable": {
                      "matchType": "NegativeBroadMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [
                              "vegetable"
                          ],
                          "negativeExact": [],
                          "positiveExact": []
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "tomato": {
                      "matchType": "NegativeExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [
                              "tomatoes"
                          ],
                          "positiveExact": []
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "strawberry": {
                      "matchType": "NegativeExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [
                              "strawberry"
                          ],
                          "positiveExact": []
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "broccoli": {
                      "matchType": "NegativeExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [
                              "broccoli"
                          ],
                          "positiveExact": []
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "banana": {
                      "matchType": "NegativeExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [
                              "banana"
                          ],
                          "positiveExact": []
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "pasta": {
                      "reviewState": "Approved",
                      "matchType": "PositiveExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [],
                          "positiveExact": [
                              "pasta"
                          ]
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "milk": {
                      "reviewState": "Approved",
                      "matchType": "PositiveExactMatch",
                      "bid": 0.50,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [],
                          "positiveExact": [
                              "milk"
                          ]
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "juice": {
                      "reviewState": "Approved",
                      "matchType": "PositiveExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [],
                          "positiveExact": [
                              "juice"
                          ]
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "egg": {
                      "reviewState": "Approved",
                      "matchType": "PositiveExactMatch",
                      "bid": 0.50,
                      "inputKeywords": {
                          "negativeBroad": [],
                          "negativeExact": [],
                          "positiveExact": [
                              "eggs"
                          ]
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  },
                  "fruit": {
                      "matchType": "NegativeBroadMatch",
                      "bid": null,
                      "inputKeywords": {
                          "negativeBroad": [
                              "fruits"
                          ],
                          "negativeExact": [],
                          "positiveExact": []
                      },
                      "createdAt": "2025-01-01T00:00:00",
                      "updatedAt": "2025-01-01T00:00:00"
                  }
              }
          }
      },
      /* omitted if no errors */
      "errors": [],
      /* omitted if no warnings */
      "warnings": []
  }
  ```
</CodeGroup>

## **Get Recommended Keywords by Line Item Id**

This endpoint retrieves a collection of recommended keywords for a line item, created automatically by our keyword models.

<Info>
  **A FEW THINGS TO KNOW**

  * Only the top 100 keywords will be returned
  * Automatic recommended keywords can change day to day, as are determined based on click volumes by users on Retailer's environment. Although significant changes are not expected, it is possible that the long tail of the top 100 keywords change slightly
</Info>

<EndpointBadge method="get">
  ```http theme={null}
  https://api.criteo.com/{version}/retail-media/line-items/{lineItemId}/keywords/recommended
  ```
</EndpointBadge>

**Sample Request**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.criteo.com/{version}/retail-media/line-items/487311207809134592/keywords/recommended" \
    -H 'Accept: application/json' \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>"
  ```

  ```python Python theme={null}
  import requests

  url = "https://api.criteo.com/{version}/retail-media/line-items/487311207809134592/keywords/recommended"

  payload={}
  headers = {
    'Accept': 'application/json',
    'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
  }

  response = requests.request("GET", url, headers=headers, data=payload)

  print(response.text)
  ```

  ```java Java theme={null}
  OkHttpClient client = new OkHttpClient().newBuilder()
    .build();

  MediaType mediaType = MediaType.parse("text/plain");

  RequestBody body = RequestBody.create(mediaType, "");

  Request request = new Request.Builder()
    .url("https://api.criteo.com/{version}/retail-media/line-items/487311207809134592/keywords/recommended")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
    .build();

  Response response = client.newCall(request).execute();
  ```

  ```php PHP theme={null}
  <?php
  require_once 'HTTP/Request2.php';
  $request = new HTTP_Request2();
  $request->setUrl('https://api.criteo.com/{version}/retail-media/line-items/487311207809134592/keywords/recommended');
  $request->setMethod(HTTP_Request2::METHOD_GET);
  $request->setConfig(array(
    'follow_redirects' => TRUE
  ));

  $request->setHeader(array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
  ));

  try {
    $response = $request->send();
    if ($response->getStatus() == 200) {
      echo $response->getBody();
    }
    
    else {
      echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
      $response->getReasonPhrase();
    }
  }

  catch(HTTP_Request2_Exception $e) {
    echo 'Error: ' . $e->getMessage();
  }
  ```
</CodeGroup>

**Sample Response**

<CodeGroup>
  ```json JSON expandable theme={null}
  {
      "data": {
          "type": "RecommendedKeywords",
          "attributes": {
              "keywords": {
                  "bar sound": {
                      "reviewState": "AutoApproved",
                      "matchType": "PositiveExactMatch",
                      "bid": 1.0,
                      "inputKeywords": {
                          "positiveExact": [
                              "bar sound",
                              "sound bar",
                              "sound-bar",
                              "sound bars",
                              "sounds bar"
                          ]
                      },
                      "createdAt": "2025-01-01T07:00:00",
                      "updatedAt": "2025-01-01T08:00:00"
                  },
                  "dolby soundbar": {
                      "reviewState": "Recommended",
                      "matchType": "PositiveExactMatch",
                      "bid": null,
                      "inputKeywords": {
                          "positiveExact": [
                              "dolby soundbars",
                              "soundbar dolby"
                          ]
                      },
                      "createdAt": "2025-01-01T07:00:00",
                      "updatedAt": "2025-01-01T08:00:00"
                  },
                  "atmos": {
                      "matchType": "NegativeBroad",
                      "inputKeywords": {
                          "negativeBroad": [
                              "atmos"
                          ]
                      },
                      "createdAt": "2025-01-01T07:00:00",
                      "updatedAt": "2025-01-01T08:00:00"
                  }
              },
              "recommended": [
                  "atmos",
                  "dolby soundbars",
                  "sound bar",
                  "sound bars",
                  "soundbar dolby"
              ]
          }
      },
      /* omitted if no errors */
      "errors": [],
      /* omitted if no warnings */
      "warnings": []
  }
  ```
</CodeGroup>

## **Add or Remove Keyword from Line Item**

<EndpointBadge method="post">
  ```http theme={null}
  https://api.criteo.com/{version}/retail-media/line-items/{lineItemId}/keywords/add-remove
  ```
</EndpointBadge>

<Info>
  **Negative Targeting v1**

  The negative keyword targeting in this API will eventually replace the [Negative Keyword Targeting](/retail-media/docs/negative-keywords-open-auction-only) endpoints. You may continue using those endpoints without disrupting your services. We recommend reviewing and testing the new Keyword endpoints to prepare for a future migration to these new endpoints.
</Info>

**Sample Request**

<CodeGroup>
  ```bash cURL theme={null}
  curl -L -X POST 'https://api.criteo.com/{version}/retail-media/line-items/325713346766241792/keywords/add-remove' \
  -H 'Content-Type: application/json' \
  -H 'Accept: text/plain' \
  -H 'Authorization: Bearer <MY_ACCESS_TOKEN>' \
  --data-raw '{
  	"data": {
  		"type": "RetailMediaKeywordAddRemove",
  		"id": "325713346766241792",
  		"attributes": {
  			"keywords": [
  				{
  					"phrase": "cookies and bread",
  					"matchType": "PositiveExactMatch",
  					"isDeleted": "false"
  				},
  				{
  					"phrase": "raspberry",
  					"matchType": "NegativeExactMatch",
  					"isDeleted": "false"
  				},
                  
  				{
  					"phrase": "potatoes",
  					"matchType": "NegativeExactMatch",
  					"isDeleted": "true"
  				}
  			]
  		}
  	}
  }'
  ```

  ```python Python expandable theme={null}
  import http.client
  import json

  conn = http.client.HTTPSConnection("api.criteo.com")
  payload = json.dumps({
    "data": {
      "type": "RetailMediaKeywordAddRemove",
      "id": "325713346766241792",
      "attributes": {
        "keywords": [
          {
            "phrase": "cookies and bread",
            "matchType": "PositiveExactMatch",
            "isDeleted": "false"
          },
          {
            "phrase": "raspberry",
            "matchType": "NegativeExactMatch",
            "isDeleted": "false"
          },
          {
            "phrase": "potatoes",
            "matchType": "NegativeExactMatch",
            "isDeleted": "true"
          }
        ]
      }
    }
  })
  headers = {
    'Content-Type': 'application/json',
    'Accept': 'text/plain',
    'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
  }
  conn.request("POST", "/{version}/retail-media/line-items/358669652976373760/keywords/add-remove", payload, headers)
  res = conn.getresponse()
  data = res.read()
  print(data.decode("utf-8"))
  ```

  ```java Java theme={null}
  OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
  MediaType mediaType = MediaType.parse("application/json");
  RequestBody body = RequestBody.create(mediaType, "{\n\t\"data\": {\n\t\t\"type\": \"RetailMediaKeywordAddRemove\",\n\t\t\"id\": \"325713346766241792\",\n\t\t\"attributes\": {\n\t\t\t\"keywords\": [\n\t\t\t\t{\n\t\t\t\t\t\"phrase\": \"cookies and bread\",\n\t\t\t\t\t\"matchType\": \"PositiveExactMatch\",\n\t\t\t\t\t\"isDeleted\": \"false\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"phrase\": \"raspberry\",\n\t\t\t\t\t\"matchType\": \"NegativeExactMatch\",\n\t\t\t\t\t\"isDeleted\": \"false\"\n\t\t\t\t},\n                \n\t\t\t\t{\n\t\t\t\t\t\"phrase\": \"potatoes\",\n\t\t\t\t\t\"matchType\": \"NegativeExactMatch\",\n\t\t\t\t\t\"isDeleted\": \"true\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}");
  Request request = new Request.Builder()
    .url("https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords/add-remove")
    .method("POST", body)
    .addHeader("Content-Type", "application/json")
    .addHeader("Accept", "text/plain")
    .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
    .build();
  Response response = client.newCall(request).execute();
  ```

  ```php PHP expandable theme={null}
  <?php
  require_once 'HTTP/Request2.php';
  $request = new HTTP_Request2();
  $request->setUrl('https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords/add-remove');
  $request->setMethod(HTTP_Request2::METHOD_POST);
  $request->setConfig(array(
    'follow_redirects' => TRUE
  ));
  $request->setHeader(array(
    'Content-Type' => 'application/json',
    'Accept' => 'text/plain',
    'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
  ));
  $request->setBody('{
  \n	"data": {
  \n		"type": "RetailMediaKeywordAddRemove",
  \n		"id": "325713346766241792",
  \n		"attributes": {
  \n			"keywords": [
  \n				{
  \n					"phrase": "cookies and bread",
  \n					"matchType": "PositiveExactMatch",
  \n					"isDeleted": "false"
  \n				},
  \n				{
  \n					"phrase": "raspberry",
  \n					"matchType": "NegativeExactMatch",
  \n					"isDeleted": "false"
  \n				},
  \n                
  \n				{
  \n					"phrase": "potatoes",
  \n					"matchType": "NegativeExactMatch",
  \n					"isDeleted": "true"
  \n				}
  \n			]
  \n		}
  \n	}
  \n}');
  try {
    $response = $request->send();
    if ($response->getStatus() == 200) {
      echo $response->getBody();
    }
    else {
      echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
      $response->getReasonPhrase();
    }
  }
  catch(HTTP_Request2_Exception $e) {
    echo 'Error: ' . $e->getMessage();
  }
  ```
</CodeGroup>

**Sample Response** *200 successful status will return an empty object array*

<CodeGroup>
  ```json JSON theme={null}
  {}
  ```
</CodeGroup>

## **Set Bid on Keyword**

💡**Info**: Bids can be set on a keyword at any time, even when the keyword are still `InReview` state

<EndpointBadge method="post">
  ```http theme={null}
  https://api.criteo.com/{version}/retail-media/line-items/{lineItemId}/keywords/set-bid
  ```
</EndpointBadge>

**Sample Request**

<CodeGroup>
  ```bash cURL theme={null}
  curl -L -X POST 'https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords/set-bid' \
  -H 'Content-Type: application/json' \
  -H 'Accept: text/plain' \
  -H 'Authorization: Bearer <MY_ACCESS_TOKEN>' \
  --data-raw '{
    "data": {
      "type": "RetailMediaKeywordsSetBid",
      "id": "358669652976373760",
      "attributes": {
        "keywords": [
          {
            "phrase": "eggs",
            "bid": "0.50"
          },
          {
            "phrase": "milk",
            "bid": "0.50"
          }
        ]
      }
    }
  }'
  ```

  ```python Python expandable theme={null}
  import http.client
  import json

  conn = http.client.HTTPSConnection("api.criteo.com")
  payload = json.dumps({
    "data": {
      "type": "RetailMediaKeywordsSetBid",
      "id": "358669652976373760",
      "attributes": {
        "keywords": [
          {
            "phrase": "eggs",
            "bid": "0.50"
          },
          {
            "phrase": "milk",
            "bid": "0.50"
          }
        ]
      }
    }
  })
  headers = {
    'Content-Type': 'application/json',
    'Accept': 'text/plain',
    'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
  }
  conn.request("POST", "/{version}/retail-media/line-items/358669652976373760/keywords/set-bid", payload, headers)
  res = conn.getresponse()
  data = res.read()
  print(data.decode("utf-8"))
  ```

  ```python Python expandable theme={null}
  import http.client
  import json

  conn = http.client.HTTPSConnection("api.criteo.com")
  payload = json.dumps({
    "data": {
      "type": "RetailMediaKeywordsSetBid",
      "id": "358669652976373760",
      "attributes": {
        "keywords": [
          {
            "phrase": "eggs",
            "bid": "0.50"
          },
          {
            "phrase": "milk",
            "bid": "0.50"
          }
        ]
      }
    }
  })
  headers = {
    'Content-Type': 'application/json',
    'Accept': 'text/plain',
    'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
  }
  conn.request("POST", "/{version}/retail-media/line-items/358669652976373760/keywords/set-bid", payload, headers)
  res = conn.getresponse()
  data = res.read()
  print(data.decode("utf-8"))
  ```

  ```php PHP theme={null}
  <?php
  require_once 'HTTP/Request2.php';
  $request = new HTTP_Request2();
  $request->setUrl('https://api.criteo.com/{version}/retail-media/line-items/358669652976373760/keywords/set-bid');
  $request->setMethod(HTTP_Request2::METHOD_POST);
  $request->setConfig(array(
    'follow_redirects' => TRUE
  ));
  $request->setHeader(array(
    'Content-Type' => 'application/json',
    'Accept' => 'text/plain',
    'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
  ));
  $request->setBody('{\n  "data": {\n    "type": "RetailMediaKeywordsSetBid",\n    "id": "358669652976373760",\n    "attributes": {\n      "keywords": [\n        {\n          "phrase": "eggs",\n          "bid": "0.50"\n        },\n        {\n          "phrase": "milk",\n          "bid": "0.50"\n        }\n      ]\n    }\n  }\n}');
  try {
    $response = $request->send();
    if ($response->getStatus() == 200) {
      echo $response->getBody();
    }
    else {
      echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
      $response->getReasonPhrase();
    }
  }
  catch(HTTP_Request2_Exception $e) {
    echo 'Error: ' . $e->getMessage();
  }
  ```
</CodeGroup>

**Sample Response** *200 successful status will return an empty object array*

<CodeGroup>
  ```json JSON theme={null}
  {}
  ```
</CodeGroup>

## **Responses**

| Response    | Description                                                                        |
| ----------- | ---------------------------------------------------------------------------------- |
| 🔵 `200` OK | Call completed with success                                                        |
| 🔵 `201` OK | \* The call to add/remove the keyword from the line item was executed successfully |

* The call to set keyword bid to the line item was executed successfully                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
  \| 🔴 `400` - Bad Request | Setting a bid for a positive keyword that doesn't exist on the line item. **Error Message** `"On line item {lineItemId} normalized keyword \"{keyword}\"/en_US not found"`Setting a keyword bid above the line-item `maxBid` value will result in a 400 bad request error message. In this example, the `maxBid` value is at least 0.40. **Error Message** `"Invalid bid value, bid greater than maximum of 1.00000000, found for keyword: <keyword>"`Setting a keyword bid below the retailer `minBid` value will result in a 400 bad request error message. In this example, the `minBid` value is at least 0.40. **Error Message** `"Invalid bid value, bid less than minimum of 0.4000, found for keyword: <keyword>"` |
