Sign Customiser

Customisers

attach_customiser_asset

destructive write

Attach customiser asset

Copy page

Put an uploaded file into one asset slot on one option record, or on the customiser labels document.

Overview

Binds a previously uploaded object to one asset slot on one record: an option image, an extra choice picture, a font TrueType file, a backboard custom SVG shape, one letter part default upload image, or the customiser storefront product image. Attaching to a slot that already holds a file overwrites it and releases the old file, so the call needs confirm: true. The upload purpose must be the one the slot accepts. It requires the customisers:write scope and an idempotency_key, and supports dry_run.

Permission

Requires thecustomisers:writepermission. A connection without it answersinsufficient_scopenaming the permission to approve.

Annotations

readOnlyHintfalse
destructiveHinttrue
idempotentHinttrue
openWorldHintfalse

Prerequisites

  • An upload id from create_upload whose bytes have already been PUT to its presigned target.
  • The upload purpose must be the one the slot accepts, which get_customiser_option and this tool description both name.
  • The record id, from list_customiser_options; letter_type_id and letter_part for the nested targets.
  • A merchant has connected this store and approved the customisers:write scope.

Side effects

  • Moves the staged object into the store permanent files area and writes its URL into the slot.
  • Overwrites and releases whatever file the slot already held.
  • Consumes the upload: each upload is single use.
  • Clears the customiser cached storefront configuration.
  • Claims the idempotency_key for at least 24 hours.

Arguments

customiser_idintegerrequired

The customiser id, from list_customisers.

asset_targetstringrequired

Which asset slot family to write. Closed set. Each value fixes which of the arguments below are needed and which upload purpose the slot accepts.

One of: backboard_image, backboard_shape, backlight_image, colour_image, extra_image, extra_choice_image, font_file, letter_type_image, letter_part_image, letter_part_colour_image, material_image, mounting_image, mounting_colour_image, support_finish_image, label_product_image

option_idinteger or string

The record that owns the slot. An integer for every target except letter_part_image, which is addressed by the part catalogue name. Omitted for label_product_image, which belongs to the customiser rather than to a record.

letter_type_idinteger

The letter type that owns the record, required for letter_part_image and letter_part_colour_image.

letter_partstring

The letter part that owns the colours, required for letter_part_colour_image. For letter_part_image the part is option_id instead.

One of: face, back, side, top, bottom, left, right, halo, trim, tube

choice_valuestring

One of an image-choice extra's choice values, required for extra_choice_image.

image_slotstring

Which picture of the record to write. Which slots a target offers is target-specific and reported by get_customiser_option; a slot the target does not offer is refused with allowed_values. Omitted for backboard_shape, font_file and label_product_image, whose paths name the slot. Expected to grow.

One of: image, button_image, example_image, texture_image, default_upload_image, preview_image

upload_idstringrequired

The id of an upload created with this slot purpose, whose bytes have already been sent to its presigned target. Each upload is single use.

confirmboolean

Must be true to apply the change, because attaching overwrites and releases whatever file the slot already holds. Without it the call returns a confirmation_required error and changes nothing. A dry run does not need it.

idempotency_keystring

A client-generated key unique to this logical write, such as a UUID. Required: repeating the call with the same key and the same arguments replays the original result instead of writing twice, and the same key with different arguments is an idempotency_key_conflict. A dry run claims no key.

dry_runboolean

When true, the record, the slot and the upload purpose are checked and the upload is not consumed is checked and nothing is written: the result is the same verdict the apply would have reached, and a problem the apply would have raised comes back as the same tool error. Defaults to false.

Result

The owning record as it now stands, with the slot URL freshly populated, and the slot that was written. A dry run returns the attach verdict and consumes nothing.

request_idstringalways present
storeobjectalways present
store.idintegeralways present
store.namestringalways present
customiser_idintegeralways present
asset_targetstringalways present

One of: backboard_image, backboard_shape, backlight_image, colour_image, extra_image, extra_choice_image, font_file, letter_type_image, letter_part_image, letter_part_colour_image, material_image, mounting_image, mounting_colour_image, support_finish_image, label_product_image

slotstringalways present

The slot that was written. For the three targets whose path names the slot, this is shape, font_file or product_image.

resourceobject

The owning record as it now stands, with the slot URL populated. Absent on a dry run.

idempotent_replayboolean

True when this call replayed an earlier attach carrying the same idempotency_key rather than consuming a second upload.

dry_runboolean

Present and true only when dry_run was requested.

validboolean

Present only on a dry run, and always true: a failing dry run returns a tool error instead.

verdictobject

Present only on a dry run: the attach verdict.

Error cases

confirmation_required

Send confirm: true. Attaching overwrites whatever the slot already holds.

insufficient_scope

The connection was approved without customisers:write.

invalid_svg

The backboard shape failed SVG sanitisation; the problem names the constraint.

missing_idempotency_key

Send idempotency_key. It is required for this write.

resource_not_found

No such customiser, record or upload in this store.

upload_already_attached

Each upload is single use and this one is spent. Create a new upload for this slot.

upload_content_type_mismatch

What arrived is not the content type that was declared. Create a new upload declaring the real type.

upload_expired

The staged upload passed its retention window. Start again at create_upload.

upload_object_missing

No bytes were found at the staging target. PUT the file to the target create_upload returned, then attach.

upload_purpose_mismatch

The upload was created for a different purpose; allowed_values names the purpose this slot accepts. Create a new upload with it.

upload_size_exceeded

The object is larger than the purpose allows; the problem reports max_byte_size.

validation_failed

A slot this target does not offer, or a missing nested key; allowed_values lists what the target accepts.

Attach a swatch to a colour

tools/call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "attach_customiser_asset",
    "arguments": {
      "customiser_id": 42,
      "asset_target": "colour_image",
      "option_id": 7,
      "image_slot": "image",
      "upload_id": "upl_9f2c4b7ad13e6058ba41cd",
      "confirm": true,
      "idempotency_key": "d4e5f607-8192-4c0d-9e1f-2a3b4c5d6e7f"
    }
  }
}
result
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": {
      "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t",
      "store": {
        "id": 12,
        "name": "Demo Signs"
      },
      "customiser_id": 42,
      "asset_target": "colour_image",
      "slot": "image",
      "resource": {
        "id": 7,
        "name": "Warm White",
        "image": "https://cdn.example.com/files/2f1c9c0e.png"
      },
      "idempotent_replay": false
    }
  }
}

The upload was created for another purpose (error)

tools/call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "attach_customiser_asset",
    "arguments": {
      "customiser_id": 42,
      "asset_target": "colour_image",
      "option_id": 7,
      "image_slot": "image",
      "upload_id": "upl_000000000000000000000",
      "confirm": true,
      "idempotency_key": "d4e5f607-8192-4c0d-9e1f-2a3b4c5d6e7f"
    }
  }
}
result
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": true,
    "structuredContent": {
      "error": {
        "code": "upload_purpose_mismatch",
        "title": "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.",
        "recovery": "The upload was created for a different purpose. Start again at create_upload with the purpose this attachment needs.",
        "pointer": "/upload_id",
        "allowed_values": [
          "option_image"
        ]
      }
    }
  }
}