Update writing style
Change a style’s name or voice configuration, or make it the scope’s default. surface and
channel are immutable — there is no path to change either after creation.
PATCH /brands/{brand_id}/writing-styles/{style_id}Authorization
| Header | Type | Required |
|---|---|---|
Authorization | Bearer asky_sk_… | required |
Idempotency-Key | string | required on every write. See Idempotency |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
brand_id | uuid | required | From List brands |
style_id | uuid | required | From List writing styles |
Body parameters
All optional; send only what changes. At least one of these, or is_default, is required.
| Parameter | Type | Description |
|---|---|---|
name | string | 1 to 60 characters. Must stay unique within this style’s scope |
tone_of_voice | object | Replaces the whole object, not a per-key merge. presets entries must exactly match one of Expert, Conversational, Confident, Educational, Bold, Empathetic, Direct, Approachable, Storytelling — anything else belongs in custom_tones, which is free text |
writing_rules | object | Replaces the whole object, not a per-key merge |
heading_case_style | string | sentence or title. Content styles only |
translation_formality | string | null | default, prefer_more, prefer_less, or null to clear it. Content styles only |
competitor_statistics_mode | string | null | ask, include, exclude, or null to clear it. Content styles only |
english_variant | string | null | us, uk, or null to clear it. Content styles only |
language_overrides | object | Replaces the whole object. Social styles only |
is_default | boolean | Must be true if present. There is no way to unset a default through this field — set a different style as default instead |
Request
cURL
curl --request PATCH \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/writing-styles/8c082c21-a2eb-4c0f-bcd9-d58097a48e45' \
--header 'Authorization: Bearer <api-key>' \
--header 'Idempotency-Key: 4e8c1a3f-7b2d-46f0-ba9c-31c9ba7f0e5d' \
--header 'Content-Type: application/json' \
--data '{"is_default": true}'Response
200
{
"data": {
"id": "8c082c21-a2eb-4c0f-bcd9-d58097a48e45",
"name": "LinkedIn Professional",
"surface": "social",
"channel": "linkedin",
"is_default": true,
"sort_order": 0,
"tone_of_voice": { "presets": [], "custom_tones": [], "description": "" },
"writing_rules": { "always_do": [], "never_do": [] },
"heading_case_style": "sentence",
"translation_formality": null,
"competitor_statistics_mode": null,
"english_variant": null,
"language_overrides": {},
"tone_generation_status": null,
"created_at": "2026-08-29T02:15:00.000Z",
"updated_at": "2026-08-29T02:20:11.000Z"
},
"request_id": "req_4e8c1a3f7b2d46f0ba9c"
}Response fields
Same shape as Get writing style’s data — the current state
of the style after applying the update.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | No fields provided, a content-only field sent for a social style, language_overrides sent for a content style, or another malformed field. The message names it |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 401 | token_expired | The key passed its expiry date |
| 401 | token_revoked | The key was revoked |
| 404 | not_found | The style does not exist for this brand, or this key is not allowed to reach the brand |
| 409 | conflict | The new name collides with another style already in this scope |
| 429 | rate_limited | Over 60 requests per minute on write endpoints |
Notes
tone_of_voice and writing_rules are whole-object replacements, not merges. Sending
writing_rules with only always_do set overwrites never_do back to []. Fetch the current
style first if you only want to change part of it.
is_default only ever sets, never unsets. {"is_default": false} is rejected outright — the
field only accepts true. To remove a style as the default, set a different style as the
default instead; a scope is never left without one as long as it has at least one style.
Setting is_default: true and other fields in the same request applies both, but as two
separate underlying operations: the field changes, then the default swap. If the swap fails after
the fields already saved, you get a 500 and the fields are still changed — retry the request
(same Idempotency-Key behavior applies) rather than assuming nothing happened.