Norman Engine
API Reference

API Reference

Authentication

All endpoints require a valid JWT in the Authorization header:

Authorization: Bearer <token>

Tokens are issued by ShellApps OAuth and verified by the auth middleware.


POST /api/chat

Streaming and non-streaming chat completions.

Request Body

{
  "messages": [
    { "role": "system", "content": "You are a helpful assistant." },
    { "role": "user", "content": "Hello!" }
  ],
  "model": "gpt-4o",
  "temperature": 0.7,
  "maxTokens": 4096,
  "stream": true
}
FieldTypeRequiredDefaultDescription
messagesArray<{role, content}>YesChat messages. Roles: system, user, assistant
modelstringNogpt-4oModel identifier
temperaturenumberNoSampling temperature (0-2)
maxTokensnumberNoMaximum tokens in response
streambooleanNofalseEnable SSE streaming

Response (Non-Streaming)

{
  "content": "Hello! How can I help you today?",
  "model": "gpt-4o",
  "usage": {
    "promptTokens": 25,
    "completionTokens": 10
  },
  "requestId": "550e8400-e29b-41d4-a716-446655440000"
}

Response (Streaming)

SSE events:

data: {"content": "Hello"}
data: {"content": "!"}
data: {"content": " How"}
data: {"usage": {"promptTokens": 25, "completionTokens": 10}}
data: [DONE]

POST /api/complete

Non-streaming chat completions only. Same request/response format as /api/chat without the stream field.


GET /api/models

List available models for the current provider.

Response

{
  "models": [
    { "id": "gpt-4o", "name": "GPT-4o" },
    { "id": "gpt-4o-mini", "name": "GPT-4o Mini" }
  ],
  "provider": "openai"
}

GET /api/usage

Per-user token usage statistics.

Query Parameters

ParameterTypeDefaultDescription
daysnumber30Days to look back (1-90)

Response

{
  "success": true,
  "data": {
    "totalPromptTokens": 150000,
    "totalCompletionTokens": 50000,
    "totalRequests": 250,
    "byModel": {
      "gpt-4o": { "promptTokens": 100000, "completionTokens": 35000, "requests": 150 },
      "gpt-4o-mini": { "promptTokens": 50000, "completionTokens": 15000, "requests": 100 }
    },
    "byDay": [
      { "date": "2026-02-20", "promptTokens": 5000, "completionTokens": 2000, "requests": 10 }
    ]
  }
}

Error Responses

All endpoints return errors in this format:

{
  "error": "Bad Request",
  "message": "messages must be a non-empty array of { role, content } objects",
  "requestId": "550e8400-e29b-41d4-a716-446655440000"
}
StatusMeaning
400Invalid request body or parameters
401Missing or invalid authentication
429Rate limit exceeded
500Internal server error

© 2026 Shell Technology. All rights reserved.