# Public API v3

Create a Store-scoped key, follow the v3 quickstart, and explore the current Sign Customiser API contract.

- Source URL: https://www.signcustomiser.com/help/api/
- Markdown URL: https://www.signcustomiser.com/help/api/index.md
- Base URL: https://web.signcustomiser.com
- Auth: Bearer token

## Guides

- [Authentication and key lifecycle](https://www.signcustomiser.com/help/api/guides/authentication/): Create, store, rotate, and revoke Store-scoped API keys safely.
- [Cold-start quickstart](https://www.signcustomiser.com/help/api/guides/quickstart/): Create a scoped key, identify its Store, list customisers, and read pricing.
- [Errors and retries](https://www.signcustomiser.com/help/api/guides/errors-and-retries/): Interpret problem details and recover safely from validation, conflict, and rate-limit responses.
- [Versioning and deprecation policy](https://www.signcustomiser.com/help/api/guides/versioning/): Understand major versions, compatible additions, breaking changes, and the previous-generation API.
- [Migrate from v2 to v3](https://www.signcustomiser.com/help/api/guides/migration-v2-to-v3/): Move previous-generation requests to v3 without duplicating writes or losing data.
- [Canonical, legacy, and UI glossary](https://www.signcustomiser.com/help/api/guides/glossary/): Translate canonical API values to legacy spellings and current merchant-admin labels.

## Machine-readable resources

- [openapi.yaml](https://www.signcustomiser.com/help/openapi.yaml): Machine-readable OpenAPI schema for the public API.
- [openapi.json](https://www.signcustomiser.com/help/openapi.json): JSON version of the OpenAPI schema for the public API.
- [collection.json](https://www.signcustomiser.com/help/collection.json): Postman collection generated from the Scribe API reference.
- [skill.md](https://www.signcustomiser.com/help/skill.md): Agent-friendly Sign Customiser documentation skill file.
- [llms.txt](https://www.signcustomiser.com/help/llms.txt): Compact public index of help articles, API pages, and machine-readable resources.
- [llms-full.txt](https://www.signcustomiser.com/help/llms-full.txt): Full-text corpus of help articles and API documentation for language models.

## Endpoint groups

### Current API, v3: Analytics

- [GET Get an analytics summary](https://www.signcustomiser.com/help/api/v3-get-get-an-analytics-summary/): Return bounded operational totals for the authenticated Store. Orders, modern products, and native-currency revenue are counted over complete UTC calendar days. Revenue remains in integer minor units and is never converted or combined across currencies. Malformed stored currency codes appear honestly in one null-currency bucket. Customer details, provider data, and legacy ProductCache rows are excluded. Requires `analytics:read`; this operation is read-only and safe to retry. `end_date` is the inclusive final day and must be before the current UTC date. It defaults to yesterday. `period` defaults to `30d`. The response reports the half-open query bounds `[starts_at, ends_before)`. Correct a 422 using the reported parameter, replace a key after 401, add the scope after 403, and retry 429 responses after `retry_after` seconds.

### Current API, v3: Customisers

- [GET List customisers](https://www.signcustomiser.com/help/api/v3-get-list-customisers/): List the store's customisers — the configurable sign products shoppers design on the storefront. Call this to discover what the store sells and to find the integer `id` used by every per-customiser operation. Each item reports the customiser's pricing model (`simple_letter`, `advanced_letter` or `frame_fit`, with a human display name), its `sign_category` and `product_family`, its styling `selection_mode` (`single_style` styles the whole sign as one unit; `per_word` lets the shopper style each word), and whether it is `active` on the storefront. The operation is read-only, has no side effects, and is always safe to retry. Requires the `customisers:read` scope; results are always limited to the store the API key belongs to. Results are paginated: `data` holds up to `limit` customisers in creation order (oldest first, stable across pages). While `pagination.has_more` is true, fetch the next page by requesting `links.next` — or by passing `pagination.next_cursor` as the `cursor` parameter with the same filters. Cursors are opaque and server-owned: send them back unchanged, never construct or edit one. A cursor is only valid for the exact filter combination it was issued with; changing filters (or altering the cursor) yields a 422 problem with code `invalid_cursor` — restart from the first page by dropping the cursor. Unsupported filters or parameters are rejected with a 422 problem rather than ignored, so a typo can never silently change meaning. A 401 problem means the key is missing, invalid, or expired. A 403 problem with code `insufficient_scope` means the key is valid but lacks `customisers:read`; its `required_scopes` and `granted_scopes` members say which scope is missing. A 429 problem means too many requests: wait `retry_after` seconds, then retry. Error responses use RFC 9457 problem+json with a machine-readable `code`, a documentation link in `type`, and a `request_id` to quote when contacting support.
- [GET Get a customiser](https://www.signcustomiser.com/help/api/v3-get-get-a-customiser/): Retrieve one customiser by its integer `id` (as returned by the list operation). The response reports the customiser's pricing model (`simple_letter`, `advanced_letter` or `frame_fit`, with a human display name), its `sign_category` and `product_family`, its styling `selection_mode`, and whether it is `active` on the storefront. The operation is read-only, has no side effects, and is always safe to retry. Requires the `customisers:read` scope. A 404 problem with code `resource_not_found` means the customiser does not exist on the store your API key belongs to — use the list operation to discover valid ids; ids from another store are indistinguishable from unknown ids. A 401 problem means the key is missing, invalid, or expired. A 403 problem with code `insufficient_scope` means the key is valid but lacks `customisers:read`. A 429 problem means too many requests: wait `retry_after` seconds, then retry. Error responses use RFC 9457 problem+json with a machine-readable `code`, a documentation link in `type`, and a `request_id` to quote when contacting support.

### Current API, v3: Orders

- [GET List orders](https://www.signcustomiser.com/help/api/v3-get-list-orders/): List orders accepted and stored by Sign Customiser for the authenticated Store, newest first. `received` means only that the order was accepted into Sign Customiser; it does not claim payment, manufacturing, fulfilment, shipping, refund, or cancellation state. `line_item_count` counts modern products only. Legacy cached products remain available to the established CSV export but are deliberately absent from v3 order projections and do not match `filter[customiser_id]`. Follow `links.next` while `pagination.has_more` is true. Cursors are opaque and are valid only with the exact filters that issued them. Unsupported parameters and filters are rejected rather than ignored. Requires `orders:read`; results are always scoped to the Store belonging to the API key. This read is safe to retry.
- [POST Create an order](https://www.signcustomiser.com/help/api/v3-post-create-an-order/): Store one order received from an enabled custom integration for the authenticated Store. Every `product_id` must be a modern product created through the same integration and Store. The 201 response means Sign Customiser committed the order; it does not claim payment, manufacturing, fulfilment, shipping, refund, or cancellation state. Requires `orders:write`. `total_amount` is the integration's external grand total in integer minor units. Sign Customiser separately derives its app total from the stored unit prices and quantities, so callers cannot override the platform fee basis. `currency` must equal the Store and every referenced product currency. Customer and address values are optional snapshots; request payloads are never retained as raw JSON. Sign Customiser durably schedules the established manufacturer order emails, order analytics, order-created webhook, and onboarding synchronisation with the order. Manufacturer recipients and analytics events have independent retry units. A queue publishing failure rolls the order back. Delivery by external providers is asynchronous. Repeating the exact method, path, body, credential, and `Idempotency-Key` replays the original 201 response and does not schedule those effects again. Retry a 409 `idempotency_key_in_flight` with the same key after `retry_after`; use the original body or a new key for an idempotency conflict. This v3 operation rejects a `store_order_id` already present for the integration and serialises concurrent v3 creations. During migration, do not send the same logical order through legacy and v3 writes in parallel.
- [POST Queue an order CSV export](https://www.signcustomiser.com/help/api/v3-post-queue-an-order-csv-export/): Queue the established CSV export for an inclusive UTC creation-date range. The email recipient is the authenticated Store's contact email and cannot be overridden. The range may contain at most 366 days and 1,000 orders, and its estimated CSV size must stay within the export ceiling; choose a shorter range when either bound is exceeded. Unlike the v3 read projection, the frozen CSV contract still includes cached legacy order rows. Requires `orders:write`. Supply an `Idempotency-Key`; replaying the same request does not queue or email a second export.
- [GET Show an order](https://www.signcustomiser.com/help/api/v3-get-show-an-order/): Return one Store-scoped order with customer and address snapshots plus its modern line items. Cached legacy products are never serialised; an older cached-only order therefore returns an empty `line_items` array. Money uses integer minor units with an explicit currency, dimensions are centimetres, and timestamps are ISO 8601 UTC. Requires `orders:read` and is safe to retry.
- [POST Queue an order email resend](https://www.signcustomiser.com/help/api/v3-post-queue-an-order-email-resend/): Queue the established order email again for the manufacturer recipient configured by the Store. The operation accepts no request fields: a caller cannot choose or override any recipient. Requires `orders:write`. Supply a unique `Idempotency-Key` for each logical resend; retrying the same body and key replays the 202 response without queuing another email. Distinct attempts are limited to two per API key per minute.

### Current API, v3: Pricing

- [GET Get customiser pricing](https://www.signcustomiser.com/help/api/v3-get-get-customiser-pricing/): Retrieve the customiser's full pricing configuration as one canonical document. The document's shape follows its `pricing_model`: `simple_letter` prices per letter at fixed sign widths (sizes carry a `sizing_strategy` of `fixed_width` or `fixed_height` and a `height_measurement_mode` of `line_height` or `letter_height`, price list rows carry per-line `base_price`/`letter_price` objects plus optional `letter_price_by_position` schedules, and an optional `sheet_pricing` section adds backing-sheet bands); `advanced_letter` prices from material length (price lists carry a `letter_pricing_method` of `material_length` or `fixed_letter`, a `shipping` configuration, and rows with rates and dimension limits; fixed-letter rows may carry `price_per_letter_by_position` schedules); `frame_fit` prices by frame area (exactly one price list with area-rate rows). Amount fields (`base_price`, `letter_price` lines, `price_per_letter`, and both position-price schedules) are integer minor units of `currency`; the rate fields `price_per_cm` and `price_per_sq_cm` are decimal major currency units per centimetre (or square centimetre); dimensions are centimetres in `_cm` fields. `currency` is the store's configured ISO 4217 currency, or null on Shopify-backed stores that leave the storefront currency in charge. The operation is read-only, has no side effects, and is always safe to retry. Requires the `pricing:read` scope; use this document as the base for `PATCH`/`PUT` writes and the validate dry-run. A 404 problem with code `resource_not_found` means the customiser does not exist on the store your API key belongs to. A 422 problem with code `legacy_pricing_model` means the customiser still uses the retired fixed-height pricing model, which has no pricing document on this API (its replacement is `simple_letter` with `fixed_height` sizing). A 401 problem means the key is missing, invalid, or expired; a 403 problem with code `insufficient_scope` means the key lacks `pricing:read`; a 429 problem means too many requests — wait `retry_after` seconds, then retry. Error responses use RFC 9457 problem+json with a machine-readable `code` and a `request_id` to quote when contacting support.
- [PUT Replace customiser pricing](https://www.signcustomiser.com/help/api/v3-put-replace-customiser-pricing/): Replace the customiser's entire pricing configuration with the request body — the full canonical document, exactly as the read operation returns it (no envelope). This is an explicit full replacement: sizes and price lists omitted from the document are deleted (each carries its id — size_id, price_list_id — to update in place; omit the id to create a new record, and use a size client_key with row size_key references to link rows to sizes created in the same request). For partial updates prefer PATCH; to check a document without persisting anything use the validate operation. The read-only descriptor fields (object, customiser_id, pricing_model, pricing_model_display_name, currency) may be echoed back unchanged but can never be changed here — in particular the pricing model cannot be switched. Field semantics, units, and the per-model document shapes are documented on the read operation. Requires the `pricing:write` scope. A successful replacement immediately reprices the storefront: the customiser's cached configuration is invalidated and translated language content is resynchronised. Send an `Idempotency-Key` header (1-255 visible ASCII characters, e.g. a UUID) to make the write safe to retry: repeating the same key with the same body replays the original response (marked `Idempotency-Replay: true`) without executing again; the same key with a different body is a 409 problem with code `idempotency_key_conflict`; keys are retained for at least 24 hours and are scoped to your credential, the HTTP method, and the path. Validation failures are 422 problems: `validation_failed` lists every field error in `errors[]` with a JSON `pointer` and, for enum violations, the `allowed_values`; `unknown_field` means the document contains fields outside the schema (fix the pointers listed — nothing is ever silently ignored); `legacy_pricing_model` means the customiser still uses the retired fixed-height model. A 409 problem with code `resource_in_use` means the document omits sizes or price lists that fonts or settings still reference — keep them in the document or detach them first. A 400 problem means the body is not valid JSON or the `Idempotency-Key` header is malformed. 401/403/404/429 behave as on the read operation.
- [PATCH Update customiser pricing](https://www.signcustomiser.com/help/api/v3-patch-update-customiser-pricing/): Partially update the customiser's pricing with a JSON Merge Patch (RFC 7396) of the canonical document: the request body is a JSON object containing only the properties to change. Properties omitted from the patch are unchanged; a null value removes a property (for example `{"sheet_pricing": null}` removes the backing-sheet section); arrays are replaced wholesale — to change one size or price list row, send the complete new array (each entry carrying its size_id or price_list_id to update in place). A merge patch can never edit one array element by itself. The patched result is validated and persisted as a full replacement, so the field rules, read-only descriptor guards, deletion semantics, and error catalogue are exactly those of the replace operation; field semantics and per-model document shapes are documented on the read operation. An empty object `{}` is a valid no-op. Requires the `pricing:write` scope. A successful update immediately reprices the storefront: the customiser's cached configuration is invalidated and translated language content is resynchronised. Send an `Idempotency-Key` header (1-255 visible ASCII characters, e.g. a UUID) to make the write safe to retry: repeating the same key with the same body replays the original response (marked `Idempotency-Replay: true`) without executing again; the same key with a different body is a 409 problem with code `idempotency_key_conflict`; keys are retained for at least 24 hours and are scoped to your credential, the HTTP method, and the path. A 422 problem with code `invalid_document` means the patch body is not a JSON object. All other failures match the replace operation: `validation_failed` (pointers into the patched document plus `allowed_values` on enum violations), `unknown_field`, `legacy_pricing_model`, 409 `resource_in_use`, 409 idempotency conflicts, 400 `malformed_json`, and 401/403/404/429.
- [POST Validate customiser pricing](https://www.signcustomiser.com/help/api/v3-post-validate-customiser-pricing/): Dry-run a pricing replacement without persisting anything. The request body is the full canonical document, exactly as the replace operation accepts it, and the response is exactly what that replace would produce: on an invalid document, the identical 422 problem (`validation_failed` with pointers and `allowed_values`, `unknown_field`, or `legacy_pricing_model`); on a document whose omissions would delete referenced records, the identical 409 `resource_in_use` problem; and on a valid document, a 200 `pricing_validation` confirmation — the same validation code path runs, only persistence is skipped. Nothing is written, no caches are touched, and no idempotency key is consumed, so the operation is always safe to repeat. To dry-run a PATCH, fetch the document, apply your merge patch locally (RFC 7396), and validate the result. Requires the `pricing:write` scope (it is the write's dry-run twin). A 400 problem means the body is not valid JSON; a 422 problem with code `invalid_document` means the body is not a JSON object. 401/403/404/429 behave as on the read operation.

### Current API, v3: Products

- [GET List products](https://www.signcustomiser.com/help/api/v3-get-list-products/): List the authenticated Store's modern products in descending creation order. Legacy ProductCache rows are excluded because they have a separate, potentially colliding identity. Each item contains integer minor-unit prices, the Store currency when valid, and ISO 8601 UTC timestamps. This read-only operation requires `products:read` and is safe to retry. A product `title` may contain customer-entered sign content, so protect API keys with this scope accordingly. Follow `links.next` while `pagination.has_more` is true. Cursors are opaque and must be returned unchanged. No filters are supported. A 401 means the API key is missing or invalid, 403 means it lacks the scope, 422 means a parameter or cursor is invalid, and 429 should be retried after the response's `retry_after` seconds.
- [GET Show a product](https://www.signcustomiser.com/help/api/v3-get-show-a-product/): Return one modern product owned by the authenticated Store, including dimensions and safe public artwork URLs. `title` and `description` are Store product metadata and may contain customer-entered sign content, so protect keys with `products:read`. ProductCache history, raw node data, provider payloads, underlying upload paths, upload/contact names, tokens, and emails are never exposed. The operation is read-only. Unknown and foreign ids return the same 404. Remove unknown query parameters after a 422. Retry 429 responses after `retry_after` seconds.
- [GET Show product selections](https://www.signcustomiser.com/help/api/v3-get-show-product-selections/): Return the Store-local option ids captured for a modern product. Stable integer `value` fields are separate from merchant-editable `display_name` labels. Canonical axes include `letter_type` and `support_finish`; the latter may report `finish_kind` and `colour_hex`. Lookups are restricted to the product customiser, so stale or foreign option ids become null or are omitted. Requires `products:read` and has no side effects. Unknown and foreign product ids share one 404 response.
- [POST Synchronise a product](https://www.signcustomiser.com/help/api/v3-post-synchronise-a-product/): Store one product created by an enabled custom integration for the authenticated Store and customiser. The response returns the modern product id used by order line items. Sign Customiser also creates a private compatibility projection for the established manufacturer email and export paths. This inbound operation never downloads remote artwork, calls the integration callback, or emits the product-created webhook. Requires `products:write`. `integration_id` must identify an enabled custom integration belonging to the Store. `store_product_id` is the integration's stable external id. This v3 operation rejects an id already present in the Store and serialises concurrent v3 synchronisations. During migration, do not send the same logical product through legacy and v3 writes in parallel. Money is integer minor units and `currency` must equal the Store currency. Artwork references must be credential-free HTTPS URLs no longer than 255 characters; they are stored as references and are not fetched during this request. Send a unique `Idempotency-Key` for each logical product. Repeating the exact method, path, body, credential, and key replays the original 201 response with `Idempotency-Replay: true` and does not create another product. A 409 `idempotency_key_in_flight` is safe to retry with the same key after `retry_after`; a key/body conflict needs a new key or the original body. Correct every pointer reported by a 422 before retrying.

### Current API, v3: Store

- [GET Get the Store subscription](https://www.signcustomiser.com/help/api/v3-get-get-the-store-subscription/): Return the authenticated Store's current local subscription projection. The same provider-neutral contract covers Universal and Shopify Stores, with a stable machine `plan`, separate display name, billing interval, renewal intent, and known trial or end timestamps. Status is expected to grow. Provider ids, payment details, test flags, customer details, and raw provider objects are never exposed or fetched. Requires `store:read`; this operation is read-only and safe to retry. This endpoint accepts no query parameters. A 401 means the key is missing or invalid. A 403 means it lacks `store:read`; create a correctly scoped key. Remove parameters after a 422. Retry a 429 after `retry_after` seconds.

### Current API, v3: Stores

- [GET Get the authenticated store](https://www.signcustomiser.com/help/api/v3-get-get-the-authenticated-store/): Identify the store your API key belongs to. Call this first: it confirms the key works, tells you which store you are operating on, whether the store runs on the `shopify` or `universal` platform, its current subscription plan, and the scopes your key grants — so you know which operations are available before calling them. The operation is read-only, has no side effects, and is always safe to retry. Requires the `store:read` scope. Authenticate every request with a store API key sent as a bearer token (`Authorization: Bearer <api key>`); keys are created in the merchant admin under Integrate → API Tokens with a chosen set of scopes and an optional expiry. A 401 problem response means the key is missing, invalid, or expired — create or re-copy the key. A 403 problem response with code `insufficient_scope` means the key is valid but lacks a required scope: the problem's `required_scopes` and `granted_scopes` members say which scope is missing and what the key can do; create a key that includes the required scope. A 429 problem response means too many requests: wait `retry_after` seconds, then retry. Error responses use RFC 9457 problem+json: machine-readable `code`, a documentation link in `type`, and a `request_id` to quote when contacting support.

### Current API, v3: Webhook events

Signed delivery payloads sent from Sign Customiser to your own application, including the product creation callback used by custom integrations.

- [WEBHOOK Product created](https://www.signcustomiser.com/help/api/webhook-product-created/): Use this as the product creation callback for custom integrations. When a customer finishes a design, Sign Customiser POSTs this payload to the create-product URL configured on your custom integration. Verify the signature, create the product in your own platform, then return a 200 JSON response containing the `external_id` you will later send in `POST /api/v2/orders`.
- [WEBHOOK Order created](https://www.signcustomiser.com/help/api/webhook-order-created/): Delivered when Sign Customiser records a completed order for your organisation.
- [WEBHOOK Form submitted](https://www.signcustomiser.com/help/api/webhook-form-submitted/): Delivered when a customer submits a Sign Customiser form workflow.

### Current API, v3: Webhook subscriptions

- [GET List webhook subscriptions](https://www.signcustomiser.com/help/api/v3-get-list-webhook-subscriptions/): Lists the authenticated Store's outbound webhook subscriptions in stable creation order. Requires `webhooks:read`. Follow `links.next` while `pagination.has_more` is true. Signing secrets and provider metadata are never returned.
- [POST Create a webhook subscription](https://www.signcustomiser.com/help/api/v3-post-create-a-webhook-subscription/): Registers an HTTPS callback for one topic. Requires `webhooks:write` and an `Idempotency-Key`. The response contains the signing `secret`; store it securely because later subscription responses never return it. Verify deliveries using https://www.signcustomiser.com/help/integrations/subscribe-to-webhooks/. Retrying the exact request and key replays the original response without creating a second subscription or rotating the secret. Registration does not itself enable delivery: `product:created` and `order:created` emit only for Stores with custom API access. Contact Sign Customiser support to confirm eligibility if those events do not arrive.
- [GET Get a webhook subscription](https://www.signcustomiser.com/help/api/v3-get-get-a-webhook-subscription/): Returns one Store-scoped subscription without its signing secret or provider metadata. Requires `webhooks:read` and is safe to retry.
- [PATCH Update a webhook subscription](https://www.signcustomiser.com/help/api/v3-patch-update-a-webhook-subscription/): Applies an RFC 7396 JSON Merge Patch to `topic` and/or `url`. Omitted fields remain unchanged; null, read-only, and unknown fields are rejected. Requires `webhooks:write` and an `Idempotency-Key`.
- [DELETE Delete a webhook subscription](https://www.signcustomiser.com/help/api/v3-delete-delete-a-webhook-subscription/): Deletes a directly managed subscription. Requires `webhooks:write` and an `Idempotency-Key`. Retrying the same request and key replays the original success after the row is gone. Provider-managed subscriptions return 409 and must be removed through their provider.
- [GET List webhook event types](https://www.signcustomiser.com/help/api/v3-get-list-webhook-event-types/): Lists every event topic available for subscription, a static example of the payload currently delivered for that topic, and the existing signing verification guide. Requires `webhooks:read`. The catalogue is one complete page, performs no Store-data reads, and accepts no query parameters. Topic values are expected to grow; clients must tolerate unknown future values. `product:created` and `order:created` emit only for Stores with custom API access; catalogue visibility and successful subscription registration do not establish delivery eligibility. Contact Sign Customiser support to confirm access if those events do not arrive.

### Previous generation: Custom integrations

Backend contract for custom integrations: handle the signed product creation callback, return your own product ID, then submit completed orders into Sign Customiser.

- [POST Create an order](https://www.signcustomiser.com/help/api/post-create-an-order/): Step 2 of the custom integration flow. After your server handles the `product:created` callback and returns an `external_id`, send the completed order from your ecommerce platform. Each `products[].external_id` value must match a product ID you previously returned during product creation.
- [POST Create a legacy order](https://www.signcustomiser.com/help/api/post-create-a-legacy-order/): Deprecated. Use `POST /api/v2/orders` for new integrations.
- [POST Sync a legacy product](https://www.signcustomiser.com/help/api/post-sync-a-legacy-product/): Deprecated. Use the current custom integration flow for new builds.

### Previous generation: Customisers

- [GET List customisers](https://www.signcustomiser.com/help/api/get-list-customisers/): Get all customisers for the current organisation.
- [GET Get a customiser](https://www.signcustomiser.com/help/api/get-get-a-customiser/): Retrieve a single customiser.

### Previous generation: Pricing

- [GET Get customiser pricing](https://www.signcustomiser.com/help/api/get-get-customiser-pricing/): Retrieve all pricing configuration for a customiser. The `pricing_model` value is the internal enum name for the customiser's pricing model. The current product names are: `FIXED_WIDTH` is the Simple Letter Model, `MATERIAL_LENGTH` is the Advanced Letter Model, and `FRAME_FIT` is the Frame Fit Model. `FIXED_HEIGHT` is the deprecated legacy Fixed Height Model and is rejected with a 422 — the supported fixed-height sizing path is the Simple Letter Model (`FIXED_WIDTH`) with a `HEIGHT` height strategy on its sizes. Error responses always include a human-readable `message` field. Validation failures also include an `errors` object keyed by field path.
- [PUT Update customiser pricing](https://www.signcustomiser.com/help/api/put-update-customiser-pricing/): Replace all pricing configuration for a customiser. This is a full replacement: sizes and price-list rows omitted from the payload are deleted. A replacement that would delete size or price-list records still referenced by fonts or settings is rejected with a 409 and no changes are applied. The `pricing_model` value is the internal enum name for the customiser's pricing model. The current product names are: `FIXED_WIDTH` is the Simple Letter Model, `MATERIAL_LENGTH` is the Advanced Letter Model, and `FRAME_FIT` is the Frame Fit Model. This endpoint cannot switch a customiser to a different pricing model, and the deprecated `FIXED_HEIGHT` legacy model is rejected with a 422. Error responses always include a human-readable `message` field. Validation failures also include an `errors` object keyed by field path.

### Previous generation: Webhooks

Manage webhook subscriptions and inspect the event topics Sign Customiser can deliver to your own systems.

- [GET List all webhooks](https://www.signcustomiser.com/help/api/get-list-all-webhooks/): Get a list of all webhooks for the current organisation.
- [POST Create a new webhook](https://www.signcustomiser.com/help/api/post-create-a-new-webhook/): Register a new webhook endpoint to receive event notifications.
- [GET Get a single webhook](https://www.signcustomiser.com/help/api/get-get-a-single-webhook/): Retrieve details for a specific webhook.
- [PUT Update a webhook](https://www.signcustomiser.com/help/api/put-update-a-webhook/): Update an existing webhook's topic, URL, or metadata.
- [DELETE Delete a webhook](https://www.signcustomiser.com/help/api/delete-delete-a-webhook/): Remove a webhook subscription.
- [GET Webhook payload examples](https://www.signcustomiser.com/help/api/get-webhook-payload-examples/): Retrieve example webhook payloads for a specific topic. If data exists for the current organisation, real data will be used. Otherwise, example data is returned.
