# Categories

Read the product category tree.

Section: Commerce · REST API
Canonical URL: https://docs.omniretailconnect.nl/commerce/api/categories

## List categories

`GET /api/v1/categories` — Needs commerce.read. Equivalent MCP tool: list_categories.

*Query parameters of GET /categories*

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `parent` | string | Optional | Category id or slug. Omit it for the top level. |
| `depth` | integer | Optional | 1 to 3, default 2. |

**List categories · curl**

```bash
export COMMERCE_API_TOKEN='ocm_<token>'

curl -sS "https://<your-shop-domain>/api/v1/categories?depth=3" \
  -H "Authorization: Bearer $COMMERCE_API_TOKEN"
```

**List categories · JavaScript**

```javascript
// Server-side code only: never put the token in browser code.
// Top-level await needs an ES module (a .mjs file or "type": "module").
const token = process.env.COMMERCE_API_TOKEN; // ocm_<token>

const response = await fetch('https://<your-shop-domain>/api/v1/categories?depth=3', {
  headers: { Authorization: `Bearer ${token}` },
});

console.log(response.status, await response.json());
```

**List categories · PHP**

```php
<?php

$token = getenv('COMMERCE_API_TOKEN'); // ocm_<token>

$curl = curl_init('https://<your-shop-domain>/api/v1/categories?depth=3');
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],
]);

$body = json_decode(curl_exec($curl), true);

echo curl_getinfo($curl, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($body);
```

**List categories · Python**

```python
import json
import os
import urllib.error
import urllib.request

token = os.environ["COMMERCE_API_TOKEN"]  # ocm_<token>

request = urllib.request.Request(
    "https://<your-shop-domain>/api/v1/categories?depth=3",
    headers={"Authorization": f"Bearer {token}"},
)

try:
    with urllib.request.urlopen(request) as response:
        print(response.status, json.load(response))
except urllib.error.HTTPError as error:
    # Errors are JSON too: {"error": {"code": ..., "message": ...}}
    print(error.code, json.load(error))
```

**Example response · 200**

```json
{
    "data": {
        "categories": [
            {
                "id": 12,
                "slug": "gereedschap",
                "name": "Gereedschap",
                "parent_id": null,
                "product_count": 48,
                "children": [
                    {
                        "id": 14,
                        "slug": "handgereedschap",
                        "name": "Handgereedschap",
                        "parent_id": 12,
                        "product_count": 21,
                        "children": []
                    }
                ]
            }
        ],
        "truncated": false
    }
}
```

*Fields of data*

| Field | Type | Description |
| --- | --- | --- |
| `categories` | array | Nodes with `id`, `slug`, `name`, `parent_id`, `product_count` and `children`. |
| `product_count` | integer | Published products in the category and its subcategories. |
| `truncated` | boolean | `true` when the tree was cut at 500 nodes. |

Use a category `id` or `slug` as `collection` in [Search products](https://docs.omniretailconnect.nl/commerce/api/products.md#search-products).

## Errors

*Errors of GET /categories*

| Status | error.code | When |
| --- | --- | --- |
| `401` | `unauthenticated` | Missing, malformed, unknown, revoked or expired token, or a token without the `api` channel. |
| `404` | `not_found` | The `parent` category does not exist. |
| `422` | `invalid_argument` | `depth` outside 1 to 3, or an unknown parameter. |
| `429` | `too_many_requests` | Rate limit reached. Wait the number of seconds in `Retry-After`. |
