# Filters

A saved filter is a name and a set of criteria. The criteria are the same grammar on both surfaces: MCP takes an object, and `POST /v1/filters` takes **that same JSON serialised to a string** in `criteria`, up to 10,000 characters.

## The grammar

```json
{
  "v": 1,
  "all": [
    { "kind": "tag", "name": "home" },
    { "kind": "priority", "min": "medium" },
    { "kind": "deadline", "withinDays": 7 }
  ]
}
```

`v` is `1`. `all` is non-empty and AND-composed: a to-do matches when it satisfies every criterion.

A criterion is one of:

| form | matches |
|---|---|
| `{"kind":"tag","name":"<tag name>"}` | the to-do carries that tag |
| `{"kind":"priority","min":"low"\|"medium"\|"high"}` | priority greater than or equal to `min` |
| `{"kind":"deadline","withinDays":0..365}` | deadline on or before today plus N, overdue included |
| `{"kind":"deadline","overdue":true}` | deadline already passed |
| `{"kind":"scheduled","state":"dated"\|"anytime"\|"someday"}` | how the to-do is scheduled |
| `{"kind":"where","containerId":"<id>"}` | that id is anywhere in the to-do’s ancestor chain |

Done to-dos never match. The universe is open plus someday to-dos; history belongs to the logbook.

## Creating one over REST

```bash
curl -s https://api.inittasks.com/v1/filters \
  -X POST \
  -H "Authorization: Bearer $INITTASKS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Due at home","criteria":"{\"v\":1,\"all\":[{\"kind\":\"tag\",\"name\":\"home\"},{\"kind\":\"deadline\",\"withinDays\":7}]}"}'
```

Note the criteria are a **string**, so the inner JSON is escaped.

## The API stores criteria verbatim

> ⚠ Today `POST /v1/filters` checks only that `criteria` is a string of 1 to 10,000 characters. It does not parse the grammar. A malformed rule is accepted, answers `201`, and produces an **inert** filter: it matches nothing and the apps show it with a muted note. The MCP tool does parse, and refuses. So validate the JSON yourself before you send it, and read the filter back to confirm it matches what you expect.

Reading it back is one call:

```bash
curl -s "https://api.inittasks.com/v1/filters/$ID/todos" \
  -H "Authorization: Bearer $INITTASKS_TOKEN"
```

An inert filter returns an empty list rather than an error, which is exactly why the check is worth making.

## Next

- [Reference for /filters](/reference/filters)
- [REST and MCP](/rest-and-mcp)
