kaimoku
Coming soon

Kuju Email is in private development. These API docs describes the platform as it will ship, so you can evaluate it before we open. Get notified at launch or read the overview.

Kuju Email API Reference

Complete REST API documentation for integrating with Kuju Email. All endpoints return JSON and accept JSON request bodies.

Overview

Base URL

Public API (JWT):http(s)://<host>:8080
Internal API:http(s)://<host>:2525

Authentication

Public endpoints require a JWT in the Authorization header:

Authorization: Bearer <token>

Admin endpoints require is_admin=true in the JWT claims. Domain admin endpoints require is_domain_admin=true or site admin privileges.

Public API

Auth

POST
/api/auth/login— Login and obtain JWT (or TOTP challenge)
POST
/api/auth/logout— Logout (no-op)JWT
POST
/api/auth/refresh— Refresh JWTJWT
POST
/api/invite— accept invite and set password (public, token-based)
POST
/api/forgot-password— request password reset email
POST
/api/reset-password— reset password with token

Two-Factor (TOTP)

GET
/api/auth/totp/status— check if TOTP is enabledJWT
POST
/api/auth/totp/setup— generate secret + QR codeJWT
POST
/api/auth/totp/confirm?session_id=...— verify code, enable TOTP, return backup codesJWT
POST
/api/auth/totp/verify— verify TOTP code during login, issue JWT
DELETE
/api/auth/totp— disable TOTP (requires current code)JWT

Folders

GET
/api/folders— List foldersJWT
POST
/api/folders— Create folderJWT
PUT
/api/folders/:id— Rename folderJWT
DELETE
/api/folders/:id— Delete folder (must be empty)JWT
GET
/api/folders/:id/messages— List messages in folderJWT

Messages

POST
/api/messages— compose / sendJWT
GET
/api/messages/:id— Get message metadataJWT
GET
/api/messages/:id/raw— raw RFC 822 sourceJWT
GET
/api/messages/:id/body— rendered bodyJWT
GET
/api/messages/:id/attachments/:aid— download attachmentJWT
PATCH
/api/messages/:id/flags— update flags (read, starred, etc.)JWT
PATCH
/api/messages/:id/move— Move message to folderJWT
PATCH
/api/messages/:id/copy— Copy message to folderJWT
DELETE
/api/messages/:id— Delete messageJWT
POST
/api/messages/search— advanced searchJWT
GET
/api/messages/search?q=...— quick searchJWT

Message Analysis

GET
/api/messages/:id/analysis— cached results + feature availability
GET
/api/messages/:id/analysis/instant— header analysis (auth, sender, hops, URLs)
POST
/api/messages/:id/analysis/ai— AI threat assessment (?force=true to re-analyze)
POST
/api/messages/:id/analysis/av-rescan— ClamAV attachment scan
POST
/api/messages/:id/analysis/url-safety— on-demand link-safety check

Attachment Knowledge

GET
/api/messages/:id/attachments/:aid/knowledge— cached extraction result
POST
/api/messages/:id/attachments/:aid/knowledge— extract text + AI summarize

Drafts

GET
/api/drafts— List draftsJWT
POST
/api/drafts— Create draftJWT
GET
/api/drafts/:id— Get draftJWT
PUT
/api/drafts/:id— Update draftJWT
DELETE
/api/drafts/:id— Delete draftJWT
POST
/api/drafts/:id/send— send a saved draftJWT

Calendars & Events

Calendars

GET
/api/calendars— list calendars
POST
/api/calendars— create calendar
PUT
/api/calendars/:id— update calendar
DELETE
/api/calendars/:id— delete calendar

Events

GET
/api/calendars/:calId/events?start=...&end=...— list events (optional RFC 3339 range filter)
GET
/api/calendars/:calId/events/:id— get event
POST
/api/calendars/:calId/events— create event
PUT
/api/calendars/:calId/events/:id— update event
DELETE
/api/calendars/:calId/events/:id— delete event

Address Books & Contacts

Address Books

GET
/api/address-books— list address books
POST
/api/address-books— create address book
PUT
/api/address-books/:id— update address book
DELETE
/api/address-books/:id— delete address book

Contacts

GET
/api/address-books/:abId/contacts?q=...— list contacts (optional search)
GET
/api/address-books/:abId/contacts/:id— get contact
POST
/api/address-books/:abId/contacts— create contact
PUT
/api/address-books/:abId/contacts/:id— update contact
DELETE
/api/address-books/:abId/contacts/:id— delete contact

CalDAV / CardDAV

Standard CalDAV and CardDAV endpoints are available for syncing calendars and contacts with third-party clients. Authentication uses HTTP Basic Auth with your email and password.

GET
/.well-known/caldav— redirects to /caldav/
GET
/.well-known/carddav— redirects to /carddav/
GET
/caldav/{accountId}/{calendarName}/— CalDAV endpoint
GET
/carddav/{accountId}/{addressBookName}/— CardDAV endpoint

Branding

GET
/api/branding— branding config for the authenticated user's domainJWT
GET
/api/branding/assets/:filename— branding asset file (logo, favicon, CSS)JWT

Account API

All account API endpoints require a valid JWT.

Preferences

PUT
/api/account/preferences— update account preferences (spam_folder, plus_tag_filing, etc.)

AI & Intelligence

GET
/api/messages/:id/thread-ai-state— get AI triage state for a thread
POST
/api/messages/:id/ai-reply— generate AI reply draft
POST
/api/messages/:id/rewrite-draft— rewrite compose draft with tone control
POST
/api/messages/:id/thread-document— generate document-centric thread analysis
POST
/api/analysis/natural-search— interpret natural language search query
POST
/api/analysis/backfill-body-search— backfill body search index

Thread Graph

GET
/api/messages/:id/thread-graph— get conversation graph (nodes + edges)

Vacation

GET
/api/vacation— get vacation responder settings
PUT
/api/vacation— update vacation responder (enabled, subject, body, start/end dates)

Waiting On Reply

GET
/api/waiting— list sent messages awaiting reply
PUT
/api/waiting/:id— update waiting status (resolved, snoozed)
POST
/api/waiting/:id/nudge— send follow-up nudge

Tasks

GET
/api/tasks— list tasks
POST
/api/tasks— create task
PUT
/api/tasks/:id— update task
DELETE
/api/tasks/:id— delete task
POST
/api/tasks/:id/to-calendar— convert task to calendar event

Activity Feed

GET
/api/feed?limit=...— merged chronological feed (messages, events, tasks)

Contact Intelligence

GET
/api/contacts/intelligence/top— top contacts by email frequency
GET
/api/contacts/intelligence/dormant— contacts with no recent communication
GET
/api/contacts/intelligence/:email— per-email communication stats
POST
/api/contacts/quick-add— quick-add sender to address book

Inbox Summary

GET
/api/inbox-summary— dashboard stats (volume, security, productivity, classifications)

Workspaces

GET
/api/workspaces— list workspaces with message counts
POST
/api/workspaces— create workspace
PUT
/api/workspaces/:id— update workspace (name, color, rules, etc.)
DELETE
/api/workspaces/:id— delete workspace (messages preserved)
GET
/api/workspaces/:id/messages?page=1&per_page=50— paginated messages
POST
/api/workspaces/:id/messages— assign message
DELETE
/api/workspaces/:id/messages/:messageId— remove message from workspace
GET
/api/messages/:id/workspaces— get workspaces a message belongs to

NL Commands

POST
/api/commands/interpret— AI interprets natural language command
POST
/api/commands/execute— execute a command plan (move, archive, delete, flag)

Domain Admin API

Requires a JWT with is_domain_admin or is_admin claims.

Accounts & Stats

GET
/api/domain-admin/stats
GET
/api/domain-admin/accounts
POST
/api/domain-admin/accounts— create account (see Account Creation below)
PUT
/api/domain-admin/accounts/:id
DELETE
/api/domain-admin/accounts/:id
POST
/api/domain-admin/accounts/:id/resend-invite— resend invite email (pending accounts only)
POST
/api/domain-admin/accounts/:id/recover— send password reset to recovery email
GET
/api/domain-admin/delivery-log
GET
/api/domain-admin/dns/check-records— verify DNS records for the admin's domain

Retention Policies

GET
/api/domain-admin/retention— get effective retention (domain + account policies)
PUT
/api/domain-admin/retention/domain— upsert retention for own domain
GET
/api/domain-admin/accounts/:id/retention— get account retention override
PUT
/api/domain-admin/accounts/:id/retention— upsert account retention override
DELETE
/api/domain-admin/accounts/:id/retention— remove account retention override

Account Creation

POST /api/domain-admin/accounts accepts a mode field:

  • "password" (default): Admin sets the password. Account is immediately active.
  • "invite": Requires invite_email (external address). Account starts as pending_invite. An invite email is sent; the recipient sets their own password.
// Invite mode example
POST /api/domain-admin/accounts
{
  "local_part": "alice",
  "mode": "invite",
  "invite_email": "alice@gmail.com",
  "display_name": "Alice",
  "quota_bytes": 1073741824
}

Site Admin API

Requires a JWT with is_admin=true.

Domains

GET
/api/admin/domains— List domainsJWT
POST
/api/admin/domains— Create domainJWT
PUT
/api/admin/domains/:id— Update domainJWT
DELETE
/api/admin/domains/:id— Deactivate domainJWT

Accounts

GET
/api/admin/accounts— List accountsJWT
POST
/api/admin/accounts— Create accountJWT
PUT
/api/admin/accounts/:id— update account; set is_admin to promote/demoteJWT
DELETE
/api/admin/accounts/:id— Deactivate accountJWT

Branding (Admin)

GET
/api/admin/branding/:domain— branding configJWT
GET
/api/admin/branding/:domain/files— list branding filesJWT
POST
/api/admin/branding/:domain/archive— upload tar.gz/zip archiveJWT
GET
/api/admin/branding/:domain/:filename— download/preview assetJWT
POST
/api/admin/branding/:domain/:filename— upload single assetJWT
DELETE
/api/admin/branding/:domain/:filename— delete assetJWT

System & Licensing

GET
/api/admin/stats— System statsJWT
GET
/api/admin/delivery-log— Delivery log entriesJWT
GET
/api/admin/license— License status and usageJWT
PUT
/api/admin/license— Install/update license keyJWT
GET
/api/admin/system-info— System info including module versionsJWT
GET
/api/admin/settings— system settings (key-value)JWT
PUT
/api/admin/settings/corporate-domain— update corporate domainJWT
PUT
/api/admin/settings/safe-browsing-key— save link-safety check API key
GET
/api/admin/dns/check-records?domain=...— verify DNS records (MX, SPF, DKIM, DMARC)JWT
GET
/api/admin/openapi.yaml— OpenAPI spec for the REST APIJWT

Delivery Thresholds

GET
/api/admin/domains/:domainId/thresholds— get spam score thresholds
PUT
/api/admin/domains/:domainId/thresholds— update junk/drop thresholds and quarantine expiry
GET
/api/admin/delivery/drops— hard drop statistics

Retention Policies

GET
/api/admin/domains/:domainId/retention— get domain retention policy
PUT
/api/admin/domains/:domainId/retention— upsert domain retention policy
DELETE
/api/admin/domains/:domainId/retention— remove domain retention policy

KumoMTA Proxy

Proxy endpoints for managing the embedded KumoMTA instance.

GET
/api/admin/kumomta/metrics— raw KumoMTA metrics (includes uptime, version)
GET
/api/admin/kumomta/{endpoint}— proxy GET (bounces, suspensions, ready-q-suspensions)
POST
/api/admin/kumomta/{endpoint}— create bounce/suspend rules
DELETE
/api/admin/kumomta/{endpoint}— delete bounce/suspend rules

Plugins

POST
/api/admin/plugins/{id}/enable-all— enable a plugin for all domains

Concepts

Account Status

StatusMeaning
activeNormal account — can login and receive mail
pending_inviteAwaiting invite acceptance — can receive mail but cannot login
inactiveDisabled — cannot login or receive mail

Pending accounts that are not activated within 14 days are automatically deleted by the cleanup worker.

Domain Fields

Domains support a catch_all_account_id field. When set, mail to unknown addresses at the domain is delivered to the designated account.

PUT /api/admin/domains/:id
{"catch_all_account_id": 5}     // enable catch-all → account 5
{"catch_all_account_id": null}  // disable catch-all

Plus Addressing

Mail sent to user+tag@domain delivers to user@domain. The tag is stored in messages.plus_tag for filtering. No configuration needed — always active.

Auto-filing: Users can enable plus_tag_filing in their preferences. When enabled, emails to user+tag@domain are automatically placed in a folder named after the tag (created if needed). Spam routing takes priority.

Branding Files

Per-domain branding lets you customize the webmail UI for each domain: logo, favicon, colors, app name, and custom CSS.

Allowed files:

branding.jsonlogo.svglogo.pngfavicon.icofavicon.svgcustom.css

Size limits:

  • Images: 512 KB
  • CSS / JSON: 64 KB
  • Archives: 2 MB

branding.json format:

{
  "app_name": "My Mail",
  "primary_color": "#667eea",
  "accent_color": "#764ba2"
}

Examples

Login:

curl -s -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@example.com","password":"secret"}'

List folders:

curl -s http://localhost:8080/api/folders \
  -H "Authorization: Bearer $TOKEN"

Compose and send:

curl -s -X POST http://localhost:8080/api/messages \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"from":"admin@example.com","to":["user@example.com"],"subject":"Hello","text":"Hi"}'

List admin domains:

curl -s http://localhost:8080/api/admin/domains \
  -H "Authorization: Bearer $ADMIN_TOKEN"