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.
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 https://api.diogenes.to/v1/models \ -H "Authorization: Bearer $DIOGENES_API_KEY"
| Field | Meaning |
|---|---|
id | The value to send as model. |
display_name | The name the app shows. |
tier | included: covered by your plan's included usage. credits: paid per token in credits. |
profile | fast answers quickly; deep is the large reasoning class; null when not set. |
context_window | Tokens the model reads in one request. |
tools | Whether the model can read links, look things up on-chain and draw pictures when those are on. |
vision | Whether the model reads images in the app. The API itself takes text only. |
credits_per_1m_in, credits_per_1m_out | Credits per million input and output tokens on credits models; null on included models. |
privacy_route | private: Diogenes-controlled infrastructure. confidential: inside an attested TEE (NEAR AI). external: another provider, reached through DigitalOcean. |
confidential | For confidential models: provider, upstream_model, attestation (verified, pending, failed or stale) and verified_at. Otherwise null. |
external_provider | For 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.
| Field | Notes |
|---|---|
model | Optional. A model id from /v1/models. Defaults to the app's default model, or to the conversation's model when you continue one. |
messages | Required. 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. |
stream | true for server-sent events. See Streaming. |
conversation_id | Diogenes. Continue a stored conversation: only your last user message is added. model must match it or be left out. |
jar_id | Diogenes. Start the conversation inside a JAR, so replies use its Knowledge. See JAR Knowledge. |
image_consent | Diogenes. Allows this request to draw a picture at the listed price. Without it no picture is drawn or charged. |
systemmessages are not sent to the model: the Diogenes system prompt applies, as in the app.- On a new conversation, your earlier
userandassistantmessages 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.
{
"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.
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].
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 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.
includedmodels run on your plan's included usage first; past it, a reply continues on credits only where the app would allow it.creditsmodels costcredits_per_1m_inandcredits_per_1m_outper million tokens.- Your monthly spending limit applies to API requests too.
usagein 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": { "code": "forbidden", "message": "This key cannot reach that JAR." } }| Status | Code | Meaning |
|---|---|---|
| 400 | validation | The request is malformed; the message says what to fix. |
| 400 | model_unavailable | That model is not offered. |
| 401 | unauthorized | The key is missing, malformed, unknown or revoked. |
| 402 | payment_required, spend_limit_reached | Not enough credits, or your spending limit is reached. |
| 403 | forbidden | The key does not reach that JAR, or personal chats. |
| 403 | external_unavailable_in_jar | External models are off in this JAR. |
| 404 | not_found | No such conversation or JAR for you. |
| 409 | payg_consent_required, external_consent_required | Confirm the price or the provider in the app first. |
| 429 | allowance_reached | Your included usage for the period is used up. |
| 429 | rate_limited | Too 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
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)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 ?? "");
}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)