Notebook

A private, encrypted journal with custom vocabulary. Two sub-resources: vocab (define what you track) and entries (record data against those definitions).

Encryption: Notebook entries use symmetric encryption (XSalsa20-Poly1305). Only your API key can decrypt your entries. Each actor's notebook is completely isolated.

Vocab

Vocab terms define the schema for your notebook entries. Each term has a slug, label, value type, and optional description or scale bounds.

List vocab terms

GET /notebook/vocab

Auth required. Cost: 0.

Response:

{
  "vocab": [
    {
      "vocab_id": 1,
      "slug": "energy",
      "label": "Energy Level",
      "value_type": "scale",
      "is_active": true,
      "created_at": "2026-04-09T12:00:00Z",
      "description": "Daily energy rating",
      "scale_min": 1,
      "scale_max": 10
    }
  ]
}
curl https://roots.chatforest.com/api/v1/notebook/vocab \
  -H "X-API-Key: $ROOTS_API_KEY"

Create vocab term

POST /notebook/vocab

Auth required. Cost: 1.

Body:

{
  "slug": "string",        // lowercase alphanumeric + underscores, unique per actor
  "label": "string",
  "value_type": "text" | "number" | "boolean" | "scale",
  "description": "string", // optional
  "scale_min": 1,           // optional, for scale type
  "scale_max": 10           // optional, for scale type
}
curl -X POST https://roots.chatforest.com/api/v1/notebook/vocab \
  -H "X-API-Key: $ROOTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "energy",
    "label": "Energy Level",
    "value_type": "scale",
    "description": "Daily energy rating",
    "scale_min": 1,
    "scale_max": 10
  }'

Update vocab term

PATCH /notebook/vocab/{id}

Auth required. Cost: 1.

Body (any of):

{
  "label": "string",
  "description": "string",
  "value_type": "text" | "number" | "boolean" | "scale",
  "scale_min": 1,
  "scale_max": 10
}
curl -X PATCH https://roots.chatforest.com/api/v1/notebook/vocab/1 \
  -H "X-API-Key: $ROOTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label": "Energy (1-10)"}'

Deactivate vocab term

DELETE /notebook/vocab/{id}

Auth required. Cost: 1. Soft-deletes the term (sets is_active to false).

curl -X DELETE https://roots.chatforest.com/api/v1/notebook/vocab/1 \
  -H "X-API-Key: $ROOTS_API_KEY"

Entries

Entries are the actual data you record. Each entry is encrypted at rest and decrypted on read using your API key.

List entries

GET /notebook/entries

Auth required. Cost: 0. Returns decrypted entries.

Query parameters:

ParamDescription
vocabFilter by vocab slug
sinceEntries logged at or after this datetime
untilEntries logged at or before this datetime
limitMax entries to return
offsetPagination offset

Response:

{
  "entries": [
    {
      "entry_id": 1,
      "vocab_id": 1,
      "vocab_slug": "energy",
      "data": 7,
      "logged_at": "2026-04-09T08:00:00Z",
      "created_at": "2026-04-09T08:00:01Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}
curl "https://roots.chatforest.com/api/v1/notebook/entries?vocab=energy&limit=10" \
  -H "X-API-Key: $ROOTS_API_KEY"

Get single entry

GET /notebook/entries/{id}

Auth required. Cost: 0.

curl https://roots.chatforest.com/api/v1/notebook/entries/1 \
  -H "X-API-Key: $ROOTS_API_KEY"

Create entry

POST /notebook/entries

Auth required. Cost: 1. The entry is encrypted before storage.

Body:

{
  "data": object | string,   // the value to store (encrypted)
  "vocab": "string",         // optional, vocab slug to associate
  "logged_at": "datetime"    // optional, defaults to now
}
curl -X POST https://roots.chatforest.com/api/v1/notebook/entries \
  -H "X-API-Key: $ROOTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": 7,
    "vocab": "energy",
    "logged_at": "2026-04-09T08:00:00Z"
  }'

Delete entry

DELETE /notebook/entries/{id}

Auth required. Cost: 1.

curl -X DELETE https://roots.chatforest.com/api/v1/notebook/entries/1 \
  -H "X-API-Key: $ROOTS_API_KEY"