Skip to content

REST API

Swagger UI

Interactive docs exposed at /swagger or /api/v1/docs. Generated from backend/swagger.go.

Handlers

All routes defined in backend/routes.go and implemented under backend/handlers/.

Base URL: /api/v1. All mutating endpoints require a bearer JWT issued by POST /auth/login and a valid CSRF token.

POST /api/v1/auth/login
Content-Type: application/json
{
"email": "alice@example.com",
"password": "correct horse battery staple"
}
  • GET /notes → list decrypted note metadata (handler: handlers/notes.go:GetNotes)
  • POST /notes → create note; payload must include encrypted title/content strings
  • GET /notes/:id/versions → fetch version history, stored in note_versions
  • POST /notes/:id/versions/:version → restore a historic version
POST /api/v1/notes
Authorization: Bearer <jwt>
Content-Type: application/json
{
"workspace_id": "c76c0c3d-0c2d-4ac3-a71c-1b1837a8cb6d",
"title_encrypted": "BASE64...",
"content_encrypted": "BASE64...",
"content_hash": "BASE64..."
}

Tags

CRUD handlers in handlers/tags.go. Deterministic hashes stored in tags.name_hash.

Folders

Endpoints live in handlers/folders.go. Moving a note triggers a folder_id update with auditing.

Templates

Handled by handlers/templates.go. POST /templates/:id/use increments usage_count.

Example assign tag request:

POST /api/v1/notes/b9fa1ed4-9d03-4d56-94f1-8b2b50f5b9de/tags
{
"tag_id": "11c8a517-11e2-43dd-96df-49ca8e5d0080"
}
  • Collaborator management resides in handlers/collaboration.go.
  • Share links served by handlers/share_links.go with Redis caching.
POST /api/v1/notes/:id/share
{
"email": "teammate@example.com",
"permission": "write"
}

Attachments are stored encrypted in PostgreSQL (attachments.content_encrypted). Uploads stream via multipart/form-data.

POST /api/v1/notes/:noteId/attachments
Authorization: Bearer <jwt>
Content-Type: multipart/form-data
file=@contract.pdf
name=Encrypted title

Handler: handlers/attachments.go:UploadAttachment enforces size limits and updates users.storage_used.

  • POST /notes/import and POST /notes/bulk-import accept encrypted JSON exports produced by the frontend.
  • POST /notes/:id/export returns decrypted data for the caller.
  • POST /search queries the encrypted keyword index (see /architecture/database-schema).

All above implemented in handlers/import_export.go and handlers/search.go. Rate limiting tier: ImportExportLimiter or SearchLimiter.

  • GET /health/live → confirms process running
  • GET /health/ready → verifies database, Redis, and template/admin readiness
  • GET /health → returns service status plus user counts

Handlers live directly in backend/routes.go. These endpoints are unauthenticated and safe for platform probes.

Standard error envelope:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{ "error": "Too many requests. Please try again later." }
  • JSON validation errors include fields array from utils.ValidationError.
  • Authorization failures return 401 with "error": "Unauthorized".
  • CSRF violations surface as 403 with "error": "invalid csrf token".

middleware.JWTMiddleware and the global CORS middleware guard every route:

  • Allowed origins derived from config.AllowedOrigins (CORS_ORIGINS env).
  • AllowHeaders includes X-CSRF-Token.
  • CSRF middleware stores a cookie csrf_token; send it back as the X-CSRF-Token header on mutating requests.

Implementation references:

  • backend/routes.go → CORS + CSRF setup
  • frontend/src/services/SecureAPI.ts → automatically forwards JWT + CSRF headers

Auth

backend/handlers/auth.go, middleware/jwt.go, services/mfa.go

Notes

backend/handlers/notes.go, handlers/templates.go, handlers/attachments.go

Collaboration

handlers/collaboration.go, websocket/hub.go

Search & Export

handlers/search.go, handlers/import_export.go