# Create a view

Source: https://docs.emelia.io/docs/inbox-api/create-view

Guide: [Inbox API](https://docs.emelia.io/docs/inbox-api.md)

`POST https://api.emelia.io/inbox/api/v1/views`

Saves a filter tree under a name, at the end of the sidebar. The tree is bounded like `?filters=` (5 levels, 50 conditions, 500 character values). Restricting a view to some mailboxes is only possible in the app. Supports `Idempotency-Key`.

## Authentication

Send your API key in the `Authorization` header: `Authorization: <your API key>`.

## Request body

Content type: `application/json`, required.

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Min length 1. |
| `icon` | string or null | no | An emoji or a numeric HTML entity; no markup. |
| `filters` | object | no | A filter tree, or `{}` for a view without filter. |

```json
{
  "name": "Hot leads",
  "icon": "🔥",
  "filters": {
    "id": "g1",
    "_and": [
      {
        "id": "c1",
        "label": "ai_label",
        "type": "contains",
        "value": "cmtgacme0000000000000002"
      },
      {
        "id": "c2",
        "label": "read_status",
        "type": "is_false",
        "value": ""
      }
    ]
  }
}
```

## Example request

**cURL**

```bash
curl -X POST "https://api.emelia.io/inbox/api/v1/views" \
  -H "Authorization: $EMELIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Hot leads",
  "icon": "🔥",
  "filters": {
    "id": "g1",
    "_and": [
      {
        "id": "c1",
        "label": "ai_label",
        "type": "contains",
        "value": "cmtgacme0000000000000002"
      },
      {
        "id": "c2",
        "label": "read_status",
        "type": "is_false",
        "value": ""
      }
    ]
  }
}'
```

**JavaScript**

```js
const response = await fetch('https://api.emelia.io/inbox/api/v1/views', {
  method: 'POST',
  headers: { Authorization: process.env.EMELIA_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "name": "Hot leads",
    "icon": "🔥",
    "filters": {
      "id": "g1",
      "_and": [
        {
          "id": "c1",
          "label": "ai_label",
          "type": "contains",
          "value": "cmtgacme0000000000000002"
        },
        {
          "id": "c2",
          "label": "read_status",
          "type": "is_false",
          "value": ""
        }
      ]
    }
  }),
});
console.log(await response.json());
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://api.emelia.io/inbox/api/v1/views",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
    json={
        "name": "Hot leads",
        "icon": "🔥",
        "filters": {
            "id": "g1",
            "_and": [
                {
                    "id": "c1",
                    "label": "ai_label",
                    "type": "contains",
                    "value": "cmtgacme0000000000000002"
                },
                {
                    "id": "c2",
                    "label": "read_status",
                    "type": "is_false",
                    "value": ""
                }
            ]
        }
    },
)
print(response.json())
```

## Responses

### 201: Created.

| Field | Type | Required | Description |
|---|---|---|---|
| `view` | object | yes |  |
| `view.id` | string | yes |  |
| `view.name` | string | yes |  |
| `view.icon` | string or null | yes | Emoji, possibly as an HTML numeric entity. |
| `view.filters` | object | yes | A filter tree, or `{}` for a view without filter. |
| `view.mailboxIds` | array of string | yes | Mailboxes the view is restricted to; empty means all. Read only. |
| `view.createdAt` | string (date-time) | yes |  |

```json
{
  "view": {
    "id": "cmvwacme0000000000000001",
    "name": "Hot leads",
    "icon": "🔥",
    "filters": {
      "id": "g1",
      "_and": [
        {
          "id": "c1",
          "label": "ai_label",
          "type": "contains",
          "value": "cmtgacme0000000000000002"
        },
        {
          "id": "c2",
          "label": "read_status",
          "type": "is_false",
          "value": ""
        }
      ]
    },
    "mailboxIds": [],
    "createdAt": "2026-10-01T11:00:00.000Z"
  }
}
```

### 400: `VALIDATION_FAILED`: invalid field, invalid filter tree or bound exceeded.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 401: Missing, malformed, unknown or disabled key. No `X-RateLimit-*` headers.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 403: `WORKSPACE_SUSPENDED`: the Emelia subscription has expired.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 409: `CONFLICT`: Idempotency-Key reused with a different request, or the original call is still in progress.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 413: `PAYLOAD_TOO_LARGE`: JSON body above 256 KB.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 429: `RATE_LIMIT_EXCEEDED`: per minute limit of the workspace (wait `Retry-After`). `QUOTA_EXCEEDED`: monthly quota exhausted until the 1st of next month UTC (in Emelia the plan cannot be upgraded).

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 500: `INTERNAL_ERROR`: unexpected failure. The message is generic in production.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```
