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

# Update Aggregate

Modify the configuration of an existing sub-tenant (aggregate). All fields are optional; only include fields you want to change.

---

## Endpoint

```
PUT /api/v3/aggregates/{id}
```

---

## Path Parameters

| Parameter | Type   | Description           |
| --------- | ------ | --------------------- |
| `id`      | string | Aggregate's tenant ID |

---

## Request Body

All fields are optional. Only include fields you want to update. Omitted fields are left unchanged.

### Core Fields

| Field                       | Type    | Description                                                                                                                                                                  |
| --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                      | string  | Store name (max 255 characters)                                                                                                                                              |
| `final_domain`              | string  | Store domain; platform subdomain or custom domain (max 255 characters, must be unique)                                                                                       |
| `lang`                      | string  | Store language (ISO 639-1 code)                                                                                                                                              |
| `timezone`                  | string  | Store timezone (IANA format)                                                                                                                                                 |
| `support_email`             | string  | Support and notifications email address (max 255 characters)                                                                                                                 |
| `disable_selling`           | boolean | When `true`, disables all e-commerce functionality on the store (checkout, paid plans, paid content).                                                                        |
| `landing_enabled`           | boolean | When `true`, the public landing page is shown.                                                                                                                               |
| `reader_flashcards_enabled` | boolean | Turns flashcards on (`true`) or off (`false`) in the reader for signed-in readers of the store (PDF and EPUB products). Never offered to anonymous readers or on audiobooks. |

:::info Flashcards and the dashboard
Store admins can also turn flashcards on or off from the reader settings in their dashboard. The API and the dashboard write the same setting, so the most recent change applies.
:::

### Branding Fields

| Field                 | Type   | Description                                                                                                                                                                                                                     |
| --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `primary_color`       | string | Primary brand color (hex format, e.g., `#336699`)                                                                                                                                                                               |
| `secondary_color`     | string | Secondary brand color (hex format, e.g., `#FF6600`)                                                                                                                                                                             |
| `reader_accent_color` | string | Accent color used in the reader's light and dark themes (hex format, e.g., `#0066CC`). Colors the reader, not the storefront.                                                                                                   |
| `logo_url`            | string | Public URL of the store logo, pointing to a JPG, PNG, WEBP, or SVG image (max 2048 characters). The platform downloads and hosts the image; see [Logo and Icon Import](./aggregates-v3-create.md#logo-and-icon-import).         |
| `icon_url`            | string | Public URL of the store icon/favicon, pointing to a JPG, PNG, WEBP, or SVG image (max 2048 characters). The platform downloads and hosts the image; see [Logo and Icon Import](./aggregates-v3-create.md#logo-and-icon-import). |

:::tip Nullable Fields
`primary_color`, `secondary_color`, `logo_url`, and `icon_url` accept `null` in the request, but an explicit `null` is ignored and the stored value is kept. `reader_accent_color` is the only field that is actually cleared by an explicit `null`; the reader then falls back to its built-in accent.
:::

:::info Reader Accent Color Scope
`reader_accent_color` only affects the reader's light and dark themes (buttons, interactive text and links, toolbar icons, the book title, the theme selector, and the reading progress bar). The other reading themes (sepia, cream, cyan, and high contrast) keep their own fixed accent and are not affected. On the dark theme, the platform automatically lightens the configured color so it stays legible against the dark background, so it will not match the configured hex exactly there. The platform does not validate contrast, so a very light color reads poorly against the light theme's white background. `reader_accent_color` is independent from `primary_color` and `secondary_color`, which apply to the storefront only; setting one never affects the others.
:::

:::info Colors on the block-based storefront
When the store runs on the block-based storefront, its colors come from the **Theme** its admins publish from the dashboard. On those stores an update ignores `primary_color` and `secondary_color` without returning an error, while the other fields in the same request are still applied. Responses return the colors of the published theme.
:::

### Auth Token (SSO) Fields

Send an `external_auth` object to configure single sign-on for the sub-tenant. See the [Auth Token guide](../../auth-integrations/auth-token.md) for the token format and login flow.

| Field                        | Type   | Description                                                                                 |
| ---------------------------- | ------ | ------------------------------------------------------------------------------------------- |
| `external_auth.key`          | string | Write-only HMAC secret (minimum 32 characters). Never returned. See the update rules below. |
| `external_auth.issuer`       | string | Your platform identifier. Required when a new `key` is sent.                                |
| `external_auth.redirect_url` | string | Where users are sent on auth errors. Required when a new `key` is sent.                     |
| `external_auth.login_url`    | string | Your platform's login URL.                                                                  |
| `external_auth.logout_url`   | string | Where users are sent after logging out.                                                     |
| `external_auth.home_url`     | string | Your platform's home URL.                                                                   |
| `external_auth.account_url`  | string | Your platform's account URL.                                                                |

The `key` field drives how an update is applied:

- **Omit `key`**: the stored secret is kept, and any other `external_auth` fields you send are updated. Use this to edit the issuer or URLs without resending the secret.
- **Send a non-empty `key`**: it replaces the stored secret and (re)activates SSO. `issuer` and `redirect_url` are required in this case.
- **Send `key` as `null`**: SSO is deactivated and the whole `external_auth` configuration is cleared.

:::info Key is write-only
Responses never include `key`. They return an `external_auth` object with every other field plus an `enabled` boolean that reflects whether a key is currently configured.
:::

### Storefront Redirect Fields

Send a `storefront_redirect` object to turn the external storefront redirect on or off. See [Storefront Redirect Fields](./aggregates-v3-create.md#storefront-redirect-fields) on the create endpoint for what the redirect covers.

| Field                         | Type    | Description                                                                                                 |
| ----------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `storefront_redirect.enabled` | boolean | Turns the redirect on (`true`) or off (`false`). Required when `storefront_redirect` is sent.               |
| `storefront_redirect.url`     | string  | Where visitors are sent; an `http` or `https` URL (max 2048 characters). Required when `enabled` is `true`. |

The fields you send are merged over the stored configuration:

- **Turn it on**: send `enabled: true` together with `url`, even if a URL is already stored.
- **Turn it off**: send `enabled: false`. The stored `url` is kept and responses keep returning it. Send `url` as `null` in the same request to clear it as well.
- **Change the destination**: send `enabled: true` with the new `url`.

---

## Request Examples

### Update Store Name

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Updated Bookstore"
  }'
```

### Update Branding

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "primary_color": "#1A237E",
    "secondary_color": "#FF6F00",
    "logo_url": "https://example.com/new-logo.png"
  }'
```

### Set the Reader Accent Color

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "reader_accent_color": "#0066CC"
  }'
```

### Clear the Reader Accent Color

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "reader_accent_color": null
  }'
```

Sending `reader_accent_color` as `null` clears the stored value and the reader falls back to its built-in accent. This is a deliberate exception: the other branding fields (`primary_color`, `secondary_color`, `logo_url`, `icon_url`) ignore an explicit `null` and keep the stored value.

### Turn On Flashcards

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "reader_flashcards_enabled": true
  }'
```

Send `false` to turn them off again.

### Update Domain and Language

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "final_domain": "new-bookstore-domain.publica.la",
    "lang": "es",
    "timezone": "America/Buenos_Aires"
  }'
```

### Update Support Email

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "support_email": "new-support@mybookstore.com"
  }'
```

### Configure or Update Auth Token (SSO)

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "external_auth": {
      "key": "your-32-character-or-longer-secret-key",
      "issuer": "my-platform",
      "redirect_url": "https://my-platform.com/auth-error"
    }
  }'
```

### Edit Auth Token Fields Without Resending the Secret

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "external_auth": {
      "redirect_url": "https://my-platform.com/new-auth-error"
    }
  }'
```

### Deactivate Auth Token (SSO)

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "external_auth": { "key": null }
  }'
```

### Redirect the Storefront to an External Site

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "storefront_redirect": {
      "enabled": true,
      "url": "https://discovery.example.com"
    }
  }'
```

### Turn Off the Storefront Redirect

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "storefront_redirect": { "enabled": false }
  }'
```

### Combined Update

```bash
curl -X PUT "https://yourstore.publica.la/api/v3/aggregates/42" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Rebranded Bookstore",
    "primary_color": "#006341",
    "secondary_color": "#FF6F00",
    "reader_accent_color": "#006341",
    "logo_url": "https://example.com/rebrand-logo.png",
    "support_email": "hello@rebranded.com"
  }'
```

---

## Response

### Success Response (200 OK)

```json
{
  "data": {
    "id": 42,
    "slug": "my-bookstore",
    "name": "My Updated Bookstore",
    "final_domain": "mybookstore.publica.la",
    "lang": "en",
    "timezone": "America/New_York",
    "support_email": "support@mybookstore.com",
    "primary_color": "#1A237E",
    "secondary_color": "#FF6F00",
    "reader_accent_color": "#0066CC",
    "reader_flashcards_enabled": true,
    "logo_url": "https://assets.publica.la/my-bookstore/logo/logo.png",
    "icon_url": null,
    "disable_selling": false,
    "landing_enabled": true,
    "storefront_redirect": {
      "enabled": false,
      "url": null
    },
    "external_auth": {
      "enabled": true,
      "issuer": "my-platform",
      "redirect_url": "https://my-platform.com/auth-error",
      "login_url": null,
      "logout_url": null,
      "home_url": null,
      "account_url": null
    },
    "created_at": "2026-03-24T15:30:00+00:00"
  }
}
```

---

## Error Handling

### Not Found (404)

Returned when the aggregate does not exist or does not belong to your store:

```json
{
  "message": "Not found."
}
```

### Validation Errors (422)

```json
{
  "message": "The given data was invalid.",
  "errors": {
    "final_domain": ["The final domain has already been taken."],
    "primary_color": ["The primary color format is invalid."]
  }
}
```

### Authentication Errors (401)

```json
{
  "message": "Unauthenticated."
}
```

### Authorization Errors (403)

```json
{
  "message": "Tenant does not have aggregation capabilities."
}
```

---

## Validation Rules

| Field                         | Rules                                                                                                                                           |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                        | Optional, string, max 255 characters                                                                                                            |
| `final_domain`                | Optional, string, max 255 characters, unique (excluding current), valid format                                                                  |
| `lang`                        | Optional, valid language code                                                                                                                   |
| `timezone`                    | Optional, valid IANA timezone                                                                                                                   |
| `support_email`               | Optional, valid email, max 255 characters                                                                                                       |
| `primary_color`               | Optional, nullable, hex color format (`#RRGGBB`)                                                                                                |
| `secondary_color`             | Optional, nullable, hex color format (`#RRGGBB`)                                                                                                |
| `reader_accent_color`         | Optional, nullable, hex color format (`#RRGGBB`). An explicit `null` clears the stored value                                                    |
| `reader_flashcards_enabled`   | Optional, boolean                                                                                                                               |
| `logo_url`                    | Optional, nullable, `http` or `https` URL, max 2048 characters. Must be reachable and serve a JPG, PNG, WEBP, or SVG image of at most 20,000 KB |
| `icon_url`                    | Optional, nullable, `http` or `https` URL, max 2048 characters. Must be reachable and serve a JPG, PNG, WEBP, or SVG image of at most 20,000 KB |
| `disable_selling`             | Optional, boolean                                                                                                                               |
| `landing_enabled`             | Optional, boolean                                                                                                                               |
| `storefront_redirect`         | Optional, object                                                                                                                                |
| `storefront_redirect.enabled` | Required when `storefront_redirect` is sent, boolean                                                                                            |
| `storefront_redirect.url`     | Required when `storefront_redirect.enabled` is `true`, nullable, `http` or `https` URL, max 2048 characters                                     |
| `external_auth.key`           | Optional, nullable, string with a minimum of 32 characters. Send `null` to clear the configuration                                              |
| `external_auth.issuer`        | Required when a non-empty `key` is sent, string, max 255 characters                                                                             |
| `external_auth.redirect_url`  | Required when a non-empty `key` is sent, valid URL, max 2048 characters                                                                         |
| `external_auth.login_url`     | Optional, nullable, valid URL, max 2048 characters                                                                                              |
| `external_auth.logout_url`    | Optional, nullable, valid URL, max 2048 characters                                                                                              |
| `external_auth.home_url`      | Optional, nullable, valid URL, max 2048 characters                                                                                              |
| `external_auth.account_url`   | Optional, nullable, valid URL, max 2048 characters                                                                                              |

---

## See Also

- [Get Aggregate](./aggregates-v3-get.md) - Retrieve aggregate details
- [Create Aggregate](./aggregates-v3-create.md) - Provision a new aggregate
- [Overview](./aggregates-v3-overview.md) - API overview
