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

# Workspaces

> Create and manage workspaces, settings, profile, competitors, model configuration, and icon.

Every resource except health and discovery endpoints is bound to a workspace path segment—for example, `/api/v1/workspaces/{workspace}/settings`.

## Endpoints

| Method | Path                                                    | Scope            | Description                                |
| ------ | ------------------------------------------------------- | ---------------- | ------------------------------------------ |
| GET    | `/api/v1/workspaces`                                    | `workspace:read` | List accessible workspaces                 |
| POST   | `/api/v1/workspaces`                                    | Session-only     | Create a workspace                         |
| GET    | `/api/v1/workspaces/{workspace}/settings`               | `settings:read`  | Get workspace settings                     |
| PATCH  | `/api/v1/workspaces/{workspace}/settings`               | `settings:write` | Update workspace settings                  |
| GET    | `/api/v1/workspaces/{workspace}/profile`                | `settings:read`  | Get workspace profile (alias for settings) |
| PATCH  | `/api/v1/workspaces/{workspace}/profile`                | `settings:write` | Update workspace profile                   |
| GET    | `/api/v1/workspaces/{workspace}/model`                  | `settings:read`  | Get the AI model                           |
| PUT    | `/api/v1/workspaces/{workspace}/model`                  | `settings:write` | Set the AI model                           |
| GET    | `/api/v1/workspaces/{workspace}/competitors`            | `settings:read`  | List competitors                           |
| POST   | `/api/v1/workspaces/{workspace}/competitors`            | `settings:write` | Add a competitor                           |
| PUT    | `/api/v1/workspaces/{workspace}/competitors`            | `settings:write` | Update a competitor by index               |
| DELETE | `/api/v1/workspaces/{workspace}/competitors`            | `settings:write` | Remove a competitor by index               |
| PUT    | `/api/v1/workspaces/{workspace}/profile/icon`           | `settings:write` | Upload workspace icon (multipart)          |
| POST   | `/api/v1/workspaces/{workspace}/profile/icon/refresh`   | `settings:write` | Refresh icon from primary domain           |
| POST   | `/api/v1/workspaces/{workspace}/profile/design/import`  | `settings:write` | Import design markdown                     |
| POST   | `/api/v1/workspaces/{workspace}/profile/design/extract` | `settings:write` | Extract brand system from domain           |

## List workspaces

```bash theme={null}
curl -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     https://ai-cmo.dev/api/v1/workspaces
```

API keys see only the workspace they are bound to. Session cookies see all accessible workspaces.

## Create a workspace

Session-only. Supply a `workspaceConfigSchema` body:

```bash theme={null}
curl -X POST https://ai-cmo.dev/api/v1/workspaces \
  -H "Cookie: geo.session=..." \
  -H "Content-Type: application/json" \
  -d '{
    "brand": "acme",
    "displayName": "Acme Corp",
    "domains": ["acme.com"],
    "languages": ["en"],
    "regions": ["north-america"],
    "competitors": [
      {
        "name": "Competitor Inc",
        "domains": ["competitor.com"],
        "aliases": ["competitor"],
        "ambiguous": false
      },
      {
        "name": "Rival Co",
        "domains": ["rival.co"],
        "aliases": ["rival"],
        "ambiguous": false
      }
    ],
    "gscProperty": "sc-domain:acme.com",
    "ga4Property": "123456789",
    "activeSetSize": 50,
    "complianceProfile": "none",
    "quotas": {
      "discovery": 0.2,
      "problem_solution": 0.2,
      "use_case": 0.2,
      "comparison": 0.15,
      "expert": 0.15,
      "brand_research": 0.1
    }
  }'
```

### workspaceConfigSchema fields

<ParamField name="brand" type="string">
  Slug regex `/^[a-z0-9-]{2,20}$/`.
</ParamField>

<ParamField name="displayName" type="string">
  2–60 characters.
</ParamField>

<ParamField name="domains" type="string[]">
  1–8 domains, validated format.
</ParamField>

<ParamField name="languages" type="string[]">
  Min 1, from supported language list.
</ParamField>

<ParamField name="regions" type="string[]">
  Up to 8 region chips.
</ParamField>

<ParamField name="competitors" type="object[]">
  2–12 competitors.
</ParamField>

<ParamField name="gscProperty" type="string">
  Pattern `sc-domain:example.com`.
</ParamField>

<ParamField name="ga4Property" type="string">
  Numeric 6–12 digits.
</ParamField>

<ParamField name="activeSetSize" type="integer">
  20–300.
</ParamField>

<ParamField name="complianceProfile" type="enum">
  `"none"` or `"eu_medical"`.
</ParamField>

<ParamField name="quotas" type="object">
  Six intent keys summing to 1.0 (`discovery`, `problem_solution`, `use_case`, `comparison`, `expert`, `brand_research`), each 0–1.
</ParamField>

### Quota validation

Quotas must sum to 1.0 within a tolerance of `0.0001`. If the sum is off, the server returns `400 invalid_request` with the zod validation error.

## Get settings

```bash theme={null}
curl -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     https://ai-cmo.dev/api/v1/workspaces/{workspace}/settings
```

## Update settings

```bash theme={null}
curl -X PATCH https://ai-cmo.dev/api/v1/workspaces/{workspace}/settings \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "Acme Corp Updated",
    "about": "A leading provider of widgets"
  }'
```

The PATCH accepts a partial `WorkspaceUpdate` body. Only the fields you supply are updated. Supported fields include `displayName`, `domains`, `languages`, `about`, `industry`, `email`, `brandColors`, `brandMeta`, `socials`, `productsServices`, `designMd`.

## Model

Get the configured model:

```bash theme={null}
curl -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     https://ai-cmo.dev/api/v1/workspaces/{workspace}/model
```

Set the model:

```bash theme={null}
curl -X PUT https://ai-cmo.dev/api/v1/workspaces/{workspace}/model \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4o"}'
```

## Competitors

Competitors are indexed by their position in the array (0-based). Updates and deletes use `index` in the request body.

### List

```bash theme={null}
curl -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     https://ai-cmo.dev/api/v1/workspaces/{workspace}/competitors
```

### Add

```bash theme={null}
curl -X POST https://ai-cmo.dev/api/v1/workspaces/{workspace}/competitors \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "New Rival",
    "domains": ["newrival.com"],
    "aliases": ["new rival"],
    "ambiguous": false
  }'
```

### Update by index

```bash theme={null}
curl -X PUT https://ai-cmo.dev/api/v1/workspaces/{workspace}/competitors \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "index": 0,
    "name": "Updated Rival",
    "domains": ["updated.com"],
    "aliases": ["updated"],
    "ambiguous": false
  }'
```

### Remove by index

```bash theme={null}
curl -X DELETE https://ai-cmo.dev/api/v1/workspaces/{workspace}/competitors \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"index": 0}'
```

## Icon upload

```bash theme={null}
curl -X PUT https://ai-cmo.dev/api/v1/workspaces/{workspace}/profile/icon \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -F "file=@/path/to/icon.png"
```

## Icon refresh from domain

```bash theme={null}
curl -X POST https://ai-cmo.dev/api/v1/workspaces/{workspace}/profile/icon/refresh \
  -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
