Customiser fonts
Attach a font file
Takes the TrueType file of a staged upload and makes it this font's
typeface, returning the font with font_file.has_font_file true and a
live ttf_url. Requires customisers:write and an Idempotency-Key.
Overview
Create the upload first with POST/api/v3/uploads using purpose
font_ttf, 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 typeface needs a new upload.
The bytes are verified here, not at create: the object must exist, be
within the purpose's cap, start with TrueType magic, and carry a table
directory a renderer can read. A file that fails leaves the upload
rejected with the failure's code, and attaching it again replays that
code — so fix the file and create a new upload rather than retrying.
Sending this to a font that already has a typeface replaces it. The
previous file is deleted once the new one is committed, so any URL
published for it stops resolving.
The attach mints a fresh server-owned font_file.family_name, 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 font id.
Example: 11
Request body
Request body example
{
"upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}curl https://web.signcustomiser.com/api/v3/customisers/1/fonts/11/file \
--request PUT \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"upload_id": "upl_9f2c4b7ad13e6058ba41cd"
}'{
"data": {
"object": "font",
"id": 11,
"customiser_id": 42,
"name": "Signature Script",
"line_height": null,
"uses_default_line_height": true,
"stencil_safe": false,
"min_height_smallest_letter_cm": null,
"min_height_uppercase_letter_cm": null,
"font_tier_id": 7,
"length_pricing_id": null,
"minimum_size_id": null,
"minimum_legacy_fixed_height_size_id": null,
"sort_order": 1,
"font_file": {
"has_font_file": true,
"family_name": "kx7q2m9v4t1b8n6c3z5j0h2w4r7y1p6d",
"ttf_url": "https://cdn.example.com/files/2f1c9c0e-6a7b-4c1d-8e2f-3a4b5c6d7e8f.ttf"
},
"created_at": "2026-08-13T00:00:00Z",
"updated_at": "2026-08-13T00:05:00Z"
},
"links": {
"self": "https://web.signcustomiser.com/api/v3/customisers/42/fonts/11/file",
"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_content_type_mismatch",
"title": "Upload content type mismatch",
"status": 422,
"code": "upload_content_type_mismatch",
"detail": "The uploaded bytes are not font/ttf. The declared content type must match the file you send; upload the correct file under a new upload.",
"errors": [
{
"pointer": "/upload_id",
"code": "upload_content_type_mismatch",
"detail": "The stored object is not font/ttf."
}
],
"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"
}