Create product
Adds to the brand’s Products & services: a product or service (kind: "product", one kind
for both), or a category that groups several of them (kind: "category"). Each product carries its
own audience, markets, page, capabilities, outcomes and differentiators. Articles about it and
Brand Alignment checks of facts about it use these details, so a claim about one product is never
attributed to another. Same list as the Products & services tab of the Brand Profile page.
Requires the write:brand_profile scope, and the workspace must be enabled for API writes.
POST /v1/brands/{brand_id}/productsAuthorization
| 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
| Field | Type | Required | Description |
|---|---|---|---|
name | string, 1–120 chars | required | What customers call it |
kind | product | category | required | product is a product or service; category groups several. See the notes for where each can sit |
parent_product_id | uuid | null | optional | The category it belongs to. Omit for the top level |
summary | string, up to 600 chars | optional | What it is, in a sentence or two |
audience | string, up to 300 chars | optional | Who it’s for. Empty means the same as its category, or the brand profile’s audience |
capabilities | string[], up to 20 | optional | What it does. Each item up to 300 chars |
outcomes | string[], up to 10 | optional | Customer outcomes. Each item up to 300 chars |
differentiators | string[], up to 10 | optional | Why customers choose it. Each item up to 300 chars |
aliases | string[], up to 10 | optional | Other names people use for it. Each item up to 80 chars |
custom_fields | {label, value}[], up to 5 | optional | Custom product context. Unique labels up to 60 characters; each value up to 10,000 characters. Reference data, not instructions |
page_url | string | null | optional | Its page on the brand website, starting with https:// |
markets | string[] | null | optional | ISO country codes where it is sold. null or omitted means the same as its category, or every brand profile market |
topic_ids | uuid[], up to 50 | optional | Topics it belongs to, from List topics. Articles on these topics write about it |
Request
cURL
curl --request POST \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/products' \
--header 'Authorization: Bearer <api-key>' \
--header 'Idempotency-Key: <unique-per-attempt>' \
--header 'Content-Type: application/json' \
--data '{"name":"Brand Alignment","kind":"product","parent_product_id":"5d0b3a7e-2c41-4f8e-9b6a-1f7c2e8d4a90","markets":["DE","AT"]}'Response
200
{
"data": {
"product": {
"id": "c41e9a20-7b5d-4e83-a1f6-3d2b8c0e9f17",
"parent_product_id": "5d0b3a7e-2c41-4f8e-9b6a-1f7c2e8d4a90",
"kind": "product",
"name": "Brand Alignment",
"summary": "",
"audience": "",
"capabilities": [],
"outcomes": [],
"differentiators": [],
"aliases": [],
"page_url": null,
"markets": ["DE", "AT"],
"topic_ids": [],
"drafted_from_website": false,
"reviewed": true
}
},
"request_id": "req_7d21b0af59c34e18b6ac"
}Response fields
| Field | Type | Description |
|---|---|---|
data.product.id | uuid | required. Use it to update or delete the item, or as another item’s parent_product_id |
data.product.parent_product_id | uuid | null | required. null at the top level |
data.product.kind | string | required. line, category, product or service |
data.product.name | string | required |
data.product.summary | string | required. Empty when not set |
data.product.audience | string | required. Empty means it follows its line or the brand profile |
data.product.capabilities | string[] | required |
data.product.outcomes | string[] | required |
data.product.differentiators | string[] | required |
data.product.aliases | string[] | required |
data.product.page_url | string | null | required |
data.product.markets | string[] | null | required. null means it follows its line or the brand profile |
data.product.topic_ids | uuid[] | required |
data.product.drafted_from_website | boolean | required. True when Asky drafted it from the brand’s website |
data.product.reviewed | boolean | required. True once someone has added, edited or confirmed it |
request_id | string | required. Also returned as the x-request-id header |
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | An unknown field, a missing name or kind, a value over its limit, or a level that cannot sit inside the parent |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 403 | insufficient_scope | The key does not carry write:brand_profile |
| 403 | plan_required | This workspace is not enabled for API writes |
| 404 | not_found | The brand, the parent or a topic does not exist, or this key is not allowed to reach it |
| 409 | conflict | Something with that name already sits at that level, or the brand holds 300 items already |
| 429 | rate_limited | Over 60 requests per minute. See the Retry-After header |
Notes
Levels. One grouping level. A top-level item is a category or a product; a category holds products; a product holds nothing. A category cannot sit inside a category.
Inheritance. An empty audience and a null markets follow the category it belongs to,
then the brand profile. Countries outside the brand profile’s markets are kept but not used until
the profile lists them; add markets with Update brand profile.
Read the list back through Get brand profile, whose products
array carries each item in display order.
Idempotency-Key is required. Send a unique value per attempt and reuse it when retrying that
attempt, so a lost response does not become a duplicate. See Idempotency.