# PUT Attach a letter part default upload image

Takes the raster image of a staged upload and puts it in the letter part's `default_upload_image` slot, returning the letter part with `default_upload_image_url` pointing at the new file. Requires `customisers:write` and an `Idempotency-Key`. Create the upload first with `POST /api/v3/uploads` with purpose `option_image`, send the bytes to the presigned target it returns, then send that upload's id here. An upload whose purpose is not the slot's answers 422 `upload_purpose_mismatch`. The upload is single use: attaching it a second time answers 409. Only PNG, JPEG and WebP are accepted. SVG is refused when the upload is created, because the option-image path stores files as they arrive and does not sanitise them. The bytes are verified here, not at create: the object must exist, be within the purpose's cap, start with the magic bytes of the type it was declared as, and carry a readable image header. A file that fails leaves the upload `rejected` with the failure's code, and attaching it again replays that code — fix the file and create a new upload rather than retrying. Attaching to a slot that already holds an image replaces it. The previous file is deleted once the new one is committed, so any URL published for it stops resolving. A letter part that holds this image cannot be deleted while it does; the delete below is what releases it. The attach clears the customiser's cached storefront configuration and runs the advisory language sync. It never regenerates Shopify products, product images, or the product cache.

- Source URL: https://www.signcustomiser.com/help/api/v3-put-attach-a-letter-part-default-upload-image/
- Markdown URL: https://www.signcustomiser.com/help/api/v3-put-attach-a-letter-part-default-upload-image.md
- Group: Customiser letter parts
- Method: PUT
- Path: /api/v3/customisers/{customiser_id}/letter-types/{letter_type_id}/letter-parts/{letter_part}/images/{image_slot}
- Auth: Bearer token
- Required scopes: `customisers:write`

## Path parameters

- customiser_id (string, required): The customiser id. Example: 1
- letter_type_id (string, required): The letter type id. Example: 7
- letter_part (string, required): The letter part. Example: face
- image_slot (string, required): Which of the letter part's images to write (closed set): the picture shown to a shopper who is asked to upload their own artwork for this part. Example: default_upload_image

## Body parameters

- upload_id (string, optional): No description provided.

## Request body example

```json
{
  "upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}
```

## cURL example

```bash
curl https://web.signcustomiser.com/api/v3/customisers/1/letter-types/7/letter-parts/face/images/default_upload_image \
  --request PUT \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}'
```

## Response examples

### 200 PUT 200 example 1

```json
{
  "data": {
    "object": "letter_part_colour_selection",
    "customiser_id": 42,
    "letter_type_id": 7,
    "letter_part": "face",
    "name": null,
    "description": null,
    "optional": null,
    "optional_label": null,
    "optional_default_none": false,
    "lightsource": false,
    "custom_image": false,
    "show_default_upload_image": true,
    "show_in_text_editor": true,
    "text_enabled": false,
    "default_upload_image_url": "https://cdn.example.com/files/2f1c9c0e-6a7b-4c1d-8e2f-3a4b5c6d7e8f.png",
    "created_at": "2026-08-13T00:00:00Z",
    "updated_at": "2026-08-13T00:05:00Z"
  },
  "links": {
    "self": "https://web.signcustomiser.com/api/v3/customisers/42/letter-types/7/letter-parts/face/images/default_upload_image",
    "documentation": "https://www.signcustomiser.com/help/api/"
  },
  "meta": {
    "api_version": "v3",
    "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
  }
}
```

### 400 Missing idempotency key

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/missing_idempotency_key",
  "title": "Missing idempotency key",
  "status": 400,
  "code": "missing_idempotency_key",
  "detail": "Provide an Idempotency-Key header for this write.",
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 401 Missing API key

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/missing_api_key",
  "title": "Missing API key",
  "status": 401,
  "code": "missing_api_key",
  "detail": "Provide a store API key as a bearer token.",
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 403 Insufficient scope

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/insufficient_scope",
  "title": "Insufficient scope",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "This operation requires the customisers:write scope.",
  "required_scopes": [
    "customisers:write"
  ],
  "granted_scopes": [
    "customisers:read"
  ],
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 404 Unknown letter part, slot or upload

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/resource_not_found",
  "title": "Resource not found",
  "status": 404,
  "code": "resource_not_found",
  "detail": "The requested resource does not exist or does not belong to the authenticated store.",
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 409 Upload already attached

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/upload_already_attached",
  "title": "Upload already attached",
  "status": 409,
  "code": "upload_already_attached",
  "detail": "This upload has already been attached to a file slot. Each upload is single use: create a new upload for each assignment.",
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 422 Purpose mismatch

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/upload_purpose_mismatch",
  "title": "Upload purpose mismatch",
  "status": 422,
  "code": "upload_purpose_mismatch",
  "detail": "This slot accepts uploads created with purpose option_image, and this upload was created with purpose font_ttf. Create a new upload with the slot's purpose.",
  "errors": [
    {
      "pointer": "/upload_id",
      "code": "upload_purpose_mismatch",
      "detail": "The upload's purpose is font_ttf.",
      "allowed_values": [
        "option_image"
      ]
    }
  ],
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 429 Option write budget exhausted

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/rate_limited",
  "title": "Too many requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "You have exceeded the request limit for this API key.",
  "retry_after": 37,
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```
