# Schema: /v2/schema

Source: https://capacms.com/docs/legacy/schema

Your project's models, fields and relations as JSON, and as ready-made TypeScript types, for code generation.

Two routes describe the content model of the project your key belongs to. `GET /v2/schema` returns every model, field and relation as JSON, with a checksum. `GET /v2/schema/types` returns the same models as TypeScript interfaces.

`capa-codegen` reads these routes when you run it with a legacy key. See [Codegen](https://capacms.com/docs/sdk/cli#codegen).

## Keys and hosts

Both routes take a legacy key (`pk_`, `sk_`, or an older key with no prefix) in `x-api-key`. Any permission reads them, `read` included. A `cap_` key is refused with `401 {"error":"Invalid API key"}`, as on every legacy route. See [Keys and scopes](https://capacms.com/docs/api/authentication#why-a-scoped-key-is-refused-on-the-legacy-surface).

Send them to `https://api.capacms.com`. They are not served through the CDN, unlike `/v2/api` and `/v3/api`.

| Status | Body                                               | When                                   |
| ------ | -------------------------------------------------- | -------------------------------------- |
| 401    | `{"error":"API key required"}`                     | no `x-api-key` header                  |
| 401    | `{"error":"Invalid API key"}`                      | an unknown, inactive or `cap_` key     |
| 402    | `{"success":false,"error":"…"}`                    | the project has no active subscription |
| 500    | `{"error":"Failed to fetch schema","message":"…"}` | something failed on our side           |

## `GET /v2/schema`

```bash
curl https://api.capacms.com/v2/schema -H "x-api-key: $CAPA_KEY"
```

```json
{
  "models": [
    {
      "id": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
      "namespace": "blog_post",
      "modelName": "Blog Post",
      "isSingleInstance": false,
      "allowDynamicFields": false,
      "category": { "id": "6a1d2c3b-4e5f-4a7b-8c9d-0e1f2a3b4c5d", "name": "Editorial" },
      "fields": [
        {
          "id": "41a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
          "namespace": "title",
          "name": "title",
          "type": "string",
          "arrayType": null,
          "required": true,
          "relationRef": null,
          "enumValues": null,
          "directEmbed": false,
          "sortOrder": 0
        },
        {
          "id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
          "namespace": "author",
          "name": "Author",
          "type": "relation",
          "arrayType": null,
          "required": false,
          "relationRef": "author",
          "enumValues": null,
          "directEmbed": false,
          "sortOrder": 1
        }
      ]
    }
  ],
  "relations": [
    { "fromModel": "blog_post", "fromField": "author", "toModel": "author", "type": "one" }
  ],
  "checksum": "3f6c1b4e2a714d0e",
  "generatedAt": "2026-10-01T14:02:11.004Z"
}
```

`models` holds every model of the project that is not deleted, sorted by `modelName`. Each model's `fields` are in their `sortOrder`.

`category` is `null` for a model with no category. `arrayType` is set only on an `array` field, `relationRef` only on a relation, and `enumValues` only on an enum with values.

`relations` lists every relation field once. `type` is `one` for a `relation` field and `many` for an `array` of relations. `toModel` is the target model's namespace, or `null` when the target no longer exists.

### The checksum

`checksum` is 16 hexadecimal characters, a hash of `models` and `relations`. It changes whenever anything in `models` or `relations` does. The same value is the response's `ETag`, so you can ask whether anything moved without downloading the schema again:

```bash
curl -i https://api.capacms.com/v2/schema \
  -H "x-api-key: $CAPA_KEY" \
  -H 'If-None-Match: "3f6c1b4e2a714d0e"'
# HTTP/1.1 304 Not Modified
```

The response is sent with `Cache-Control: private, max-age=60`. It is specific to your key's project, so no shared cache stores it.

## `GET /v2/schema/types`

```bash
curl https://api.capacms.com/v2/schema/types -H "x-api-key: $CAPA_KEY" -o capa-types.ts
```

The body is TypeScript, sent as `text/plain` with `Content-Disposition: attachment; filename="capa-types.ts"`. It starts with four shared interfaces, `CapaImage`, `CapaVideo`, `CapaFile` and `CapaInstance`, then one interface per model, named after its namespace in PascalCase:

```ts
export interface BlogPost {
  title: string;
  author?: Author;
  tags?: string[];
  views?: number;
}
```

A required field has no `?`. Field types map like this:

| Field type                                            | TypeScript                                                                  |
| ----------------------------------------------------- | --------------------------------------------------------------------------- |
| `string`, `markdown`, `html`, `code`, `color`, `date` | `string`                                                                    |
| `number`                                              | `number`                                                                    |
| `true_false`                                          | `boolean`                                                                   |
| `image`, `video`, `file`                              | `CapaImage`, `CapaVideo`, `CapaFile`                                        |
| `enum` with values                                    | a union of the values, such as `'draft' \| 'live'`                          |
| `relation`                                            | the target model's interface, or `unknown` when the target no longer exists |
| `array`                                               | the item type followed by `[]`                                              |
| anything else                                         | `unknown`                                                                   |

## Which to use

For new code on `/api/`, run `capa-codegen` with a `cap_` key instead. It writes the same interfaces from the key's GraphQL schema, with no project id. See [Codegen](https://capacms.com/docs/sdk/cli#codegen).
