Skip to main content

API Endpoints Reference

Complete reference for all Ozwell API endpoints.

Base URLs​

EnvironmentURL
Current Ozwell Manager APIhttps://ozwellapi.os.mieweb.org
tip

Use https://ozwellapi.os.mieweb.org for current Ozwell Manager features. Production is temporarily unavailable while it migrates to the future api.ozwell.ai endpoint, so it is not advertised as the active API here.

Chat​

Create Chat Completion​

Generate a response for a conversation.

POST /v1/chat/completions

Request Body​

ParameterTypeRequiredDescription
providerstringNoProvider ID (e.g., openai, anthropic, ollama). Required when model is ambiguous across allowed providers.
modelstringNoModel ID (e.g., gpt-4.1-mini). If omitted, uses the agent model-policy default, then the server-wide fallback, then LLM_MODEL — each still subject to the effective policy.
messagesarrayYesArray of message objects
temperaturenumberNoSampling temperature (0-2). Default: 1
top_pnumberNoNucleus sampling. Default: 1
nintegerNoNumber of completions to generate. Default: 1
streambooleanNoStream responses. Default: false
stopstring/arrayNoStop sequences
max_tokensintegerNoMaximum tokens to generate
presence_penaltynumberNoPresence penalty (-2 to 2). Default: 0
frequency_penaltynumberNoFrequency penalty (-2 to 2). Default: 0
toolsarrayNoList of tools (functions) available
tool_choicestring/objectNoTool selection behavior

Message Object​

{
"role": "user | assistant | system | tool",
"content": "Message content",
"name": "optional_name",
"tool_calls": [],
"tool_call_id": "for_tool_role"
}

Example Request​

curl https://ozwellapi.os.mieweb.org/v1/chat/completions \
-H "Authorization: Bearer $OZWELL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "openai",
"model": "gpt-4",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
"temperature": 0.7
}'

Response​

{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1699000000,
"model": "gpt-4",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The capital of France is Paris."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 10,
"total_tokens": 35
}
}

Embeddings​

Create Embedding​

Generate vector embeddings for text.

POST /v1/embeddings

Request Body​

ParameterTypeRequiredDescription
modelstringYesModel ID (e.g., text-embedding-ada-002)
inputstring/arrayYesText to embed
encoding_formatstringNofloat or base64. Default: float

Example Request​

curl https://ozwellapi.os.mieweb.org/v1/embeddings \
-H "Authorization: Bearer $OZWELL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "text-embedding-ada-002",
"input": "The quick brown fox"
}'

Response​

{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.0023, -0.0092, 0.0156, ...]
}
],
"model": "text-embedding-ada-002",
"usage": {
"prompt_tokens": 4,
"total_tokens": 4
}
}

Files​

Upload File​

Upload a file for use with the API.

POST /v1/files

Request (multipart/form-data)​

ParameterTypeRequiredDescription
filefileYesThe file to upload
purposestringYesPurpose: assistants, fine-tune, etc.

Example Request​

curl https://ozwellapi.os.mieweb.org/v1/files \
-H "Authorization: Bearer $OZWELL_API_KEY" \
-F "file=@document.pdf" \
-F "purpose=assistants"

Response​

{
"id": "file-abc123",
"object": "file",
"bytes": 1024000,
"created_at": 1699000000,
"filename": "document.pdf",
"purpose": "assistants"
}

List Files​

List all uploaded files.

GET /v1/files

Query Parameters​

ParameterTypeDescription
purposestringFilter by purpose

Response​

{
"object": "list",
"data": [
{
"id": "file-abc123",
"object": "file",
"bytes": 1024000,
"created_at": 1699000000,
"filename": "document.pdf",
"purpose": "assistants"
}
]
}

Retrieve File​

Get information about a specific file.

GET /v1/files/{file_id}

Delete File​

Delete a file.

DELETE /v1/files/{file_id}

Retrieve File Content​

Download file contents.

GET /v1/files/{file_id}/content

Audio​

Create Transcription​

Transcribes audio into the input language.

POST /v1/audio/transcriptions

This is a multipart/form-data endpoint.

Request Body (multipart/form-data)​

ParameterTypeRequiredDescription
filefileYesThe audio file to transcribe. Supported formats: mp3, mp4, mpeg, mpga, m4a, wav, webm
modelstringYesModel ID (currently whisper-1)
languagestringNoLanguage code in ISO-639-1 format
response_formatstringNoOutput format: json, text, srt, verbose_json, vtt. Default: json
temperaturenumberNoSampling temperature (0-1). Default: 0
timestamp_granularitiesarrayNoTimestamp granularities: word, segment. Requires verbose_json format

Example Request​

curl https://ozwellapi.os.mieweb.org/v1/audio/transcriptions \
-H "Authorization: Bearer $OZWELL_API_KEY" \
-F "file=@audio.mp3" \
-F model=whisper-1

Response (json format)​

{
"text": "Hello, this is a transcription of the audio file."
}

Response (verbose_json format)​

{
"task": "transcribe",
"language": "english",
"duration": 3.0,
"text": "Hello, this is a transcription of the audio file.",
"words": [
{ "word": "Hello", "start": 0.0, "end": 0.5 }
],
"segments": [
{
"id": 0,
"seek": 0,
"start": 0.0,
"end": 3.0,
"text": "Hello, this is a transcription of the audio file.",
"tokens": [50364, 639, 307],
"temperature": 0.0,
"avg_logprob": -0.25,
"compression_ratio": 1.0,
"no_speech_prob": 0.01
}
]
}

Models​

List Models​

List discovered provider/model records. The registry is stored in the backend database and refreshed from the configured gateway/Ollama discovery paths.

GET /v1/models

Response (example — actual models depend on your backend configuration)​

{
"object": "list",
"data": [
{
"id": "gpt-4.1-mini",
"provider": "openai",
"model": "gpt-4.1-mini",
"object": "model",
"created": 0,
"owned_by": "openai"
},
{
"id": "gpt-4o-mini",
"provider": "openai",
"model": "gpt-4o-mini",
"object": "model",
"created": 0,
"owned_by": "openai"
}
]
}

List Effective Models​

List the provider/model records allowed for the current parent key or agent key.

GET /v1/models/effective

The effective list is:

enabled discovered models ∩ server-wide restrictions ∩ parent-key restrictions ∩ agent model policy

Each level only narrows the level above it, and an empty level is a no-op. Policy is resolved before any provider dispatch, so a request for a disallowed pair is rejected with 403 model_not_allowed before it reaches an upstream provider.

Retrieve Model​

Get details about a specific model.

GET /v1/models/{model_id}

Manager Model Policy Endpoints​

Manager-console routes expose the same provider-aware policy controls:

EndpointPurpose
GET /v1/manager/modelsList/refresh discovered provider models for the manager console, narrowed by the server-wide policy
GET /v1/manager/admin/model-restrictionsRead server-wide restrictions (admin only)
PUT /v1/manager/admin/model-restrictionsSave server-wide restrictions with allowed_models (admin only)
GET /v1/manager/admin/default-modelRead the server-wide fallback model (admin only)
PUT /v1/manager/admin/default-modelSet or clear the server-wide fallback model (admin only)
GET /v1/manager/admin/parent-keys/{key_id}/model-restrictionsRead parent-key restrictions
PUT /v1/manager/admin/parent-keys/{key_id}/model-restrictionsSave parent-key restrictions with allowed_models
GET /v1/manager/agents/{agent_id}/model-policyRead an agent fallback model and allowed-model policy
PUT /v1/manager/agents/{agent_id}/model-policySave an agent fallback model and allowed-model policy
GET /v1/manager/notificationsList model-policy notifications

Restriction bodies use provider-aware entries:

{
"allowed_models": [
{ "provider": "openai", "model": "gpt-4o-mini" },
{ "provider": "anthropic" }
]
}

An empty allowed_models array means unrestricted within the higher-level effective policy.

An entry with a provider and no model allows that whole provider.

Server-Wide Restrictions​

GET/PUT /v1/manager/admin/model-restrictions set one allow-list for the entire server. They require an admin manager user and return 403 admin_required otherwise. The policy applies to every key and agent, including requests made with no parent key, and takes effect on the next request with no restart.

{
"allowed_models": [{ "provider": "ollama", "model": "gemma3:1b" }],
"discovered_models": [],
"effective_models": []
}

discovered_models is the unfiltered registry, so an admin UI can still offer every discovered model to choose from; effective_models is the same list after the server-wide policy is applied.

Server-wide policy is stored in its own table and never touches provider_models.enabled, which discovery refresh owns. Saving it does not modify or delete any parent-key or agent policy — those stay stored exactly as written and simply narrow further.

If a save takes a model away, every key that loses one gets a model_policy_changed notification — the same one a per-key change sends. Keys that lose nothing are not notified.

A save that would exclude the server-wide fallback model is rejected with 400 default_model_not_allowed, since it would leave every request that names no model with nothing to resolve to. Change the fallback first, or keep its model approved.

Server-Wide Fallback Model​

GET/PUT /v1/manager/admin/default-model set the model used when a request names none. Admin only, 403 admin_required otherwise. A stored value beats LLM_MODEL and every other environment value, and is read per request, so a save takes effect without a restart.

{
"provider": "openai",
"model": "gpt-4o-mini"
}

Sending both fields as null clears the fallback and drops the server back to its environment chain:

agent model-policy default → server-wide fallback → environment → gpt-4o-mini

The environment step is the environment_model below — LLM_MODEL when LLM_BASE_URL is set, the first Ollama model when it is not and Ollama is reachable, otherwise DEFAULT_MODEL.

Both endpoints return the stored value plus effective_models, the list an admin picker should offer:

{
"default_model": { "provider": "openai", "model": "gpt-4o-mini" },
"environment_model": { "provider": "openai", "model": "gpt-4o-mini" },
"effective_models": []
}

environment_model is what the server falls back to when default_model is null, resolved from the backend in use — LLM_MODEL, the first Ollama model, or DEFAULT_MODEL. It is reported so an admin console can show the model actually in use rather than an empty control.

A PUT naming a model the server cannot serve is rejected with 400 default_model_not_allowed — whether it is missing from the registry, blocked by the server-wide allow-list, or available only under a different provider. Chat resolves the fallback through the same effective list, so a model accepted here but absent there would return 403 model_not_allowed on the next request that names no model.

The check runs whenever the registry holds anything. A fresh server whose registry is still empty accepts any pair, because there is nothing to check against and the stored value seeds the registry itself.

Only the server-wide allow-list is guarded this way. A parent-key or agent restriction that excludes the fallback is still accepted, and a request from that key naming no model then fails with 403 model_not_allowed. That is deliberate — a key narrowed to one provider should not be forced to keep a fallback from another — but it means a narrowed key needs its own default model set through PUT /v1/manager/agents/{agent_id}/model-policy.

A PUT naming only one of provider and model is rejected with 400 invalid_default_model. Send both to set a fallback, or both as null to clear it.

The same value seeds the model registry when discovery returns nothing, replacing LLM_MODEL and LLM_PROVIDER in that path too.


Responses (Ozwell Extension)​

Extended response format with additional capabilities.

Create Response​

Create a response with extended features.

POST /v1/responses

Request Body​

Includes all chat/completions parameters plus:

ParameterTypeDescription
conversation_idstringID for conversation persistence
include_sourcesbooleanInclude source citations
response_formatobjectStructured output format

Example Request​

curl https://ozwellapi.os.mieweb.org/v1/responses \
-H "Authorization: Bearer $OZWELL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Summarize this document"}],
"conversation_id": "conv_abc123",
"include_sources": true
}'

Response​

{
"id": "resp-abc123",
"object": "response",
"created": 1699000000,
"model": "gpt-4",
"conversation_id": "conv_abc123",
"output": {
"role": "assistant",
"content": "Here is the summary..."
},
"sources": [
{
"file_id": "file-xyz789",
"filename": "document.pdf",
"page": 3,
"excerpt": "Relevant excerpt..."
}
],
"usage": {
"prompt_tokens": 150,
"completion_tokens": 80,
"total_tokens": 230
}
}

Pagination​

List endpoints support pagination:

ParameterTypeDescription
limitintegerMax items to return (1-100). Default: 20
afterstringCursor for next page
beforestringCursor for previous page

Example​

# First page
curl "https://ozwellapi.os.mieweb.org/v1/files?limit=10" \
-H "Authorization: Bearer $OZWELL_API_KEY"

# Next page
curl "https://ozwellapi.os.mieweb.org/v1/files?limit=10&after=file-abc123" \
-H "Authorization: Bearer $OZWELL_API_KEY"

Widget Sign-In​

Sign-in routes for the embeddable widget. They mint a sess_ token that stands in for the signed-in user's own API key — see Authentication.

These routes take no API key. Everything else on this page does.

List Sign-In Methods​

Report which methods this server offers, so the widget only shows what will work.

GET /auth/methods
{ "google": true, "apple": true, "email_otp": true, "user_key": true }

google is false unless the server has GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET set. apple requires all four Apple settings described in Widget Authentication.

Request an Email Code​

POST /auth/otp/request
{ "email": "user@example.com" }

Returns a challenge_id. The code is six digits, lasts 10 minutes, and allows 5 attempts.

One address may request 3 codes per 15 minutes; beyond that the route returns 429. A malformed address returns 400, and 502 means the code could not be delivered.

Where the code goes depends on SMTP_URL. With it set, the code is mailed and kept out of the logs. Without it — the normal local-development case — the code is logged instead, and AUTH_DEV_ECHO_OTP=1 additionally returns it as dev_code. That echo is ignored whenever a mail sender is configured, so it cannot bypass delivery.

Verify an Email Code​

POST /auth/otp/verify
{ "challenge_id": "...", "code": "123456" }

Returns { "session_token": "sess_...", "email": "..." }. A wrong or expired code returns 401. Each challenge verifies once.

Start Google Sign-In​

GET /auth/oidc/google/start

Redirects to Google's consent screen. OAuth 2.0 authorization code with PKCE (S256), plus state and nonce. Returns 404 when Google is not configured. Both providers share a limit of 1,000 pending sign-in flows per process; new starts return 429 at capacity until flows complete or expire after ten minutes.

Open this in a popup, not in an iframe — Google refuses to render consent in a frame.

Google Callback​

GET /auth/oidc/google/callback

Google's redirect target. Exchanges the code, verifies the ID token against Google's JWKS (issuer, audience, nonce and email_verified), then mints a session. Responds with a small page that posts { source: 'ozwell-auth', session_token, email } to window.opener and closes itself.

Register this URL under Authorized redirect URIs in Google Cloud Console — not under Authorized JavaScript origins, which rejects any URL carrying a path. The server builds it from PUBLIC_BASE_URL, never from request input.

Start Apple Sign-In​

GET /auth/oidc/apple/start

Opens Apple consent in a popup using authorization code flow, state, nonce, and response_mode=form_post. Returns 404 when Apple is not configured.

Apple Callback​

POST /auth/oidc/apple/callback
Content-Type: application/x-www-form-urlencoded

Accepts Apple's code and state (or provider error), exchanges the code using an ES256 client secret, and verifies the signed identity token and verified email. Returns the same origin-restricted popup response as Google. Register the exact public HTTPS return URL built from PUBLIC_BASE_URL; localhost is not supported. See Widget Authentication for Apple configuration.

Describe the Current Session​

GET /auth/session

With Authorization: Bearer sess_..., returns { "email": "...", "user_id": ... }. An expired or unknown token returns 401.

Sign Out​

POST /auth/logout

Revokes the token in the Authorization header. Sessions otherwise expire 24 hours after sign-in, and are lost on server restart.


Versioning​

The API is versioned in the URL path (/v1/). Breaking changes will result in a new version.

Current version: v1


Agents​

Agent registration and management API. See the full reference:

➡️ Agent Registration API


See Also​