Sign Customiser

Takes the SVG of a staged upload and makes it this backboard's shape, returning the backboard with geometry.has_custom_shape true and geometry.status pending. Requires customisers:write and an Idempotency-Key.

PUT/api/v3/customisers/{customiser_id}/backboards/{backboard_id}/shape

Overview

Create the upload first with POST/api/v3/uploads using purpose backboard_shape_svg, send the bytes to the presigned target it returns, then send that upload's id here. The upload is single use: attaching it a second time answers 409, and a replacement shape needs a new upload. A shape is the one uploaded file this API stores inside its own resource rather than as a file. It is sanitised and written into the backboard, is never published as a URL, and the staged object is deleted rather than kept. geometry is how you read it back. The bytes are verified here, not at create: the object must exist, be within the purpose's cap, be well-formed XML with an svg element, carry no script elements, event-handler attributes or javascript: references, and still draw something once sanitised. A file that fails answers invalid_svg and leaves the upload rejected, and attaching it again replays that code — so fix the file and create a new upload rather than retrying. Attaching a shape queues server-side geometry measurement, which is why the response reports geometry.status pending. Poll the backboard until it reaches ready; failed carries a geometry.failure_reason. A backboard that has measured is what backboard_type custom_shape and cutout need, so this is the call that makes those types usable: attach the shape, then set the type in the ordinary backboard write. Sending this to a backboard that already has a shape replaces it and discards the previous measurement. Re-attaching a document that sanitises to the shape already measured is the one exception: there is nothing new to measure, so the existing ready result stands and the response says so rather than reporting pending. 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

customiser_idstringpathrequired

The customiser id.

Example: 1

backboard_idstringpathrequired

The backboard id.

Example: 11

Request body

upload_idstringbody

Request body example

application/json
{
  "upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}
Attach a backboard shape
curl https://web.signcustomiser.com/api/v3/customisers/1/backboards/11/shape \
  --request PUT \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}'
Response
{
  "data": {
    "object": "backboard",
    "id": 11,
    "customiser_id": 42,
    "name": "Cloud Panel",
    "description": null,
    "backboard_type": "board",
    "letter_type_ids": [],
    "outline_size": null,
    "allow_multilayer": false,
    "custom_background_enabled": false,
    "show_custom_background": false,
    "base_price": 0,
    "currency": "USD",
    "price_multiplier": 1,
    "price_multiplier_target": "base_letter_price",
    "price_per_sq_cm": null,
    "sort_order": 1,
    "image_url": null,
    "button_image_url": null,
    "geometry": {
      "has_custom_shape": true,
      "status": "pending",
      "failure_reason": null,
      "measured_at": 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/backboards/11/shape",
    "documentation": "https://www.signcustomiser.com/help/api/"
  },
  "meta": {
    "api_version": "v3",
    "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
  }
}