> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brand-wallet.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a category

> Add a product category to your BrandWallet menu. Categories power category-filtered campaigns and menu synchronization.

```http theme={null}
POST $BASE_URL/v1/categories
```

**Adds a new category to your organization; the record is always created with `status: 1` (published).**

> **Auth:** `Authorization: Bearer <accessToken>` — an organization-scoped token from [Authentication](/api/authentication). Integrator API users carry the category management permission by default.

> Categories are also created automatically when you send `items[].categories` on transactions — see [menu synchronization](/api/process-transaction#menu-synchronization-lazy-sync). Use this endpoint when you want to upload or manage the category tree explicitly.

### Payload schema

```json theme={null}
{
  "name": { "TR": "…", "EN": "…" },
  "description": "…",
  "opaqueId": "…",
  "parent": "category-uuid",
  "types": {}
}
```

### Body

All fields except `name` are optional.

| Field | Type | Description |
| - | - | - |
| `name` | string \| MLString | Required. A plain string (`"Hot Drinks"`) or a language code → text object (`{ "TR": "…", "EN": "…" }`). MLString language keys: `EN`, `TR`, `AR`, `RU`, `ES`, `IT`, `FR`, `HE`, `DE`, `AZ`. |
| `description` | string \| MLString | Description. |
| `opaqueId` | string | Your external category id (used for [menu sync](/api/process-transaction#menu-synchronization-lazy-sync) matching). |
| `parent` | string | Parent category id — for building a hierarchy. |
| `types` | object | Free-form extra data. |

> `status` is not accepted in the body — records are always created with `1` (use the [delete endpoint](/api/delete-category) to remove a category). `organization` is derived from your token; you cannot create categories for another organization. Fields outside the schema are silently dropped; type errors return 400 with the individual validation messages joined in `message`.

### Example

```bash theme={null}
curl --request POST \
  --url "$BASE_URL/v1/categories" \
  --header 'Authorization: Bearer <accessToken>' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": { "TR": "Espresso Bazlı", "EN": "Espresso Based" },
    "opaqueId": "espresso-based",
    "parent": "1e1cc0fb-55a1-4679-80df-6dccb936273f"
  }'
```

### Response

Returns **201** with the created category document.

```json theme={null}
{
  "id": "79a83256-2925-44b4-9bdc-a401caccf969",
  "name": { "TR": "Espresso Bazlı", "EN": "Espresso Based" },
  "organization": "07f84834-1184-4eb6-82f5-7eda13231fc3",
  "status": 1,
  "opaqueId": "espresso-based",
  "parent": "1e1cc0fb-55a1-4679-80df-6dccb936273f",
  "createdAt": "2026-09-18T09:23:28.303Z",
  "updatedAt": "2026-09-18T09:23:28.303Z"
}
```

Notes:

* `organization` is set server-side from your token — trust the values in the response, not what you sent.
* `parent` is not validated — sending an unknown id still creates the record; keeping the hierarchy consistent is the caller's responsibility.
* Optional fields you did not send are omitted from the response — do not expect `null`.
