# Set default customiser language (`set_default_customiser_language`)

Makes one customiser language the default, which is the copy the live storefront falls back to when a shopper locale has no published language. The previous default loses the flag at the same time, and the authoring language does not change. The language must be published with a current published value for every required key, otherwise the call is refused with language_not_defaultable. Setting the default on the language that already holds it changes nothing. The call requires confirm true and changes nothing without it; dry_run true checks the change without applying it. It requires the customisers:write scope and an idempotency_key.

- Source URL: https://www.signcustomiser.com/help/mcp/tools/set_default_customiser_language/
- Markdown URL: https://www.signcustomiser.com/help/mcp/tools/set_default_customiser_language.md
- MCP endpoint: https://mcp.signcustomiser.com
- Required scope: `customisers:write`
- Behaviour: destructive write

## Purpose

Change which language the storefront falls back to, after the merchant has agreed to it.

## Annotations

| Hint | Value |
| --- | --- |
| readOnlyHint | false |
| destructiveHint | true |
| idempotentHint | true |
| openWorldHint | true |

## Prerequisites

- A customiser id from list_customisers and a language code from list_customiser_languages.
- A published language whose required published copy is complete; publish_customiser_language publishes it.
- The merchant explicit agreement, sent as confirm true.
- A merchant has connected this store and approved the customisers:write scope.

## Side effects

- Makes this language the default and removes the default flag from the previous default.
- Changes the copy shoppers see when their locale has no published language.
- Clears the customiser cached storefront configuration and runs the language sync.
- Claims the idempotency_key for at least 24 hours.

## Arguments

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `customiser_id` | integer | yes | The customiser id, from list_customisers. |
| `language_code` | string | yes | The BCP 47 language tag the language is addressed by, such as fr or pt-BR, from list_customiser_languages. |
| `confirm` | boolean | unless `dry_run` is true | Must be true to apply the change, because the storefront falls back to this language instead of the current default. Without it the call returns a confirmation_required error and changes nothing. |
| `idempotency_key` | string | unless `dry_run` is true | A client-generated key unique to this logical write, such as a UUID. Required: repeating the call with the same key and the same arguments replays the original result instead of writing twice, and the same key with different arguments is an idempotency_key_conflict. |
| `dry_run` | boolean | no | When true, the change is checked against the language publish state and its required published copy is checked and nothing is written: the result is the same verdict the apply would have reached, and a problem the apply would have raised comes back as the same tool error. Defaults to false. A dry run claims no key. A dry run does not require the confirm argument. |

## Result

The language record after the change. A dry run returns the verdict instead and changes nothing.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `request_id` | string | yes |  |
| `store` | object | yes |  |
| `store.id` | integer | yes |  |
| `store.name` | string | yes |  |
| `customiser_id` | integer | yes |  |
| `language` | object | no | The language after the change. Absent on a dry run. |
| `language.language_code` | string | yes |  |
| `language.source_language_code` | string or null | no |  |
| `language.display_name` | string or null | no |  |
| `language.status` | string | yes |  |
| `language.is_default` | boolean | yes |  |
| `language.is_authoring` | boolean | yes |  |
| `language.translation_summary` | object or null | no |  |
| `language.ai_translation` | object or null | no |  |
| `language.published_at` | string or null | no |  |
| `language.updated_at` | string or null | no |  |
| `dry_run` | boolean | no | Present and true only when dry_run was requested. |
| `valid` | boolean | no | Present only on a dry run, and always true: a failing dry run returns a tool error instead. |
| `verdict` | object | no | Present only on a dry run: the verdict. |
| `idempotent_replay` | boolean | no | True when this call replayed a previously recorded response for the same idempotency_key instead of applying the write again. |

## Error cases

| Code | Recovery |
| --- | --- |
| `confirmation_required` | Send confirm true once the merchant has agreed to the change. Nothing changed. |
| `idempotency_subject_changed` | The language changed after the recorded change. Issue a new key and re-check the language before writing again. |
| `insufficient_scope` | The connection was approved without customisers:write. |
| `language_not_defaultable` | Read reason. not_published: publish the language first. incomplete_published_translations: write and publish its missing required copy first. |
| `resource_not_found` | No customiser with that id, or no language with that code on it. |
| `resource_state_conflict` | The language changed while the call ran. Read it again and retry. |

## Example: Make a published language the default

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "set_default_customiser_language",
    "arguments": {
      "customiser_id": 42,
      "language_code": "fr",
      "confirm": true,
      "idempotency_key": "d0e1f2a3-b4c5-4d67-8e90-a1b2c3d4e5f6"
    }
  }
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": {
      "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t",
      "store": {
        "id": 12,
        "name": "Demo Signs"
      },
      "customiser_id": 42,
      "language": {
        "language_code": "fr",
        "source_language_code": "en",
        "display_name": "French",
        "status": "published",
        "is_default": true,
        "is_authoring": false,
        "translation_summary": {
          "key_count": 184,
          "required_key_count": 96,
          "translated_key_count": 184,
          "retired_key_count": 0,
          "missing_required_key_count": 0,
          "publishable": true
        },
        "ai_translation": null,
        "published_at": "2026-05-04T10:02:00Z",
        "updated_at": "2026-05-04T10:05:00Z"
      },
      "idempotent_replay": false
    }
  }
}
```

## Example: A draft language cannot be the default (error)

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "set_default_customiser_language",
    "arguments": {
      "customiser_id": 42,
      "language_code": "de",
      "dry_run": true
    }
  }
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": true,
    "structuredContent": {
      "error": {
        "code": "language_not_defaultable",
        "title": "Language not eligible to be the default",
        "detail": "The storefront uses the default language when another language has no published value for a key. Thus, the default language must be published. It must also have a current published value for each required key. Publish this language first, then retry.",
        "recovery": "Read reason. For not_published, publish the language first. For incomplete_published_translations, write and publish its missing required copy first. Then retry.",
        "reason": "not_published"
      }
    }
  }
}
```
