Update brand profile
Updates the brand’s identity and descriptions: name, industry, primary audience, aliases, short and detailed descriptions, key features and main market. These are the same fields the Identity and Descriptions tabs of the Brand Profile page edit, and they land in the same place.
This is a PATCH, not a PUT. Send only the fields you want to change: omit a field to leave it
alone, or pass null to clear it. There is no whole-document replace on this API, because one that
silently cleared the fields you did not send would be a data-loss bug wearing the right verb.
Requires the write:brand_profile scope, and the workspace must be enabled for API writes.
PATCH /v1/brands/{brand_id}/profileAuthorization
| Header | Type | Required |
|---|---|---|
Authorization | Bearer asky_sk_… | required |
Idempotency-Key | string | required |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
brand_id | uuid | required | From List brands |
Query parameters
None.
Any parameter you pass returns 400 invalid_request naming the offending key, rather than being
ignored silently.
Body
application/json. At least one field is required — an empty body returns 400 invalid_request
rather than reporting success for a call that changed nothing.
| Field | Type | Required | Description |
|---|---|---|---|
name | string, 1–100 chars | optional | May also rename the workspace. See Notes |
industry | string | null, up to 200 chars | optional | Used for positioning and competitor benchmarks |
primary_audience | string | null, up to 200 chars | optional | Who the brand serves first |
main_market | string | null, up to 100 chars | optional | |
short_description | string | null, up to 1000 chars | optional | Concise summary |
description | string | null, up to 5000 chars | optional | Detailed description |
aliases | string[] | null, max 50 | optional | Other names the brand is referenced by. null or [] clears them |
key_features | string[] | null, max 50 | optional | null or [] clears them |
Every limit matches what the Brand Profile page enforces, so a value written here is one the page can save back.
Request
cURL
curl --request PATCH \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/profile' \
--header 'Authorization: Bearer <api-key>' \
--header 'Idempotency-Key: <unique-per-attempt>' \
--header 'Content-Type: application/json' \
--data '{"industry":"B2B SaaS - AI Search Optimization Platforms","primary_audience":"B2B marketers"}'Response
200
{
"data": {
"profile": {
"name": "Asky",
"aliases": ["Asky Labs"],
"industry": "B2B SaaS - AI Search Optimization Platforms",
"short_description": "AI search visibility monitoring.",
"description": "Asky tracks how brands appear across AI search engines…",
"primary_audience": "B2B marketers",
"main_market": "Europe",
"key_features": ["Visibility tracking", "Competitor benchmarks"]
}
},
"request_id": "req_7d21b0af59c34e18b6ac"
}Response fields
The complete profile after the change, so you can put it straight into a cache without a follow-up read. The shape matches the corresponding fields of Get brand profile.
| Field | Type | Description |
|---|---|---|
data.profile.name | string | required |
data.profile.aliases | string[] | required. [] when none |
data.profile.industry | string | null | required |
data.profile.short_description | string | null | required |
data.profile.description | string | null | required |
data.profile.primary_audience | string | null | required |
data.profile.main_market | string | null | required |
data.profile.key_features | string[] | required. [] when none |
data.workspace_renamed | boolean | present only when name changed. false when the workspace has several brands and was deliberately left alone |
request_id | string | required. Also returned as the x-request-id header |
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | An unknown field, a value over its limit, or a body with no fields |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 403 | plan_required | This workspace is not enabled for API writes |
| 403 | insufficient_scope | The key lacks write:brand_profile, or is brand-restricted and attempted a rename. The message distinguishes them |
| 404 | not_found | The brand does not exist, or this key is not allowed to reach it. The two are deliberately indistinguishable |
| 409 | conflict | The brand has no analysed profile yet, so there is nothing to update |
| 429 | rate_limited | Over 60 requests per minute. See the Retry-After header |
Notes
Renaming the brand may also rename its workspace, on exactly the same rule the app uses: only
when the workspace holds a single active brand, and the workspace becomes "{name} Workspace". A
workspace with several brands is left alone, because renaming a shared workspace after one of its
brands would be wrong. data.workspace_renamed reports which happened, read back from the database
rather than assumed.
Because that reaches an entity above the brand, a key restricted to specific brands may not do
it: renaming would let a credential deliberately narrowed to one brand change the workspace it
lives in. Such a key gets 403 insufficient_scope with a message naming that reason, and every other field still updates normally. A key with
access to all brands behaves exactly like the app.
The workspace rename runs after the brand rename and is reported separately as
data.workspace_renamed. false is the normal answer for a multi-brand workspace and needs no
action. The brand rename itself always succeeds or the call fails, so a 200 means the brand was
renamed either way.
null clears, omission preserves. {"description": null} empties the detailed description;
leaving description out entirely keeps whatever is there. For aliases and key_features, both
null and [] clear the list.
Not editable here: domains, sitemaps, documentation sources, social profiles, connected social accounts and writing styles. Each either asserts ownership of something outside Asky, schedules crawl work, or holds credentials — none are text edits, so none sit behind this scope. Manage them in the app.
Changing the profile does not re-run anything. Prompt suggestions and alignment read the profile when they next run; updating it does not trigger a refresh, matching the app.
Idempotency-Key is required. Send a unique value per attempt and reuse it when retrying that
attempt: a retry replays the original response instead of executing again. See
Idempotency.