Developers

Diogenes API

Base URL https://api.diogenes.to/v1 · updated 25 September 2026

An OpenAI-compatible API over the same models, JAR Knowledge and billing as the Diogenes app. Only the request format is OpenAI's; nothing is sent to OpenAI.

Quick start

Create a key in Settings → API on diogenes.to. It is shown once; keep it in an environment variable.

curl
export DIOGENES_API_KEY="dgn_..."

curl https://api.diogenes.to/v1/chat/completions \
  -H "Authorization: Bearer $DIOGENES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "Hello"}]}'

The reply comes back in OpenAI's chat.completion shape with one addition, conversation_id. Every request is stored as a chat in your workspace, so it shows in the sidebar and follows your retention, export and delete settings.

Authentication

Send the key as a bearer token: Authorization: Bearer dgn_…. Diogenes stores only a hash of it.

  • A key acts as you: the same models, included usage, credits and spending limit as the app.
  • A key reaches all your JARs and personal chats unless you limit it. In Settings → API choose Limit this key to name the JARs it may use and whether it may use personal chats. A request outside that answers 403 forbidden.
  • Up to 10 active keys. Revoking one stops it at once.
  • Keys are for servers and scripts. The API sends no CORS headers; never put a key in a web page.

Models

GET /v1/models lists the models you can use, their price, and where your prompts are processed.

curl
curl https://api.diogenes.to/v1/models \
  -H "Authorization: Bearer $DIOGENES_API_KEY"
FieldMeaning
idThe value to send as model.
display_nameThe name the app shows.
tierincluded: covered by your plan's included usage. credits: paid per token in credits.
profilefast answers quickly; deep is the large reasoning class; null when not set.
context_windowTokens the model reads in one request.
toolsWhether the model can read links, look things up on-chain and draw pictures when those are on.
visionWhether the model reads images in the app. The API itself takes text only.
credits_per_1m_in, credits_per_1m_outCredits per million input and output tokens on credits models; null on included models.
privacy_routeprivate: Diogenes-controlled infrastructure. confidential: inside an attested TEE (NEAR AI). external: another provider, reached through DigitalOcean.
confidentialFor confidential models: provider, upstream_model, attestation (verified, pending, failed or stale) and verified_at. Otherwise null.
external_providerFor external models, the provider's name. Otherwise null.

The list also carries image_generation: the picture model and its price per image, or null while pictures are off.

Chat completions

POST /v1/chat/completions takes OpenAI's request body, plus three Diogenes fields.

FieldNotes
modelOptional. A model id from /v1/models. Defaults to the app's default model, or to the conversation's model when you continue one.
messagesRequired. 1–200 messages with role system, user or assistant; content is a string or text parts. The last message must be from the user. Up to 200,000 characters in total.
streamtrue for server-sent events. See Streaming.
conversation_idDiogenes. Continue a stored conversation: only your last user message is added. model must match it or be left out.
jar_idDiogenes. Start the conversation inside a JAR, so replies use its Knowledge. See JAR Knowledge.
image_consentDiogenes. Allows this request to draw a picture at the listed price. Without it no picture is drawn or charged.
  • system messages are not sent to the model: the Diogenes system prompt applies, as in the app.
  • On a new conversation, your earlier user and assistant messages become its stored history.
  • Text only: images and files are not accepted over the API.
  • Browsing and the sign-in view need the app and are not offered. Link reading, on-chain lookups and pictures follow the same switches as in the app.
Response
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "created": 1790330000,
  "model": "qwen3.5-397b-a17b",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Hello! …" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 812, "completion_tokens": 64, "total_tokens": 876 },
  "conversation_id": "…"
}

The headers X-Conversation-Id and X-Model-Id carry the same values. The body is written after the reply is stored, so conversation_id always names a conversation that already holds it.

Continue a conversation
curl https://api.diogenes.to/v1/chat/completions \
  -H "Authorization: Bearer $DIOGENES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"conversation_id": "CONVERSATION_ID",
       "messages": [{"role": "user", "content": "And the week before?"}]}'

Streaming

With "stream": true the reply arrives as chat.completion.chunk events: first the role, then text deltas, then a closing chunk with finish_reason and usage, and finally data: [DONE].

Server-sent events
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}],…}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}],…}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":812,"completion_tokens":64,"total_tokens":876},…}

data: [DONE]

finish_reason is stop, cancelled when the connection closed, or error. On error the closing chunk also carries error with a code and message.

JAR Knowledge

Pass jar_id to start a conversation inside a JAR you belong to. Replies draw on its Knowledge exactly as a JAR chat does in the app. GET /v1/jars lists the JARs this key can use, with id, name and your role; personal_chats says whether it may also chat outside a JAR.

curl
curl https://api.diogenes.to/v1/jars \
  -H "Authorization: Bearer $DIOGENES_API_KEY"

curl https://api.diogenes.to/v1/chat/completions \
  -H "Authorization: Bearer $DIOGENES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jar_id": "JAR_ID",
       "messages": [{"role": "user", "content": "What changed since last week?"}]}'
  • Membership is checked on every reply. Leaving a JAR ends the key's access to it.
  • A JAR's owner may keep external models out of it: 403 external_unavailable_in_jar.

Billing

Requests are billed exactly like messages in the app. See Models & Credits for the prices.

  • included models run on your plan's included usage first; past it, a reply continues on credits only where the app would allow it.
  • credits models cost credits_per_1m_in and credits_per_1m_out per million tokens.
  • Your monthly spending limit applies to API requests too.
  • usage in every response shows the tokens counted.
  • When the app would first ask you to choose (a pay-as-you-go price, an external provider, a plan), the API answers with the matching error instead. Make the choice once in the app, then retry.

Errors

Errors share one shape and the app's codes:

Error
{ "error": { "code": "forbidden", "message": "This key cannot reach that JAR." } }
StatusCodeMeaning
400validationThe request is malformed; the message says what to fix.
400model_unavailableThat model is not offered.
401unauthorizedThe key is missing, malformed, unknown or revoked.
402payment_required, spend_limit_reachedNot enough credits, or your spending limit is reached.
403forbiddenThe key does not reach that JAR, or personal chats.
403external_unavailable_in_jarExternal models are off in this JAR.
404not_foundNo such conversation or JAR for you.
409payg_consent_required, external_consent_requiredConfirm the price or the provider in the app first.
429allowance_reachedYour included usage for the period is used up.
429rate_limitedToo many messages at once; retry after the Retry-After header.

Limits

  • The app's per-minute message limit, shared between the app and your keys.
  • Up to 200 messages and 200,000 characters per request; request bodies up to 1 MB.
  • Up to 10 active keys; a limited key names up to 20 JARs.

Examples

Python · openai
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.diogenes.to/v1",
    api_key=os.environ["DIOGENES_API_KEY"],
)

reply = client.chat.completions.create(
    model="qwen3.5-397b-a17b",
    messages=[{"role": "user", "content": "Summarise this week's notes."}],
    extra_body={"jar_id": "JAR_ID"},
)
print(reply.choices[0].message.content)
TypeScript · openai, streaming
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.diogenes.to/v1",
  apiKey: process.env.DIOGENES_API_KEY,
});

const stream = await client.chat.completions.create({
  model: "qwen3.5-397b-a17b",
  messages: [{ role: "user", content: "What changed since last week?" }],
  stream: true,
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
Python · LangChain
import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="https://api.diogenes.to/v1",
    api_key=os.environ["DIOGENES_API_KEY"],
    model="qwen3.5-397b-a17b",
)
print(llm.invoke("Hello").content)