API documentation

The LessStrict API is OpenAI-compatible. If your code already talks to OpenAI, change the base URL and the API key and use our model slugs. Everything else keeps working.

Quickstart

  1. Create an account and open Dashboard, API keys. Create a key and copy it; it is shown once.
  2. Send your first request:
bash
curl https://lessstrict.com/v1/chat/completions \
  -H "Authorization: Bearer lsk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ls-lite",
    "messages": [
      {"role": "system", "content": "You are a terse assistant."},
      {"role": "user", "content": "Give me a regex for ISO 8601 dates."}
    ]
  }'

The response has the standard OpenAI shape:

json
{
  "id": "chatcmpl-9f2b...",
  "object": "chat.completion",
  "created": 1762500000,
  "model": "ls-lite",
  "choices": [{ "index": 0, "message": { "role": "assistant", "content": "^\\d{4}-\\d{2}-\\d{2}$" }, "finish_reason": "stop" }],
  "usage": { "prompt_tokens": 31, "completion_tokens": 12, "total_tokens": 43 }
}

Authentication

Every request needs an API key in the Authorization header as a bearer token. Keys start with lsk_. Treat them like passwords: keep them on the server, never in client-side code.

http
Authorization: Bearer lsk_live_...

Each key has a billing mode that you choose when you create it and can change later:

  • AUTO (default): use the plan allowance for the model first; when it is used up or the model is not in the plan, charge the wallet.
  • SUBSCRIPTION: plan allowance only. Requests fail with 402 plan_limit when it is exhausted.
  • WALLET: always pay per token from the wallet, never touching plan allowances.

Keys can also be restricted to specific models and given a monthly spend cap.

Base URL

text
https://lessstrict.com/v1

All endpoints below are relative to this URL. Requests must use HTTPS in production. CORS is enabled for GET and POST, but calling the API from a browser exposes your key, so proxy through your own backend.

Chat completions

POST /v1/chat/completions

Generates a reply for a conversation. Parameters:

FieldTypeNotes
modelstringA LessStrict model slug, e.g. "ls-lite". See GET /v1/models.
messagesarrayMessages with role system, user or assistant. Content is a string or an array of text and image_url parts (images only on vision models).
streambooleantrue to receive server-sent events. Default false.
temperaturenumber0 to 2. Defaults to the model's default.
max_tokensintegerCap on output tokens. Clamped to the model's max output. max_completion_tokens is accepted as an alias.
top_pnumber0 to 1.
stopstring | string[]Stop sequences.
response_formatobject{"type": "json_object"} for JSON mode on models that support it.
web_searchbooleanLessStrict extension. Runs a web search for the last user message and gives the results to the model, which cites them as [n]. Uses your plan's search allowance, then the wallet.

Example with web search and JSON mode:

json
{
  "model": "ls-lite",
  "web_search": true,
  "response_format": { "type": "json_object" },
  "messages": [
    { "role": "system", "content": "Reply with JSON: {\"summary\": string, \"sources\": string[]}" },
    { "role": "user", "content": "What changed in the latest Node.js LTS release?" }
  ]
}

A system message you send is appended to LessStrict's own system prompt for the model (identity, date, capabilities). Your instructions take precedence for style and format.

Streaming

With "stream": true the response is text/event-stream. Each event is a chat.completion.chunk in OpenAI format. The last content chunk is followed by a usage chunk and then data: [DONE].

text
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1762500000,"model":"ls-lite","choices":[{"index":0,"delta":{"role":"assistant","content":"Hel"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1762500000,"model":"ls-lite","choices":[{"index":0,"delta":{"content":"lo"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1762500000,"model":"ls-lite","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":2,"total_tokens":14}}

data: [DONE]

If the upstream provider fails mid-stream you receive a chunk with an error object and the stream ends. Tokens are only billed for successful or client-cancelled responses, never for upstream errors.

Models

GET /v1/models

Lists the models your key can use. The shape matches OpenAI's list with extra fields:

json
{
  "object": "list",
  "data": [
    {
      "id": "ls-chat",
      "object": "model",
      "created": 1762500000,
      "owned_by": "lessstrict",
      "name": "LS Coder",
      "description": "Built for software engineering",
      "context_length": 262144,
      "max_output_tokens": 32768,
      "pricing": { "input_per_1m": 0.5, "output_per_1m": 2.0, "currency": "USD" },
      "capabilities": { "vision": false, "tools": true, "json": true, "reasoning": false, "streaming": true },
      "categories": ["coding", "agents"]
    }
  ]
}

GET /v1/models/{id} returns a single model.

Account

GET /v1/me

Returns the state of the account behind the key: wallet balance, plan, and remaining allowance per model for the current period. Use it to decide which model to call or to show your own users what is left.

json
{
  "balance_usd": 12.4,
  "plan": { "slug": "pro", "name": "Pro", "requests_per_minute": 60 },
  "key": { "name": "backend", "billing_mode": "AUTO" },
  "allowances": [
    { "model": "ls-chat", "monthly_tokens": 6000000, "used_month_tokens": 418233, "daily_tokens": null, "used_day_tokens": 12000 }
  ]
}

Response headers

HeaderMeaning
x-request-idUnique ID for the request. Quote it in support requests.
x-ls-billed-viaplan or wallet: which source paid for the request.
x-ls-charge-usdAmount deducted from the wallet, 0 when covered by the plan. Sent as a trailer-free header on non-streaming responses.
x-ratelimit-limitRequests allowed per minute on your plan.
x-ratelimit-remainingRequests left in the current minute.

Errors

Errors use the OpenAI shape so SDK error handling works unchanged:

json
{ "error": { "message": "You have used this month's Pro allowance for LS Ultra.", "type": "billing_error", "code": "plan_limit" } }
StatusCodeWhen
400invalid_requestMalformed body or unsupported parameter.
401invalid_api_keyMissing, revoked, expired or unknown key.
402plan_limitPlan allowance for the model is used up and no wallet fallback applies.
402insufficient_fundsWallet is empty on a wallet-billed request.
402no_paygModel is only available through plans and your plan does not include it.
403model_not_allowed_for_keyKey is restricted to other models, or the account lacks API access.
404model_not_foundUnknown model slug.
429rate_limitedRequests per minute exceeded. Retry after the delay in the message.
502upstream_errorThe provider behind the model failed. Nothing was billed.
503model_unavailableThe model is disabled or its provider is not configured.

Official SDKs

Point the OpenAI SDK at LessStrict. No other change is needed.

Python

python
from openai import OpenAI

client = OpenAI(base_url="https://lessstrict.com/v1", api_key="lsk_...")

resp = client.chat.completions.create(
    model="ls-chat",
    messages=[{"role": "user", "content": "Write a Python function that parses a cron expression."}],
)
print(resp.choices[0].message.content)

Node.js

ts
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://lessstrict.com/v1", apiKey: process.env.LESSSTRICT_API_KEY });

const stream = await client.chat.completions.create({
  model: "ls-chat",
  messages: [{ role: "user", content: "Write a TypeScript function that parses a cron expression." }],
  stream: true,
});
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");

Tools that accept a custom OpenAI base URL (editors, agents, chat clients) work the same way: base URL https://lessstrict.com/v1, API key lsk_…, model set to a LessStrict slug.

Limits and billing

  • Rate limits are per account, in requests per minute, set by your plan. The chat and the API share the same limit.
  • Plan allowances are per model, in tokens per month, optionally with a daily token or request cap. They reset at 00:00 UTC on the first of the month (monthly) and every day (daily).
  • On AUTO, a request runs on the plan if the estimated size fits the remaining allowance, otherwise on the wallet at the model's per-token rate.
  • Wallet charges use the token counts reported by the provider. If a provider does not report usage we estimate conservatively and show the estimate in your usage history.
  • Requests that fail before generation starts are free. Requests you cancel mid-stream are billed for the tokens generated.
  • Every request appears in Dashboard, Usage with tokens, cost, billing source and request ID.

Something missing? Tell us what you are building and we will document it.