---
name: pensieve
description: Gerencia as notas e listas do Pensieve de uma pessoa pela API REST — criar, buscar, editar, favoritar, mover entre listas, excluir e agendar lembretes (únicos ou recorrentes: todo dia, dias úteis, semanal, mensal, anual). Use quando a pessoa pedir para anotar algo, lembrar de algo numa data/hora ou com frequência, adiar um lembrete, ou organizar/consultar suas notas e listas no Pensieve.
---

# Pensieve API

O Pensieve guarda **notas** de uma pessoa. Cada nota é:

- **texto livre, sem título** (`content`, até 10.000 caracteres; espaços nas pontas são removidos);
- opcionalmente numa **lista** (`listId`) — uma categoria com nome e cor;
- opcionalmente **favorita** (`isFavorite`) — favoritas aparecem sempre primeiro;
- opcionalmente com um **lembrete** (`remindAt`) — a pessoa recebe um aviso nessa data/hora, que pode **repetir** (`repeat`).

## Conexão

- **Base URL:** `https://www.pensieve.com.br/api/v1` — todos os caminhos abaixo são relativos a ela.
- **Autenticação:** `Authorization: Bearer $PENSIEVE_API_KEY` em toda requisição (também aceita `X-API-Key: $PENSIEVE_API_KEY`).
  A chave começa com `pk_`, é gerada pela pessoa em *Minha conta › API* e dá acesso total às notas e listas da conta.
  **Nunca mostre, repita ou registre a chave** nas respostas.
- **Formato:** JSON (`Content-Type: application/json`), corpo de até 100 KB. CORS liberado para qualquer origem.
- **Limite:** 120 requisições por minuto por chave. As respostas trazem os cabeçalhos `RateLimit` / `RateLimit-Policy`.
- **Especificação completa (OpenAPI 3.1):** https://www.pensieve.com.br/api/v1/openapi.json · documentação interativa: https://www.pensieve.com.br/api/v1/docs/

Antes da primeira operação numa conversa, `GET /me` confirma que a chave funciona e de quem é a conta.

## Endpoints

| Ação | Requisição | Resposta |
| --- | --- | --- |
| Dono da chave | `GET /me` | `200 { user: { id, name, email } }` |
| Listar notas | `GET /notes?filter=&listId=&q=&limit=&offset=` | `200 { notes: [Note], total?, limit?, offset? }` |
| Contagens | `GET /notes/counts` | `200 { counts: { all, favorites, alerts, noList } }` |
| Ver nota | `GET /notes/{id}` | `200 { note: Note }` |
| Criar nota | `POST /notes` `{ content, listId?, isFavorite?, remindAt?, repeat?, timeZone? }` | `201 { note: Note }` |
| Editar nota | `PATCH /notes/{id}` (só os campos que mudam) | `200 { note: Note }` |
| Adiar lembrete | `POST /notes/{id}/snooze` `{ minutes? }` | `200 { note: Note }` |
| Excluir nota | `DELETE /notes/{id}` | `204` (sem corpo) |
| Listar listas | `GET /lists` | `200 { lists: [List] }` |
| Ver lista | `GET /lists/{id}` | `200 { list: List }` |
| Criar lista | `POST /lists` `{ name, color }` | `201 { list: List }` |
| Editar lista | `PATCH /lists/{id}` `{ name?, color? }` | `200 { list: List }` |
| Excluir lista | `DELETE /lists/{id}` | `204` (sem corpo) |

Formatos devolvidos:

```json
{ "id": 42, "content": "Verificar os backups", "listId": 3, "isFavorite": false,
  "remindAt": "2026-09-28T12:00:00.000Z", "repeat": { "freq": "weekly", "interval": 1, "days": [1, 4] },
  "createdAt": "2026-09-24T13:10:00.000Z", "updatedAt": "2026-09-24T13:10:00.000Z" }
```

```json
{ "id": 3, "name": "Infra", "color": "#3B6EA8", "noteCount": 12, "createdAt": "2026-09-01T10:00:00.000Z" }
```

## Buscar e listar notas

- `filter`: `all` (padrão) · `favorites` · `alerts` (com lembrete, inclusive já vencidos) · `nolist` (sem lista).
- `listId`: só as notas daquela lista. `q`: trecho do texto (até 200 caracteres; `%` e `_` são literais).
- Os filtros se **combinam** (E lógico): `?filter=favorites&listId=3&q=backup`.
- Ordem: favoritas primeiro, depois as mais recentes. Com `filter=alerts`, favoritas primeiro e depois pela data do lembrete (mais próxima primeiro).
- **Paginação:** sem `limit` vêm todas as notas do filtro. Com `limit` (1–500) e `offset`, a resposta traz também `total`.
  Em contas grandes, prefira `limit=50` e pagine só se precisar.
- A busca é por trecho, não semântica: se não achar, tente palavras mais curtas ou sinônimos antes de dizer que a nota não existe.

## Datas e fusos

- Envie datas em **ISO 8601 com fuso**: `2026-09-28T09:00:00-03:00` ou `2026-09-28T12:00:00Z`.
  **Sem fuso é recusado** (422 `Data/hora inválida.`).
- As respostas vêm sempre em **UTC** (`...Z`). Converta para o fuso da pessoa ao mostrar ("segunda, 28/09 às 09:00").
- Quando a pessoa fala em horário relativo ("amanhã às 9", "daqui a 2 horas", "toda segunda"), calcule a data a partir da data/hora
  atual **no fuso dela**. Se não souber o fuso, use `America/Sao_Paulo` (UTC−03:00), que é o padrão do Pensieve.
- Hora sem minuto → `:00`. Dia sem hora → pergunte, ou use 09:00 e diga que usou.

## Lembretes

### Lembrete único

Envie só `remindAt`. Se a data já passou, a nota é salva normalmente mas **não gera aviso** — avise a pessoa.

### Lembrete recorrente

Envie `remindAt` (o primeiro aviso) + `repeat` + `timeZone` (IANA, ex.: `America/Sao_Paulo`). `repeat` sem `remindAt` dá 422.

| `repeat` | Significado |
| --- | --- |
| `{ "freq": "daily" }` | todo dia |
| `{ "freq": "daily", "interval": 15 }` | a cada 15 dias |
| `{ "freq": "weekdays" }` | segunda a sexta (`interval` é ignorado) |
| `{ "freq": "weekly", "days": [1, 4] }` | toda segunda e quinta |
| `{ "freq": "weekly", "interval": 2, "days": [5] }` | sexta sim, sexta não |
| `{ "freq": "monthly" }` | todo mês, no mesmo dia do `remindAt` |
| `{ "freq": "monthly", "interval": 3 }` | a cada 3 meses |
| `{ "freq": "yearly" }` | todo ano, na mesma data do `remindAt` |

Como a série é montada a partir do `remindAt`:

- **Horário:** o do `remindAt` no `timeZone` — e ele se mantém mesmo com horário de verão.
- **Dias da semana** (`days`, só em `weekly`): 0 = domingo, 1 = segunda … 6 = sábado. Sem `days`, vale o dia da semana do `remindAt`.
- **Dia do mês/ano** (`monthly`/`yearly`): o do `remindAt`. Em meses mais curtos cai no último dia (31 → 30/28) e volta ao 31 no mês seguinte.
- Se o `remindAt` cai num dia fora da regra (ex.: semanal seg/qui e o `remindAt` numa quarta), o primeiro aviso vai para o próximo dia válido.
- Se o `remindAt` já passou, o primeiro aviso é a próxima ocorrência futura.
- `interval`: 1 a 99 (padrão 1).
- `timeZone` inválido ou ausente vira `America/Sao_Paulo` sem erro — envie sempre o fuso certo.
- Depois de cada aviso, `remindAt` avança sozinho para a próxima ocorrência. **Confira o `remindAt` devolvido** para confirmar à pessoa quando será o primeiro aviso.

### Editar e remover lembretes (PATCH)

- `remindAt: null` remove o lembrete **e** a repetição.
- `repeat: null` para de repetir (mantém um aviso único no `remindAt` atual).
- Mudar só `repeat` recalcula a série a partir do `remindAt` atual.
- A série só é recalculada quando `remindAt` (no minuto) ou `repeat` mudam. Para trocar o fuso, envie `timeZone` junto com `remindAt`/`repeat`.

### Adiar

`POST /notes/{id}/snooze` `{ "minutes": 30 }` (1 a 1440, padrão 10) reagenda o aviso para daqui a N minutos, contando de agora.
Numa nota recorrente, depois do aviso adiado a série continua no horário normal da regra.

## Listas

- Para usar uma lista pelo nome, busque em `GET /lists` (ordem alfabética, com `noteCount`) e compare sem diferenciar maiúsculas.
  **Se não existir, pergunte antes de criar.**
- `name`: 1 a 80 caracteres, **único na conta** (409 se repetir). `color`: hexadecimal `#RRGGBB` (volta em maiúsculas).
  Sem preferência da pessoa, escolha uma cor sóbria (ex.: `#3B6EA8`, `#2F7D5B`, `#9A2427`, `#8A6D1F`, `#6B4C9A`).
- Excluir uma lista **não apaga as notas**: elas ficam "Sem lista" (`listId: null`).
- `listId` de outra conta ou inexistente, ao criar/editar nota → 422 com `fields.listId`.

## Fluxos recomendados

- **"Anota X"** → `POST /notes { content }`. Guarde o texto como a pessoa disse (sem inventar título); se ela citar uma lista, resolva o `listId` antes.
- **"Me lembra de X amanhã às 9"** → `POST /notes { content, remindAt, timeZone }` e confirme a data/hora no fuso dela.
- **"Toda segunda me lembra de X"** → `repeat: { freq: "weekly", days: [1] }` com `remindAt` na próxima segunda no horário pedido.
- **Editar / concluir / excluir uma nota** → primeiro `GET /notes?q=trecho`. Se vier mais de uma, mostre as opções e pergunte qual.
  Nunca adivinhe o `id`.
- **Excluir** (nota ou lista) → **confirme com a pessoa antes**, citando o texto da nota ou o nome da lista. Exclusão é definitiva.
- **"O que tenho pra hoje / essa semana?"** → `GET /notes?filter=alerts` e filtre pelo `remindAt` no período, no fuso da pessoa.
- **Resumo da conta** → `GET /notes/counts` + `GET /lists`.
- Ao mostrar notas, traga o texto, a lista pelo nome (não pelo id), ⭐ se favorita e o próximo lembrete no fuso local.

## Erros

Formato: `{ "error": { "message": "...", "fields": { "campo": "problema" }, "code": "..." } }` — `fields` e `code` só quando houver.

| Status | Quando | O que fazer |
| --- | --- | --- |
| 400 | JSON malformado | Corrija o corpo. |
| 401 | `API_KEY_MISSING` (sem chave) · `API_KEY_INVALID` (inválida ou revogada) | Peça à pessoa uma chave nova em *Minha conta › API*. Não tente de novo. |
| 404 | Nota/lista não existe ou é de outra conta; rota inexistente | Busque de novo (`GET /notes?q=`); o item pode ter sido excluído. |
| 409 | Nome de lista repetido | Use a lista existente ou peça outro nome. |
| 422 | Dados inválidos — veja `fields` | Corrija o campo indicado. Não repita a mesma requisição. |
| 429 | `RATE_LIMITED` (120/min) | Espere o tempo do cabeçalho `RateLimit` (ou ~60 s) e tente de novo. |

## Exemplos

Criar uma tarefa recorrente (toda segunda e quinta às 9h, horário de Brasília):

```bash
curl -X POST https://www.pensieve.com.br/api/v1/notes \
  -H "Authorization: Bearer $PENSIEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Verificar os backups dos servidores",
    "remindAt": "2026-09-28T09:00:00-03:00",
    "repeat": { "freq": "weekly", "days": [1, 4] },
    "timeZone": "America/Sao_Paulo"
  }'
```

Pagar o aluguel todo dia 5, às 10h:

```bash
curl -X POST https://www.pensieve.com.br/api/v1/notes \
  -H "Authorization: Bearer $PENSIEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Pagar o aluguel", "remindAt": "2026-10-05T10:00:00-03:00",
        "repeat": { "freq": "monthly" }, "timeZone": "America/Sao_Paulo" }'
```

Buscar uma nota pelo texto (primeira página):

```bash
curl "https://www.pensieve.com.br/api/v1/notes?q=backup&limit=20" -H "Authorization: Bearer $PENSIEVE_API_KEY"
```

Notas com lembrete:

```bash
curl "https://www.pensieve.com.br/api/v1/notes?filter=alerts" -H "Authorization: Bearer $PENSIEVE_API_KEY"
```

Favoritar e mover para uma lista:

```bash
curl -X PATCH https://www.pensieve.com.br/api/v1/notes/42 \
  -H "Authorization: Bearer $PENSIEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "isFavorite": true, "listId": 3 }'
```

Parar de repetir, mantendo o próximo aviso:

```bash
curl -X PATCH https://www.pensieve.com.br/api/v1/notes/42 \
  -H "Authorization: Bearer $PENSIEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "repeat": null }'
```

Adiar o lembrete em 1 hora:

```bash
curl -X POST https://www.pensieve.com.br/api/v1/notes/42/snooze \
  -H "Authorization: Bearer $PENSIEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "minutes": 60 }'
```

Criar uma lista:

```bash
curl -X POST https://www.pensieve.com.br/api/v1/lists \
  -H "Authorization: Bearer $PENSIEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Infra", "color": "#3B6EA8" }'
```
