Customiser support finishes
Attach a support finish image
Takes the raster image of a staged upload and puts it in one of the
support finish's three image slots, returning the support finish with
that slot's *_url pointing at the new file. Requires
customisers:write and an Idempotency-Key.
Overview
Create the upload first with POST/api/v3/uploads — purpose
option_image for preview_image or example_image,
option_texture_image for texture_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, and
each slot needs its own upload.
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.
Attaching to texture_image is what makes the texture finish kind
available: send the image here first, then set finish_kind on the
finish itself.
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.
Authorisation
Bearer token required. Include it in theAuthorization header.
Required scope: customisers:write
Path parameters
The customiser id.
Example: 1
The support finish id.
Example: 27
Which of the support finish's images to write (closed set): the swatch a shopper picks from, the example photograph beside it, or the texture the texture finish kind is tiled from.
Example: preview_image
Request body
Request body example
{
"upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}curl https://web.signcustomiser.com/api/v3/customisers/1/support-finishes/27/images/preview_image \
--request PUT \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}'{
"data": {
"object": "support_finish",
"id": 27,
"customiser_id": 42,
"name": "Gloss Black",
"description": null,
"finish_kind": "colour",
"hexcode": "#111111",
"opacity": 1,
"applied_to_visualisation": true,
"backboard_ids": [
11
],
"min_width_cm": null,
"min_height_cm": null,
"min_size_rule": "any",
"base_price": 0,
"currency": "USD",
"price_multiplier": 1,
"price_multiplier_target": "base_letter_price",
"sort_order": 1,
"preview_image_url": "https://cdn.example.com/files/2f1c9c0e-6a7b-4c1d-8e2f-3a4b5c6d7e8f.png",
"example_image_url": null,
"texture_image_url": null,
"created_at": "2026-08-13T00:00:00Z",
"updated_at": "2026-08-13T00:05:00Z"
},
"links": {
"self": "https://web.signcustomiser.com/api/v3/customisers/42/support-finishes/27/images/preview_image",
"documentation": "https://www.signcustomiser.com/help/api/"
},
"meta": {
"api_version": "v3",
"request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
}{
"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"
}{
"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"
}{
"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"
}{
"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"
}{
"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"
}{
"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_texture_image, and this upload was created with purpose option_image. Create a new upload with the slot's purpose.",
"errors": [
{
"pointer": "/upload_id",
"code": "upload_purpose_mismatch",
"detail": "The upload's purpose is option_image.",
"allowed_values": [
"option_texture_image"
]
}
],
"request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}{
"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"
}