FAQ API Docs Products
Open-Source · Self-Hosted · AI-Powered

Jenn API Documentation

Jenn is an open-source, self-hosted AI message router. It captures messages from multiple sources (Telegram, Desktop CLI, API), processes them through an AI router with multi-provider fallback (Groq → OpenRouter → GigaChat), and routes the results to your knowledge bases (Notion, Obsidian). Your data stays on your machine.

info How it works

Messages flow through a simple pipeline: Input (Telegram/CLI/API) → Jenn Core (AI Router + Skills) → Output (Notion/Obsidian). The AI router determines intent and category, then executes the appropriate skill to save or process the data.

Jenn Console Dashboard

Quick Start

Get Jenn running in under 5 minutes.

1
Clone and install
git clone https://github.com/yourusername/jenn.git cd jenn npm install
2
Configure environment
cp .env.example .env # Edit .env with your API keys # GROQ_KEY, OPENROUTER_KEY, NOTION_API_KEY, JWT_SECRET
3
Run database migration and start
npx prisma migrate dev node index.js # → http://localhost:3000 # → Console: http://localhost:3000/console

Architecture

The data flow from input to output.

input Inputs
Telegram, CLI, API
terminal SDK
Bearer Token
psychology Jenn Core
AI Router + Skills
api REST API
/v1/*
database Storage
Notion, Obsidian
Jenn Pipeline View

Authentication

Public API uses Bearer tokens. Each input source gets its own UUID token.

Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000

Admin API uses JWT tokens (httpOnly cookie or Bearer header). Register via POST /v1/admin/register to get started.

Jenn Admin Login
GET /health

Server Health

No authentication required. Returns server status.

Request
curl http://localhost:3000/health
Response 200 OK
{ "status": "ok", "uptime": 123456, "version": "1.0.0" }
GET /v1/ping

Ping

Check that your token is valid and the input source is configured correctly.

Request
curl -H "Authorization: Bearer YOUR_TOKEN" \ http://localhost:3000/v1/ping
Response 200 OK
{ "status": "ok", "source": "tg_bot" }
POST /v1/message

Send Message

The core endpoint. Sends a message for AI processing and routing.

Request Body
Field Type Required Description
sourcestringyesSource name (must match token)
textstringyesMessage text (max 4096 chars)
user.idstringyesUser ID in source system
user.namestringnoDisplay name
metaobjectnoAny additional data
Example Request
curl -X POST http://localhost:3000/v1/message \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "source": "tg_bot", "text": "Meeting notes from today: discussed Q3 roadmap", "user": { "id": "123456789", "name": "Ivan" }, "meta": { "chat_id": -1001234567890 } }'
Response 201 Created
{ "status": "ok", "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "received_at": "2026-07-07T12:00:00Z", "result": { "success": true, "output": "notion", "destination": "Meeting Notes", "category": "work" } }

Admin Authentication

JWT-based auth via httpOnly cookie or Bearer header.

POST /v1/admin/register
// Request { "username": "admin", "password": "your_password" } // Response 201 { "status": "ok", "token": "eyJhbGciOi..." }
POST /v1/admin/login
// Same body as register { "username": "admin", "password": "your_password" } // Response 200 { "status": "ok", "token": "eyJhbGciOi..." }

Configuration

GET /v1/admin/config

Returns the full user configuration (inputs, outputs, skills, routing).

// Response 200 { "status": "ok", "config": { "inputs": ["tg_bot", "desktop"], "outputs": { "notion": { "api_key": "..." } }, "skills": ["save_entry"] } }
PUT /v1/admin/config
// Request — saves full config { "config": { ... } } // Response 200 { "status": "ok" }

Inputs

Manage input sources (Telegram Bot, Desktop CLI) and review custom marketplace requests from the console.

GET/v1/admin/inputs— List installed inputs
GET/v1/admin/inputs/library— Browse available inputs
POST/v1/admin/inputs/:name/install— Install input + create token
DELETE/v1/admin/inputs/:name— Uninstall input
GET/v1/admin/inputs/:name/config— Get input config
PUT/v1/admin/inputs/:name/config— Save input config
POST/v1/admin/inputs/:name/test— Test input connection
GET/v1/admin/marketplace-requests— List custom marketplace requests
POST/v1/admin/marketplace-requests— Submit GitHub repo, description, and docs link

Outputs

Manage output targets (Notion, Obsidian) and review custom marketplace requests from the console.

GET/v1/admin/outputs— List installed outputs
GET/v1/admin/outputs/library— Browse available outputs
POST/v1/admin/outputs/:name/install— Install output
DELETE/v1/admin/outputs/:name— Uninstall output
GET/v1/admin/outputs/:name/config— Get output config
POST/v1/admin/outputs/:name/test— Test output connection
POST/v1/admin/outputs/:name/destinations— List destinations
POST/v1/admin/outputs/:name/sync-destinations— Sync from external app
POST/v1/admin/outputs/:name/sync-schema— Sync Notion DB schema
GET/v1/admin/outputs/:name/functions— List output functions
GET/v1/admin/marketplace-requests— List custom marketplace requests
POST/v1/admin/marketplace-requests— Submit GitHub repo, description, and docs link

Skills

Manage skills (save_entry, custom skills) and create new ones from the pipeline skill hub.

GET/v1/admin/skills— List installed skills
GET/v1/admin/skills/library— Browse skill marketplace
POST/v1/admin/skills/:name/install— Install skill
DELETE/v1/admin/skills/:name— Uninstall skill
POST/v1/admin/skills/create— Create custom skill
POST/v1/admin/skills/:name/publish— Publish to marketplace
GET/v1/admin/skills/:name/config— Get skill config
POST/v1/admin/skills/:name/config— Save skill config
GET/v1/admin/capabilities— Aggregated capabilities

Logs & Messages

GET/v1/admin/messages?limit=50— Message history
POST/v1/admin/test-message— Send test message
GET/v1/admin/logs/recent— Recent log entries
GET/v1/admin/logs/stream— SSE real-time stream
SSE Stream Example
const es = new EventSource('/v1/admin/logs/stream?token=YOUR_JWT'); es.onmessage = (e) => { const log = JSON.parse(e.data); console.log(log.time, log.level, log.msg); };

Rate Limits

Limit Value
Messages per minute60
Max text length4096 chars
Max request body64 KB

Exceeding limits returns 429 Too Many Requests with a Retry-After header.

Error Codes

Error HTTP Description
invalid_token401Token not found or expired
missing_fields400Required fields missing
source_mismatch403Token belongs to different source
text_too_long413Text exceeds 4096 characters
rate_limited429Too many requests
Error Response Format
{ "error": "invalid_token", "message": "Token not found or expired" }