# Create an inbox filter

Source: https://docs.maylee.app/api-reference/inbox-filters/create-inbox-filter

`POST https://api.maylee.app/api/v1/filters`

Scope: `write`.

Hides matching emails from the main inbox without moving them: they stay in INBOX, are listed by `GET /emails?filtered=only`, and remain visible in any view whose criteria match them.

Addresses and domains are stored lowercase; a leading `@` on a domain is dropped. A `label` filter must reference a label of the workspace.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | A unique value per operation, such as a UUID. Replays the stored response for 24h. Reusing a key with a different body returns 409. 0 to 255 characters. |

## Request body

`application/json`, required.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | `sender`: exact address, case-insensitive. `domain`: sender domain such as `acme.com`. `subject`: text contained in the subject, case-insensitive. `label`: id of a label (manual or AI) carried by the email. One of: `sender`, `domain`, `subject`, `label`. |
| `value` | string | yes | Address (stored lowercase), domain (stored lowercase, a leading `@` is dropped), subject text, or label id, depending on `type`. 1 to 255 characters. |

## Example request

```bash
curl -X POST "https://api.maylee.app/api/v1/filters" \
  -H "Authorization: Bearer $MAYLEE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "type": "domain",
  "value": "newsletter.example.com"
}'
```

## Responses

### 201

Created.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `filter` | InboxFilter | yes | Hides matching emails from the main inbox without moving them. Evaluated when listing, so it applies to past emails too and is undone by deleting the filter. |
| `filter.createdAt` | string (date-time) | yes |  |
| `filter.id` | string | yes |  |
| `filter.label` | LabelRef or null | yes | The targeted label when `type` is `label`, null otherwise. |
| `filter.type` | string | yes | `sender`: exact address, case-insensitive. `domain`: sender domain such as `acme.com`. `subject`: text contained in the subject. `label`: id of a label (manual or AI) carried by the email. One of: `sender`, `domain`, `subject`, `label`. |
| `filter.updatedAt` | string (date-time) | yes |  |
| `filter.value` | string | yes |  |

```json
{
  "filter": {
    "createdAt": "2026-07-15T08:30:00.000Z",
    "id": "cmfl1a2b3c4d5e6f7g8h9i0j",
    "label": null,
    "type": "domain",
    "updatedAt": "2026-07-15T08:30:00.000Z",
    "value": "newsletter.example.com"
  }
}
```

### 400

Invalid payload.

### 401

Missing, malformed, revoked or expired API key.

### 403

Key lacks the required scope, or outbound sending is not enabled on it.

### 404

`LABEL_NOT_FOUND`: the label of a `label` filter is not in this workspace.

### 409

`DUPLICATE_FILTER`: a filter with this type and value already exists.

### 429

Per-minute rate limit (`RATE_LIMIT_EXCEEDED`) or monthly quota (`QUOTA_EXCEEDED`) exhausted.

Errors use the format `{ "code", "error", "details" }`: see [Errors](/errors.md).
