- Slim README to essentials, link to docs/ for details - Add docs/openapi.yaml as single source of truth for the API - Add scripts/generate-api-docs.ts to produce docs/API.md from the spec - Add pnpm docs:api / make docs-api target Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.8 KiB
Crumbs API
REST API for Crumbs by Bretzel — a self-hostable, offline-first notes app.
Base URL: http://localhost:3000
All endpoints require a session cookie (set by login) except where noted.
Auth
POST /api/auth/setup
First-time password setup
Creates the single user account. Only works once — returns 400 if already set up.
No authentication required.
Request:
{
"password": "password"
}
Response: 201
{
"success": true
}
Errors: 400 Setup already completed or invalid password
POST /api/auth/login
Log in
No authentication required.
Request:
{
"password": "password"
}
Response: 200
{
"success": true
}
Errors: 401 Invalid password
POST /api/auth/logout
Log out
Response: 200
{
"success": true
}
Notes
GET /api/notes
List notes
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
filter |
query | string | no | (all, archived, trashed) — default: all |
Response: 200
[
{
"id": "uuid",
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"version": 1,
"tags": [
"item"
]
}
]
POST /api/notes
Create a note
Request:
{
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1
}
Response: 201
{
"id": "uuid",
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"version": 1,
"tags": [
"item"
]
}
GET /api/notes/{id}
Get a note
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes |
Response: 200
{
"id": "uuid",
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"version": 1,
"tags": [
"item"
]
}
Errors: 404 Note not found
PATCH /api/notes/{id}
Update a note
Partial update — only include changed fields.
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes |
Request:
{
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1
}
Response: 200
{
"id": "uuid",
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"version": 1,
"tags": [
"item"
]
}
Errors: 404 Note not found
DELETE /api/notes/{id}
Permanently delete a note
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes |
Response: 200
{
"success": true
}
Errors: 404 Note not found
Attachments
GET /api/notes/{id}/attachments
List or download attachments
Without attachmentId, lists all attachments. With attachmentId, returns the file.
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes | |
attachmentId |
query | string | no |
Response: 200
POST /api/notes/{id}/attachments
Upload an image attachment
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes |
Request: multipart/form-data with file field.
Response: 201
{
"id": "id",
"noteId": "noteId",
"filename": "filename",
"mimeType": "mimeType",
"size": 1,
"createdAt": "2025-01-01T00:00:00.000Z"
}
Errors: 400 Invalid file
DELETE /api/notes/{id}/attachments
Delete an attachment
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes | |
attachmentId |
query | string | yes |
Response: 200
{
"success": true
}
Search
GET /api/search
Full-text search
Searches across note titles, content, and tags. Excludes trashed notes.
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
q |
query | string | yes |
Response: 200
[
{
"id": "uuid",
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"version": 1,
"tags": [
"item"
]
}
]
Tags
GET /api/tags
List all tags
Response: 200
[
{
"id": 1,
"name": "name"
}
]
Sync
GET /api/sync
Pull changes since timestamp
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
since |
query | integer | yes | Unix timestamp in milliseconds |
Response: 200
[
{
"id": "uuid",
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"version": 1,
"tags": [
"item"
]
}
]
POST /api/sync
Push local changes
Request:
{
"changes": [
{
"noteId": "uuid",
"operation": "create",
"timestamp": 1,
"data": {
"title": "title",
"content": "content",
"color": "default",
"pinned": true,
"archived": true,
"trashed": true,
"checklistMode": true,
"sortOrder": 1
}
}
]
}
Response: 200
{
"success": true
}