---
title: Update Customization
description: Update an existing customization by its unique identifier.
slug: recommendations/customization/update-customization
docKind: endpoint
hub: recommendations
tableOfContents: true
---
import ApiSection from "../../../../components/ApiSection.astro";
import ApiEndpoint from "../../../../components/ApiEndpoint.astro";
import ApiCodeTabs from "../../../../components/ApiCodeTabs.astro";
import { Aside } from "@astrojs/starlight/components";

<ApiSection>
  <div slot="code">
    <ApiEndpoint method="PUT" url="https://live.luigisbox.com/v1/recommender/pin/{TRACKER_ID}/scope/{CUSTOMIZATION_ID}" />
  </div>
## Overview

Update an existing customization by its unique identifier. This request replaces the full customization definition.

<Aside type="caution">
  This endpoint requires HMAC authentication. See [Authentication](/platform-foundations/api-principles/#authentication).
</Aside>
</ApiSection>

<ApiSection>
## Request parameters

### Path parameters

| Parameter | Type | Required | Description |
| :-- | :-- | :-- | :-- |
| `TRACKER_ID` | string | ✓ | Your unique tracker identifier. |
| `CUSTOMIZATION_ID` | UUID | ✓ | The unique ID of the customization to update. |

### Request headers

| Header | Value | Description |
| :-- | :-- | :-- |
| `Content-Type` | `application/json; charset=utf-8` | Required. |
| `Date` | HTTP date | Required for HMAC. |
| `Authorization` | `ApiAuth {TRACKER_ID}:{SIGNATURE}` | Required for HMAC. |

### Request body attributes

The request body follows the same structure as [Create Customization](/recommendations/customization/create-customization/).

| Parameter | Type | Required | Description |
| :-- | :-- | :-- | :-- |
| `model` | string | ✓ | Recommender model. |
| `target_type` | string | ✓ | Scope type: `item`, `criteria`, or `all`. |
| `target_identity` | string |  | Item ID when `target_type` is `item`. |
| `target_criteria` | object |  | Criteria definition when `target_type` is `criteria`. |
| `tags` | array |  | Customization tags. |
| `pin_definitions` | array | ✓ | Pin definitions to set on the customization. |

  <div slot="code">
    <h4 class="code-section-title">Example Request</h4>

```shell
tracker_id="1234-5678"
customization_id="199620b4-df1a-46e8-ab59-9e9ed9af7106"
private_key="your_private_api_key"
host="https://live.luigisbox.com"
path="/v1/recommender/pin/${tracker_id}/scope/${customization_id}"
method="PUT"
content_type="application/json; charset=utf-8"
date=$(date -u "+%a, %d %b %Y %H:%M:%S GMT")

string_to_sign="$(printf "${method}\n${content_type}\n${date}\n${path}")"
signature=$(echo -n "${string_to_sign}" | openssl dgst -sha256 -hmac "${private_key}" -binary | base64)

curl -X ${method} "${host}${path}" \
  -H "Content-Type: ${content_type}" \
  -H "Date: ${date}" \
  -H "Authorization: ApiAuth ${tracker_id}:${signature}" \
  -d '{
    "model": "basket",
    "target_type": "item",
    "target_identity": "/p/123",
    "pin_definitions": [
      {
        "position": 1,
        "pin_type": "item",
        "pin_identity": "/p/555",
        "active_from": "2025-02-01T00:00:00Z"
      }
    ]
  }'
```
  </div>
</ApiSection>

<ApiSection>
## How to Make a Request

1. Build the HMAC string from the method, content type, date, and full resource path including the customization ID.
2. Generate the HMAC SHA-256 digest with your private key.
3. Send the full updated customization object in the JSON body.

<div slot="code">
  <h4 class="code-section-title">Code Examples</h4>
  <ApiCodeTabs syncKey="recommendations-customization-update">
    <div slot="ruby">

```ruby
require 'faraday'
require 'base64'
require 'openssl'
require 'json'
require 'time'

def generate_luigisbox_digest(private_key, http_method, endpoint_path, date_header, content_type_header)
  data = "#{http_method}\n#{content_type_header}\n#{date_header}\n#{endpoint_path}"
  Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', private_key, data)).strip
end

tracker_id = 'YOUR_TRACKER_ID'
customization_id = '199620b4-df1a-46e8-ab59-9e9ed9af7106'
endpoint_path = "/v1/recommender/pin/#{tracker_id}/scope/#{customization_id}"
content_type = 'application/json; charset=utf-8'
date_header = Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S GMT")
signature = generate_luigisbox_digest('your_private_api_key', 'PUT', endpoint_path, date_header, content_type)

customization_data = {
  model: 'basket',
  target_type: 'item',
  target_identity: '/p/123',
  pin_definitions: [{ position: 1, pin_type: 'item', pin_identity: '/p/555' }]
}

response = Faraday.new(url: 'https://live.luigisbox.com').put(endpoint_path) do |req|
  req.headers['Date'] = date_header
  req.headers['Content-Type'] = content_type
  req.headers['Authorization'] = "ApiAuth #{tracker_id}:#{signature}"
  req.body = customization_data.to_json
end

puts response.status
```
    </div>
    <div slot="php">

```php
<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;

function generateLuigisboxDigest($privateKey, $httpMethod, $endpointPath, $dateHeader, $contentTypeHeader) {
    $data = "{$httpMethod}\n{$contentTypeHeader}\n{$dateHeader}\n{$endpointPath}";
    return trim(base64_encode(hash_hmac('sha256', $data, $privateKey, true)));
}

$trackerId = 'YOUR_TRACKER_ID';
$customizationId = '199620b4-df1a-46e8-ab59-9e9ed9af7106';
$endpointPath = "/v1/recommender/pin/{$trackerId}/scope/{$customizationId}";
$contentType = 'application/json; charset=utf-8';
$date = gmdate('D, d M Y H:i:s') . ' GMT';
$signature = generateLuigisboxDigest('your_private_api_key', 'PUT', $endpointPath, $date, $contentType);

$client = new Client();
$response = $client->request('PUT', "https://live.luigisbox.com{$endpointPath}", [
    'headers' => [
        'Content-Type' => $contentType,
        'Date' => $date,
        'Authorization' => "ApiAuth {$trackerId}:{$signature}",
    ],
    'json' => [
        'model' => 'basket',
        'target_type' => 'item',
        'target_identity' => '/p/123',
        'pin_definitions' => [
            ['position' => 1, 'pin_type' => 'item', 'pin_identity' => '/p/555'],
        ],
    ],
]);

echo $response->getStatusCode();
```
    </div>
    <div slot="javascript">

```javascript
const axios = require('axios');
const crypto = require('crypto');

function generateLuigisBoxDigest(privateKey, httpMethod, endpointPath, dateHeader, contentTypeHeader) {
  const data = `${httpMethod}\n${contentTypeHeader}\n${dateHeader}\n${endpointPath}`;
  return crypto.createHmac('sha256', privateKey).update(data).digest('base64').trim();
}

const trackerId = 'YOUR_TRACKER_ID';
const customizationId = '199620b4-df1a-46e8-ab59-9e9ed9af7106';
const endpointPath = `/v1/recommender/pin/${trackerId}/scope/${customizationId}`;
const contentType = 'application/json; charset=utf-8';
const dateHeader = new Date().toUTCString();
const signature = generateLuigisBoxDigest('your_private_api_key', 'PUT', endpointPath, dateHeader, contentType);

axios({
  method: 'PUT',
  url: `https://live.luigisbox.com${endpointPath}`,
  headers: {
    'Content-Type': contentType,
    Date: dateHeader,
    Authorization: `ApiAuth ${trackerId}:${signature}`,
  },
  data: {
    model: 'basket',
    target_type: 'item',
    target_identity: '/p/123',
    pin_definitions: [{ position: 1, pin_type: 'item', pin_identity: '/p/555' }],
  },
}).then((response) => console.log(response.status));
```
    </div>
  </ApiCodeTabs>
</div>
</ApiSection>

<ApiSection>
## Response structure

The server returns `204 No Content` on success.

  <div slot="code">
    <h4 class="code-section-title">Example Response</h4>

```http
HTTP/1.1 204 No Content
```
  </div>
</ApiSection>

<ApiSection>
## Error handling

| HTTP Status | Description |
| :-- | :-- |
| `204 No Content` | Customization updated successfully. |
| `400 Bad Request` | Invalid configuration provided. |
| `401 Unauthorized` | Missing or invalid authentication. |
| `404 Not Found` | Customization ID not found. |
| `422 Unprocessable Entity` | Invalid pin definition provided. |

  <div slot="code">
    <h4 class="code-section-title">Example Error</h4>

```json
{
  "reason": "Invalid pin definition provided",
  "exception_details": {
    "pin_definitions": ["Missing required field: position"],
    "target_type": ["Must be one of: item, criteria, all"]
  }
}
```
  </div>
</ApiSection>
