Kendr.org

Pick the auth flow that matches your client.

Kendr supports several auth modes because the clients are different: browser pages, installed apps, server-side integrations, Kendr Desktop, and the CLI do not all authenticate the same way. This page covers the exact routes, request bodies, and token shapes accepted by https://kendr.org.

Cookies X-Kendr-Session API keys OAuth PKCE and device code

Auth matrix

Mode Header or state Best for
Browser session kendr_session cookie Browser-driven flows after /api/auth/otp/verify.
App session X-Kendr-Session Installed apps that authenticate directly with Kendr and immediately call customer endpoints.
API key Authorization: Bearer kndr_live_... or X-API-Key Server-to-server usage, background jobs, and long-lived backend integrations.
OAuth bearer Authorization: Bearer kndr_oat_... Kendr Desktop, CLI, or other native clients using PKCE or device code with the app scope.

Browser session auth

The browser endpoints separate sign-in from signup, send a six-digit code through AWS SES, and create the kendr_session cookie after verification. They are useful for portals, browser automation, and any flow that wants cookie-backed auth rather than manually managing X-Kendr-Session.

Request a login code

curl https://kendr.org/api/auth/otp/request \
	  -X POST \
	  -H "Content-Type: application/json" \
	  -d '{
	    "email": "user@example.com",
	    "purpose": "login"
	  }'

Request signup verification

curl https://kendr.org/api/auth/otp/request \
	  -X POST \
	  -H "Content-Type: application/json" \
	  -d '{
	    "email": "new@example.com",
	    "purpose": "signup"
	  }'

Verify login and store the cookie

curl https://kendr.org/api/auth/otp/verify \
	  -X POST \
	  -H "Content-Type: application/json" \
	  -c cookies.txt \
	  -d '{
	    "email": "user@example.com",
	    "code": "123456",
	    "purpose": "login"
	  }'

Verify and create the account

curl https://kendr.org/api/auth/otp/verify \
	  -X POST \
	  -H "Content-Type: application/json" \
	  -c cookies.txt \
	  -d '{
	    "email": "new@example.com",
	    "code": "123456",
	    "purpose": "signup",
	    "full_name": "Example User",
	    "terms_accepted": true,
	    "referral_code": "OPTIONAL"
	  }'

Inspect browser session state

curl https://kendr.org/api/auth/session \
  -b cookies.txt

Log out

curl https://kendr.org/api/auth/logout \
  -X POST \
  -b cookies.txt \
  -c cookies.txt
Payload rules

purpose=login requires an existing account. purpose=signup requires a new email plus full name and legal consent during verification. Omit purpose only for backward-compatible native clients that intentionally combine login and signup. Codes expire after 10 minutes.

App session auth

The app auth routes return a session token directly in the JSON response. That token is sent on later calls as X-Kendr-Session. Installed clients should prefer /api/app/auth/otp/request and /api/app/auth/otp/verify, or OAuth PKCE/device code. Password login remains available for existing clients.

Switch languages

Use the tabs to view the same login flow in Curl, JavaScript, Python, .NET, Java, or Go. The response shape stays the same across every client.

Authenticate and receive the session token

Post credentials and read session.token from the JSON response

curl https://kendr.org/api/app/auth/login \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "supersecret123"
  }'

Successful response

{
  "ok": true,
  "authenticated": true,
  "user": {
    "id": 12,
    "email": "user@example.com",
    "full_name": "Example User",
    "credit_balance": 250
  },
  "session": {
    "token": "SESSION_TOKEN",
    "header_name": "X-Kendr-Session",
    "expires_at": "2026-04-24T12:00:00Z"
  }
}

Inspect the app session

curl https://kendr.org/api/app/auth/session \
  -H "X-Kendr-Session: $KENDR_SESSION"

Log out the app session

curl https://kendr.org/api/app/auth/logout \
  -X POST \
  -H "X-Kendr-Session: $KENDR_SESSION"

Create, scope, use, and rotate API keys

A Kendr API key is the caller credential for backend services. It is different from the OpenAI, Anthropic, Bedrock, Gemini, or other upstream provider credential. Your code receives only the kndr_live_... value and calls Kendr model aliases; upstream secrets and provider model IDs remain behind the gateway.

Create a least-privilege key

curl https://kendr.org/api/me/api-keys \
  -X POST \
  -H "X-Kendr-Session: $KENDR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Production model service",
    "environment": "production",
    "scopes": ["models:read", "models:invoke", "usage:read"]
  }'

Use the returned key

export KENDR_API_KEY="kndr_live_..."

curl https://kendr.org/v1/models \
  -H "Authorization: Bearer $KENDR_API_KEY"

# X-API-Key is also accepted
curl https://kendr.org/v1/models \
  -H "X-API-Key: $KENDR_API_KEY"
ScopeAllows
models:readDiscover enabled Kendr model aliases and poll owned video analyses.
models:invokeCall Responses, Chat Completions, Messages, and video analysis creation.
connectors:readRead connector-backed resources where the endpoint supports API-key auth.
connectors:invokeExecute enabled unified query surfaces.
usage:readRead wallet and exact model usage summaries.
knowledge:readRead permitted knowledge resources.
knowledge:writeCreate or modify permitted knowledge resources.

List keys without revealing secrets

curl https://kendr.org/api/me/api-keys \
  -H "X-Kendr-Session: $KENDR_SESSION"

Revoke during rotation

curl https://kendr.org/api/me/api-keys/revoke \
  -X POST \
  -H "X-Kendr-Session: $KENDR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"api_key_id": 42}'
One-time secret

The create response returns raw_token once. Store it in a server-side secret manager or environment variable, create a replacement before rotation, and never embed it in browser JavaScript or a distributed desktop binary.

OAuth PKCE for desktop apps

Kendr’s first-party OAuth clients are seeded as kendr-desktop and kendr-cli. Native clients can use PKCE with GET /oauth/authorize and POST /oauth/token. Kendr Desktop opens the hosted login page, then returns through its native app callback after the browser login succeeds.

Parameter Needed for
response_type=code Required on /oauth/authorize.
client_id Use kendr-desktop or another allowed client.
redirect_uri Must match an allowed client redirect URI, including Kendr loopback or custom URI handlers.
code_challenge and code_challenge_method=S256 Required for PKCE.
scope Optional. Defaults to the client’s default scopes. Include offline_access when you need a refresh token.
https://kendr.org/oauth/authorize?response_type=code&client_id=kendr-desktop&redirect_uri=kendr%3A%2F%2Foauth%2Fcallback&scope=profile%20email%20app%20offline_access&code_challenge=YOUR_S256_CHALLENGE&code_challenge_method=S256&state=opaque-state
curl https://kendr.org/oauth/token \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=kendr-desktop" \
  -d "grant_type=authorization_code" \
  -d "code=$OAUTH_CODE" \
  -d "redirect_uri=kendr://oauth/callback" \
  -d "code_verifier=$CODE_VERIFIER"

OAuth device code for the CLI

Device code is the cleanest CLI flow because the terminal never asks the user for their password. The CLI starts the flow, the user approves it in the browser, and the client then exchanges the device code for an access token.

Start the flow

curl https://kendr.org/oauth/device/code \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=kendr-cli" \
  -d "scope=profile email app offline_access"

Response fields

{
  "device_code": "kndr_odc_...",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://kendr.org/oauth/device",
  "verification_uri_complete": "https://kendr.org/oauth/device?user_code=ABCD-EFGH",
  "expires_in": 900,
  "interval": 5,
  "scope": "profile email app offline_access"
}
curl https://kendr.org/oauth/token \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=kendr-cli" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "device_code=$DEVICE_CODE"
Polling behavior

Poll no faster than the returned interval. Kendr returns OAuth protocol errors such as authorization_pending, slow_down, or access_denied as appropriate.

OAuth metadata and user info

Discovery metadata

curl https://kendr.org/.well-known/oauth-authorization-server

User info

curl https://kendr.org/oauth/userinfo \
  -H "Authorization: Bearer $KENDR_OAUTH_ACCESS_TOKEN"
Scope behavior

profile exposes name and preferred username, email exposes the email address, and app allows customer endpoints such as dashboard, API keys, purchases, and query execution.

App telemetry endpoints

Kendr also exposes app-side endpoints for installations, activity, error reports, feedback, and active notifications. These endpoints accept JSON and can carry extra metadata beyond their primary fields.

Path Key fields Response
POST /api/app/installations installation_id, platform, app_version, channel, source status, install_id, total_installs, recorded_at
POST /api/app/activity installation_id, platform, app_version, source status, activity_date, identity_type, total_active, recorded_at
POST /api/app/errors Required message; optional install, version, platform, error name, error code, details, stack trace, severity, email status, error_id, created_at
POST /api/app/feedback Required message; optional install, version, platform, category, rating, email status, feedback_id, created_at
GET /api/app/notifications No body count and notifications
curl https://kendr.org/api/app/feedback \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "installation_id": "desktop-prod-001",
    "platform": "windows",
    "app_version": "0.2.0",
    "category": "feature_request",
    "rating": 5,
    "message": "Please add saved query presets."
  }'

SDK helpers

JavaScript helpers

import { KendrClient } from './sdk/javascript/index.js';

const client = new KendrClient({
  apiKey: process.env.KENDR_API_KEY,
  baseUrl: 'https://kendr.org'
});

const models = await client.listModels();
const answer = await client.response({
  model: 'kc-intelligent',
  input: 'Summarize this change.'
});

Python helpers

import os
from kendr import KendrClient

client = KendrClient(
    api_key=os.environ['KENDR_API_KEY'],
    base_url='https://kendr.org',
)

models = client.list_models()
answer = client.response({
    'model': 'kc-intelligent',
    'input': 'Summarize this change.',
})
User-bound clients

When the app is acting for a signed-in user, initialize the same clients with sessionToken/session_token or oauthAccessToken/oauth_access_token instead of an API key.