# Documents: Scarleta API reference

Page: https://www.scarleta.ai/docs/reference/documents
Base URL: https://api.scarleta.ai. Authentication: `Authorization: Bearer $SCARLETA_API_KEY`.
Operations: 4.

## GET /v1/documents

Operation id: `list_documents`

**List documents**

Returns the latest version of each of your documents, newest first, with the full content. `meta.count` is the number of documents returned.

Access: API key required; free and paid accounts. Cost: no token cost.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | integer | no | Documents to return, from 1 to 100. Defaults to 50. A value outside the range, or one that is not a whole number, is refused with `invalid_limit`. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `[].id` | string | Identifier of the document. Every version of one document has the same id. |
| `[].created_at` | string | ISO 8601 timestamp of this version. |
| `[].title` | string | The document title. |
| `[].content` | string \| null | The document content; null when the version has none. |
| `[].kind` | "text" \| "code" \| "sheet" \| "image" \| "chart" | What the content is: `text`, `code`, `sheet`, `image` or `chart`. |

### Responses

200: Success

```json
{
  "data": [
    {
      "id": "5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38",
      "created_at": "2026-10-21T03:41:56.630Z",
      "title": "Mix notes",
      "content": "Kick is masking the bass below 80 Hz.",
      "kind": "text"
    }
  ],
  "meta": {
    "request_id": "4d18043e-5317-4d76-9c7f-b01c34db04b4",
    "count": 1
  }
}
```

400: `limit` is not a whole number in the allowed range.

```json
{
  "error": {
    "code": "invalid_limit",
    "message": "limit must be an integer between 1 and 100",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_limit"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`invalid_limit`](https://www.scarleta.ai/docs/errors#invalid_limit), [`list_failed`](https://www.scarleta.ai/docs/errors#list_failed), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
curl "https://api.scarleta.ai/v1/documents" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"
```

## POST /v1/documents

Operation id: `save_document`

**Create a document or save a new version**

Without `id`, creates a new document and returns its first version with `201`. With the `id` of one of your documents, appends a new version to it (the history is kept) and returns that version, also with `201`. A body that is not valid JSON is answered like a body with no title: `400 missing_title`. A chart whose content is an invented, flat heatmap is refused with `400 degenerate_heatmap`; fix the content to save it.

Access: API key required; free and paid accounts. Cost: no token cost.

### Request body

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Id of an existing document to add a version to. Leave it out to create a new document. Must be a UUID. |
| `title` | string | The title, at most 200 characters after leading and trailing spaces are removed. Required, and not blank. Allowed: 1 to 200 characters. |
| `content` | string \| null | The content, at most 1048576 characters. Leave it out or send null for none. |
| `kind` | "text" \| "code" \| "sheet" \| "image" \| "chart" | What the content is. Defaults to `text`. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Identifier of the document. Every version of one document has the same id. |
| `created_at` | string | ISO 8601 timestamp of this version. |
| `title` | string | The document title. |
| `content` | string \| null | The document content; null when the version has none. |
| `kind` | "text" \| "code" \| "sheet" \| "image" \| "chart" | What the content is: `text`, `code`, `sheet`, `image` or `chart`. |

### Responses

201: The version just saved.

```json
{
  "data": {
    "id": "5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38",
    "created_at": "2026-10-21T03:41:56.630Z",
    "title": "Mix notes",
    "content": "Kick is masking the bass below 80 Hz.",
    "kind": "text"
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: The title is missing or blank, or the body is not valid JSON (`missing_title`); the title is too long (`title_too_long`); `id` is not a UUID (`invalid_id`); `kind` is not one of the five kinds (`invalid_kind`); or a chart is a degenerate heatmap (`degenerate_heatmap`).

```json
{
  "error": {
    "code": "missing_title",
    "message": "title is required",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#missing_title"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

404: `id` names a document that is not yours or does not exist.

```json
{
  "error": {
    "code": "not_found",
    "message": "Document 5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38 not found",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#not_found"
  }
}
```

413: The content is over the size limit.

```json
{
  "error": {
    "code": "content_too_large",
    "message": "document content must not exceed 1048576 characters",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#content_too_large"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`content_too_large`](https://www.scarleta.ai/docs/errors#content_too_large), [`create_failed`](https://www.scarleta.ai/docs/errors#create_failed), [`degenerate_heatmap`](https://www.scarleta.ai/docs/errors#degenerate_heatmap), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_id`](https://www.scarleta.ai/docs/errors#invalid_id), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`invalid_kind`](https://www.scarleta.ai/docs/errors#invalid_kind), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`missing_title`](https://www.scarleta.ai/docs/errors#missing_title), [`not_found`](https://www.scarleta.ai/docs/errors#not_found), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`title_too_long`](https://www.scarleta.ai/docs/errors#title_too_long), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
curl -X POST "https://api.scarleta.ai/v1/documents" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Mix notes",
    "content": "Kick is masking the bass below 80 Hz.",
    "kind": "text"
  }'
```

## GET /v1/documents/{id}

Operation id: `get_document`

**Get a document**

Returns the latest version of one document. With `versions=true`, returns every version instead, oldest first, and `meta.count` is the number of versions.

Access: API key required; free and paid accounts. Cost: no token cost.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | The document id, for example `5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38`. Allowed: at least 1 character. |
| `versions` | query | string | no | Send `true` to get every version of the document, oldest first. Any other value returns only the latest version. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Identifier of the document. Every version of one document has the same id. |
| `created_at` | string | ISO 8601 timestamp of this version. |
| `title` | string | The document title. |
| `content` | string \| null | The document content; null when the version has none. |
| `kind` | "text" \| "code" \| "sheet" \| "image" \| "chart" | What the content is: `text`, `code`, `sheet`, `image` or `chart`. |
| `[].id` | string | Identifier of the document. Every version of one document has the same id. |
| `[].created_at` | string | ISO 8601 timestamp of this version. |
| `[].title` | string | The document title. |
| `[].content` | string \| null | The document content; null when the version has none. |
| `[].kind` | "text" \| "code" \| "sheet" \| "image" \| "chart" | What the content is: `text`, `code`, `sheet`, `image` or `chart`. |

### Responses

200: The latest version as an object, or with `versions=true` an array of versions (see the response fields: `data` is an object or an array).

```json
{
  "data": {
    "id": "5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38",
    "created_at": "2026-10-21T03:41:56.630Z",
    "title": "Mix notes",
    "content": "Kick is masking the bass below 80 Hz.",
    "kind": "text"
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: The id in the path is not a UUID.

```json
{
  "error": {
    "code": "invalid_id",
    "message": "id must be a valid UUID",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_id"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

404: No document with this id exists in your account (a document of another account is reported the same way).

```json
{
  "error": {
    "code": "not_found",
    "message": "Document 5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38 not found",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#not_found"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`get_failed`](https://www.scarleta.ai/docs/errors#get_failed), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_id`](https://www.scarleta.ai/docs/errors#invalid_id), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`not_found`](https://www.scarleta.ai/docs/errors#not_found), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
ID="YOUR_ID"
curl "https://api.scarleta.ai/v1/documents/$ID" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"
```

## DELETE /v1/documents/{id}

Operation id: `delete_document_versions`

**Delete the versions of a document saved after a time**

Removes every version of the document saved after the time in `after`, which restores the document to the version that was current at that time. This cannot be undone. `after` is required so a call can never wipe a whole history by accident; send `after=0` to remove every version, which deletes the document. The call answers `200` with `removed: 0` when nothing is newer, when the document is already gone, or when it is not yours.

Access: API key required; free and paid accounts. Cost: no token cost.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | The document id, for example `5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38`. Allowed: at least 1 character. |
| `after` | query | number | yes | A time in milliseconds since the Unix epoch. Versions saved after it are removed; the version saved at exactly this time stays. Use `Date.parse(created_at)` of the version you want to keep. Send a whole number of milliseconds (digits only): a blank, fractional, signed or exponent value is refused with `invalid_after`. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | The document id. |
| `removed` | integer | Versions removed. Allowed: -9007199254740991 to 9007199254740991. |

### Responses

200: Success

```json
{
  "data": {
    "id": "5c2f8a14-9d3b-4e07-a1c6-0b7d4e9f2a38",
    "removed": 1
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: `after` is missing (`missing_after`) or is not a whole number of milliseconds (`invalid_after`), or the id is not a UUID (`invalid_id`).

```json
{
  "error": {
    "code": "missing_after",
    "message": "after (epoch ms) query param is required",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#missing_after"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`delete_failed`](https://www.scarleta.ai/docs/errors#delete_failed), [`invalid_after`](https://www.scarleta.ai/docs/errors#invalid_after), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_id`](https://www.scarleta.ai/docs/errors#invalid_id), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`missing_after`](https://www.scarleta.ai/docs/errors#missing_after), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
ID="YOUR_ID"
curl -X DELETE "https://api.scarleta.ai/v1/documents/$ID" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"
```
