# POST Create an extra

Adds an extra to the customiser, at the end of the current presentation order. `name` and `input_type` are required; every other field has a documented default (`default_value` false, both exclusion lists empty, `base_price` 0, `price_multiplier` 0, `price_multiplier_target` base_letter_price). The input type decides which fields the extra reads, and naming one it never reads is a 422 `field_not_used_by_input_type` on that field. A `yes_no` extra reads its labels, default answer, colour exclusions, and its own price; a `dropdown` or `image_choice` reads `select_options`, where each choice carries its own price; a `notes` extra reads `char_limit`. A dropdown or image choice needs at least one choice. An extra charges a flat amount or a multiplier, never both: naming one clears the other, and a body naming both is a 422 `price_mode_conflict`. A defaulted price charges nothing. Colour exclusions name the customiser's own colours — an id from another customiser or another store is a 422 on the offending element — and each one may be scoped to a single `letter_part` or left unscoped with null. Choice images cannot be set here: image upload is a follow-up surface, so `image_url` and `example_image_url` are read-only and an image-choice extra created through the API draws its choices without pictures until one is uploaded in the merchant admin. Requires `customisers:write` and an `Idempotency-Key`. The write clears the customiser's cached storefront configuration and runs the advisory language sync. It never regenerates Shopify products, product images, or the product cache, so live listings are untouched. Option writes also spend one unit of a separate per-key option-write budget; exhausting it returns a 429 with `retry_after`.

- Source URL: https://www.signcustomiser.com/help/api/v3-post-create-an-extra/
- Markdown URL: https://www.signcustomiser.com/help/api/v3-post-create-an-extra.md
- Group: Customiser extras
- Method: POST
- Path: /api/v3/customisers/{customiser_id}/extras
- Auth: Bearer token
- Required scopes: `customisers:write`

## Path parameters

- customiser_id (string, required): The customiser id. Example: 1

## Body parameters

- input_type (string, optional): No description provided.
- yes_colour_exclusions (array, optional): No description provided.
- no_colour_exclusions (array, optional): No description provided.
- price_multiplier_target (string, optional): No description provided.
- name (string, optional): No description provided.
- description (string, optional): No description provided.
- true_label (string, optional): No description provided.
- false_label (string, optional): No description provided.
- default_value (boolean, optional): No description provided.
- base_price (integer, optional): No description provided.

## Request body example

```json
{
  "input_type": "yes_no",
  "yes_colour_exclusions": [
    {
      "letter_part": "face"
    }
  ],
  "no_colour_exclusions": [
    []
  ],
  "price_multiplier_target": "base_letter_price",
  "name": "Dimmer",
  "description": "Adds a dimmer switch to the transformer",
  "true_label": "Yes",
  "false_label": "No",
  "default_value": false,
  "base_price": 500
}
```

## cURL example

```bash
curl https://web.signcustomiser.com/api/v3/customisers/1/extras \
  --request POST \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "input_type": "yes_no",
  "yes_colour_exclusions": [
    {
      "letter_part": "face"
    }
  ],
  "no_colour_exclusions": [
    []
  ],
  "price_multiplier_target": "base_letter_price",
  "name": "Dimmer",
  "description": "Adds a dimmer switch to the transformer",
  "true_label": "Yes",
  "false_label": "No",
  "default_value": false,
  "base_price": 500
}'
```

## Response examples

### 201 POST 201 example 1

```json
{
  "data": {
    "object": "extra",
    "id": 9,
    "customiser_id": 42,
    "name": "Dimmer",
    "description": null,
    "input_type": "yes_no",
    "true_label": null,
    "false_label": null,
    "default_value": false,
    "char_limit": null,
    "yes_colour_exclusions": [],
    "no_colour_exclusions": [],
    "select_options": null,
    "image_url": null,
    "base_price": 0,
    "currency": "USD",
    "price_multiplier": 0,
    "price_multiplier_target": "base_letter_price",
    "sort_order": 1,
    "created_at": "2026-08-13T00:00:00Z",
    "updated_at": "2026-08-13T00:00:00Z"
  },
  "links": {
    "self": "https://web.signcustomiser.com/api/v3/customisers/42/extras/9",
    "documentation": "https://www.signcustomiser.com/help/api/"
  },
  "meta": {
    "api_version": "v3",
    "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
  }
}
```

### 400 Missing idempotency key

```json
{
  "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"
}
```

### 401 Missing API key

```json
{
  "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"
}
```

### 403 Insufficient scope

```json
{
  "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"
}
```

### 404 Unknown customiser

```json
{
  "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"
}
```

### 409 Idempotency conflict

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/idempotency_key_conflict",
  "title": "Idempotency key conflict",
  "status": 409,
  "code": "idempotency_key_conflict",
  "detail": "This Idempotency-Key was already used for a different request body on this operation.",
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 413 Request body too large

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/request_too_large",
  "title": "Request too large",
  "status": 413,
  "code": "request_too_large",
  "detail": "The request body must not exceed 2 MiB.",
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 422 Field the input type never reads

```json
{
  "type": "https://www.signcustomiser.com/help/api/problems/validation_failed",
  "title": "Validation failed",
  "status": 422,
  "code": "validation_failed",
  "detail": "A notes extra never reads base_price.",
  "errors": [
    {
      "pointer": "/base_price",
      "code": "field_not_used_by_input_type",
      "detail": "A notes extra does not use base_price."
    }
  ],
  "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t"
}
```

### 429 Option write budget exhausted

```json
{
  "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"
}
```
