# Namespaces

A namespace is the container [KV Store](/en/documentation/platform/kv-store/) keeps keys and values in. Its name is its identifier, and a namespace carries no numeric id. The Azion API v4 addresses a namespace by name, and a [function](/en/documentation/platform/functions/) opens one by name through `Azion.KV`. That client belongs to the runtime rather than to KV Store, so its methods, options, and errors are documented with the other runtime bindings, in [KV Store API](/en/documentation/devtools/runtime/api-reference/kv-store/).

A namespace is permanent. It cannot be renamed, deactivated, emptied, or deleted, on any interface. The Azion API v4 exposes three operations on it — create, list, and retrieve — and a function cannot create one either. Once the account holds a name, it holds that name from then on, so the name is worth choosing before the first request. This page lists the fields of a namespace, the three operations, the list envelope, and the errors a rejected request returns.

---

## Namespace names

A namespace name is chosen at creation and cannot be changed afterwards.

| Rule       | Value                                                                                                               |
| ---------- | ------------------------------------------------------------------------------------------------------------------- |
| Length     | 3 to 63 characters                                                                                                  |
| Characters | Letters, numbers, the hyphen (`-`), and the underscore (`_`), matching `^[a-zA-Z0-9_-]+$`                           |
| Case       | Uppercase is accepted, and names are case-sensitive. `BadNameUpper` and `badnameupper` are two different namespaces |
| Uniqueness | A name is unique within your account                                                                                |

A name shorter than 3 characters, longer than 63 characters, or carrying a character outside the pattern returns `400` with `validation_error`. A name the account already holds returns `400` with the message `Namespace already exists`, and not `409`.

The pattern accepts uppercase letters, so `Orders-EU` is as valid a name as `orders-eu`, and the two are **different namespaces**: a retrieve of one answers `200` while the same name in another case answers `404` with `namespace_not_found`. Lowercase is a convention rather than a rule, and it matters because a namespace cannot be deleted, so a name created in the wrong case is permanent. For the convention Azion recommends, refer to [Best practices](/en/documentation/platform/kv-store/best-practices/).

---

## Namespace fields

| Field           | Type                       | Required | Default | Description                                                      |
| --------------- | -------------------------- | -------- | ------- | ---------------------------------------------------------------- |
| `name`          | string, 3 to 63 characters | Yes      | —       | The namespace name, and its identifier. Read-only after creation |
| `created_at`    | date-time                  | —        | —       | When the namespace was created. Read-only                        |
| `last_modified` | date-time                  | —        | —       | When the namespace last changed. Read-only                       |

A create request accepts `name`, and nothing else. The resource carries these three fields and no others: there is no `id`, no `description`, and no `status`. No field is editable afterwards.

The two timestamp fields come back in two formats. A create response carries microseconds and no zone, as in `2026-01-01T12:00:00.577829`. A retrieve or a list response carries whole seconds and a zone, rounded up, as in `2026-01-01T12:00:01+00:00`. Both describe the same instant, and the samples below show each response in its own format.

---

## Operations

Every operation is authenticated and sits under `https://api.azion.com/v4/workspace/kv`.

| Operation            | Method and path          |
| -------------------- | ------------------------ |
| Create a namespace   | `POST /namespaces`       |
| List namespaces      | `GET /namespaces`        |
| Retrieve a namespace | `GET /namespaces/{name}` |

Create, list, and retrieve are the entire surface.

### Create a namespace

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/kv/namespaces \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "my-namespace"
}'
```

The response carries `201` and the whole namespace:

```json
{
  "name": "my-namespace",
  "created_at": "2026-01-01T12:00:00.577829",
  "last_modified": "2026-01-01T12:00:00.577829"
}
```

The request is synchronous, and there is no provisioning state to poll. The `name` the response carries is the handle every later call uses. A function opens the namespace under that same name.

### List namespaces

```bash
curl --request GET \
  --url https://api.azion.com/v4/workspace/kv/namespaces \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

The response carries `200`, one namespace per entry under `results`, and a `pagination` object beside them:

```json
{
  "results": [
    {
      "name": "my-namespace",
      "created_at": "2026-01-01T12:00:01+00:00",
      "last_modified": "2026-01-01T12:00:01+00:00"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 50,
    "total_count": 1,
    "total_pages": 1,
    "has_next": false,
    "has_previous": false
  }
}
```

The list returns every namespace the account holds, one page at a time. That envelope is not the one the rest of the Azion API v4 uses: Pagination describes it.

### Retrieve a namespace

```bash
curl --request GET \
  --url https://api.azion.com/v4/workspace/kv/namespaces/my-namespace \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

The response carries `200`:

```json
{
  "name": "my-namespace",
  "created_at": "2026-01-01T12:00:01+00:00",
  "last_modified": "2026-01-01T12:00:01+00:00"
}
```

The path segment is the namespace name, and not an identifier. A name the account does not hold returns `404`:

```json
{
  "state": "error",
  "error": {
    "code": "namespace_not_found",
    "message": "Namespace not found",
    "details": {
      "name": "no-such-namespace",
      "account_id": "[ACCOUNT ID]"
    }
  }
}
```

The `details` object echoes the name that was asked for and the account the request authenticated as. The `account_id` above is a placeholder.

---

## Pagination

The list response does not use the Azion API v4 collection envelope. Every other v4 collection carries `count`, `total_pages`, `page`, `page_size`, `next`, `previous`, and `results` at the top level. KV Store carries `results` beside a nested `pagination` object, so code written against another v4 collection reads fields that are not there.

| Field                     | What it carries                                                         |
| ------------------------- | ----------------------------------------------------------------------- |
| `results`                 | One namespace per entry, carrying the fields listed in Namespace fields |
| `pagination.page`         | The page this response carries                                          |
| `pagination.page_size`    | Namespaces per page                                                     |
| `pagination.total_count`  | Namespaces the account holds                                            |
| `pagination.total_pages`  | Pages the result divides into, at the current `page_size`               |
| `pagination.has_next`     | Whether a page follows this one                                         |
| `pagination.has_previous` | Whether a page precedes this one                                        |

There are no `next` and `previous` fields. `has_next` and `has_previous` are booleans rather than links, so a client that walks the list increments `page` itself.

| Query parameter | Effect                                                    |
| --------------- | --------------------------------------------------------- |
| `page`          | Return one page of the list                               |
| `page_size`     | Namespaces per page. Defaults to 50, and accepts 1 to 100 |

A `page_size` outside 1 to 100 returns `400` with `invalid_page_size`.

A `HEAD` request on the collection returns the same counts as headers: `x-total-count`, `x-page`, `x-page-size`, and `x-total-pages`.

The endpoint also accepts a `fields` parameter and ignores it. A request that sends `?fields=name` receives all three fields of every namespace. That is the same response a request without the parameter receives, so the response cannot be narrowed.

---

## The operations that do not exist

`OPTIONS` on the collection answers `allow: GET, POST, HEAD, OPTIONS`. `OPTIONS` on a namespace answers `allow: GET, HEAD, OPTIONS`. `PUT`, `PATCH`, and `DELETE` each answer `405` in the gateway envelope Errors describes.

There is no rename, no deactivation, no emptying, and no delete, in the Azion API v4 or in any other interface. That is what makes a namespace permanent.

There is no keys collection either. The paths that would carry one return the platform's HTML `Not Found` page: `/v4/workspace/kv/namespaces/{name}/keys`, and the same path ending in `/values`, `/items`, or `/entries`. A path the gateway routes returns a JSON error instead, so the HTML page is the tell that these paths do not exist. Keys are reached from a function. For the methods that reach them, refer to [KV Store API](/en/documentation/devtools/runtime/api-reference/kv-store/).

---

## Errors

Two error envelopes coexist on this endpoint, and a client that handles one of them misses the other. The platform gateway emits the Azion API v4 envelope for a `405`, with a numeric `code` and the text in `detail`. The KV service emits its own envelope for `400`, `404`, and `500`, with a snake\_case `code` and the text in `message`.

The gateway envelope:

```json
{
  "errors": [
    {
      "code": "10007",
      "title": "Method Not Allowed",
      "detail": "Method \"DELETE\" not allowed.",
      "status": "405",
      "source": {
        "pointer": "/data"
      },
      "meta": {
        "method": "DELETE"
      }
    }
  ]
}
```

The KV service envelope:

```json
{
  "state": "error",
  "error": {
    "code": "validation_error",
    "message": "Name must be at least 3 characters long",
    "details": {
      "field": "name"
    }
  }
}
```

| Status | `code`                | `message`                                                                | Cause                                                                                               |
| ------ | --------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| 400    | `validation_error`    | `Name must be at least 3 characters long`                                | The name is shorter than 3 characters                                                               |
| 400    | `validation_error`    | `Name must be no more than 63 characters long`                           | The name is longer than 63 characters                                                               |
| 400    | `validation_error`    | `Name is required`                                                       | The body carries no `name`, or `name` is an empty string                                            |
| 400    | `validation_error`    | `Name can only contain alphanumeric characters, hyphens and underscores` | The name carries a character outside `^[a-zA-Z0-9_-]+$`                                             |
| 400    | `validation_error`    | `Namespace already exists`                                               | The account already holds a namespace with that name                                                |
| 400    | `invalid_page_size`   | `Page size must be between 1 and 100`                                    | `page_size` is outside 1 to 100                                                                     |
| 404    | `namespace_not_found` | `Namespace not found`                                                    | The account holds no namespace with that name. `details` echoes `name` and `account_id`             |
| 405    | `10007`               | —                                                                        | A `PUT`, `PATCH`, or `DELETE` request. The gateway envelope carries `Method Not Allowed` in `title` |
| 500    | `internal_error`      | `Internal server error`                                                  | The body is not valid JSON, or `name` carries a type other than a string                            |

The `500` row records what the endpoint returns, and not a response to write code against. A body that is not valid JSON, and a `name` that is not a string, are both client mistakes. For the symptom and what to check, refer to [Troubleshooting](/en/documentation/platform/kv-store/troubleshooting/).

---

## Authentication

Every request carries a personal token in the `Authorization` header, under the `Token` scheme, and asks for JSON:

```http
Authorization: Token [TOKEN VALUE]
Accept: application/json
```

A request that carries a body also carries `Content-Type: application/json`.

---

## Limits

A namespace name runs 3 to 63 characters, and a list response returns at most 100 namespaces per page.

Every other bound on a namespace, what the platform does past each value, and the usage each plan includes are in [KV Store limits](/en/documentation/platform/kv-store/limits/).

---

## Related resources

- [KV Store API](/en/documentation/devtools/runtime/api-reference/kv-store.md): The methods a function calls against the keys inside a namespace.
- [How KV Store works](/en/documentation/platform/kv-store/how-it-works.md): Where a value is written, and where a read is served from.
- [KV Store limits](/en/documentation/platform/kv-store/limits.md): Every bound on this page in one table, with the usage each plan includes.
- [Best practices](/en/documentation/platform/kv-store/best-practices.md): The naming convention behind a name that cannot be changed.
- [Troubleshooting](/en/documentation/platform/kv-store/troubleshooting.md): What to do about the error a rejected request returns.
