Get API key

Local LLM OpenAI API: Run Local, Switch to Hosted

A local LLM OpenAI API is a model server on your own machine that answers the same HTTP requests the OpenAI SDKs send. Because the request format is shared, the code you write for it also runs against a hosted endpoint, and this page shows what carries over and what does not.

Updated

Desktop computer and cloud server joined by one cable with a switch, showing local and hosted LLM endpoints.

Key points

What the phrase means

People use "local LLM OpenAI API" for two related things. The first is a language model you run yourself, on a laptop or a home server, that listens on a local port and speaks the OpenAI chat format. The second is the habit of writing your app against that format so the model behind it can be swapped.

The format is a simple contract. Your app sends a JSON body with a model name and a list of messages, each with a role of system, user or assistant. The server replies with a JSON object holding the generated message, or with a stream of small chunks if you ask for streaming. Official SDKs for Python and JavaScript wrap this, and they let you override the base URL, which is the whole trick.

Many local tools expose this contract. Ollama, LM Studio, the llama.cpp server and vLLM each offer an OpenAI-style route. Hosted services do too, which is why the same twenty lines of client code can talk to either. The endpoint on this site is one of the hosted kind. It accepts POST /v1/chat/completions and GET /v1/models, and it is reached at https://api.onekeyllmapi.com/v1.

Local versus hosted at a glance

Neither is better in general. They trade control for effort. The table sticks to differences that hold for the category, not for any particular product.

QuestionLocal runnerHosted OpenAI-style API
Where prompts goStay on your machineTravel to the provider over HTTPS
HardwareYou supply GPU or CPU and memoryNone on your side
Model sizeLimited by your memoryWhatever the provider serves
Cost modelHardware and powerPer token, from prepaid credit here
AvailabilityAs long as your machine is onAlways-on server, shared limits
SetupInstall, download weights, tuneCreate a key, set the base URL

If your data must never leave a machine you control, local wins and hosted is the wrong tool. If you need a bigger model than your hardware holds, or a bot that stays reachable from many places, hosted wins. A common setup keeps both and picks per task.

Switching a client from local to hosted

If your code already talks to a local runner, the move is three values. Everything else, including how you build messages and read streamed chunks, stays the same.

  1. Base URL. Use https://api.onekeyllmapi.com/v1 instead of your local address.
  2. API key. Local servers often ignore the key. A hosted one requires it as Authorization: Bearer <key>, and the SDK sends it for you.
  3. Model ID. Local names are whatever you pulled. Here the ID is uncensored.

A tidy way to keep this flexible is to read all three from environment variables, so one file works in both places.

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.environ.get("LLM_BASE_URL", "https://api.onekeyllmapi.com/v1"),
    api_key=os.environ.get("LLM_API_KEY", "YOUR_KEY"),
)
MODEL = os.environ.get("LLM_MODEL", "uncensored")

models = client.models.list()
print([m.id for m in models.data])

resp = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "Answer in two sentences."},
        {"role": "user", "content": "Why do OpenAI-style endpoints make switching models easy?"},
    ],
    temperature=0.5,
)
print(resp.choices[0].message.content)

The same call from the command line, useful for a quick smoke test:

curl https://api.onekeyllmapi.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "uncensored", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 20}'

With Node, the pattern is identical:

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: process.env.LLM_BASE_URL ?? "https://api.onekeyllmapi.com/v1",
  apiKey: process.env.LLM_API_KEY,
});

const res = await client.chat.completions.create({
  model: process.env.LLM_MODEL ?? "uncensored",
  messages: [{ role: "user", content: "Name three uses for JSON mode." }],
});
console.log(res.choices[0].message.content);

What OpenAI-compatible does and does not cover

Compatible means the wire format matches. It does not promise that every feature the original service offers is present. Before you migrate a real app, check each of these against the target.

What this API supports

  • Chat completions at POST /v1/chat/completions and a model list at GET /v1/models.
  • Streaming over server-sent events with stream: true, with usage reported at the end of the stream.
  • Tool calling through tools and tool_choice, streamed tool_calls, and results sent back as role: "tool" messages.
  • JSON mode through response_format: {"type": "json_object"}.
  • Sampling controls: temperature, top_p, stop, seed and the penalty parameters are passed through.

What it does not do

  • No images, audio or video generation. It is text only.
  • No embeddings endpoint and no fine-tuning. If your app builds a vector index, you need a separate embedding source.
  • One model only. The model is an open-weight model run by an independent provider. It is not the official API of any big vendor, and it is not a router across vendors, so you cannot pick between model families by changing the ID.

Local runners sometimes differ the other way: a local server may offer an embeddings route or let you load several models, and the context size is whatever you configure. Read the target's docs for each, and keep a short list of the features your app really uses. The quickstart docs show the request fields in full.

Context, limits and cost differences

Three numbers change when you leave a local server. The first is the window. A local runner's context length is a setting tied to your memory. Here it is fixed at 100,000 tokens, shared by the prompt and the completion, and max_tokens is optional. The second is concurrency. Your own machine can be queued as deep as you like, but a full key here allows 8 concurrent requests and 300 per minute, and a trial key 2 and 60. The third is the bill.

Hosted use costs $0.15 per 1M input tokens and $0.50 per 1M output tokens, pay as you go from prepaid credit. Work through a daily job as an example: a summarizer processes 400 documents a day, each 3,000 tokens in and 300 tokens out. Input is 400 x 3,000 = 1,200,000 tokens, which costs 1.2 x $0.15 = $0.18. Output is 400 x 300 = 120,000 tokens, which costs 0.12 x $0.50 = $0.06. The day totals $0.24, and a 30-day month is $7.20. Compare that with the cost of keeping a GPU powered and of the card itself before you decide.

When you exceed a limit, the API answers HTTP 429 with the code rate_limited or concurrency. For brief overload it adds Retry-After: 5. Keep retry logic that waits and tries again. Requests that fail or are refused are not charged. Credit never expires, so an idle month costs nothing.

A streamed request keeps its concurrency slot until the stream ends, so close streams you stop reading. Top-ups begin at $20; the tiers and bonuses are on the pricing page.

Debugging when the switch misbehaves

Most failed migrations come down to a handful of causes. Work through them in this order.

  • 404 or connection errors. The base URL probably lacks the /v1 suffix, or has an extra path. Use it exactly as https://api.onekeyllmapi.com/v1.
  • Authentication errors. The key is missing or sent in the wrong header. The format is Authorization: Bearer <key>. SDK users should confirm the environment variable actually loaded.
  • Model not found. The old local model name is still in your config. Call GET /v1/models and use the ID it lists, which is uncensored.
  • 429 under load. You are past 8 concurrent requests or 300 a minute on a full key. Add a queue or semaphore.
  • A parameter seems ignored. Check that it is one of the passed-through fields listed above, and compare behavior with a fixed seed and low temperature.

Every response includes an X-Request-Id header. Log it next to your own request ID so a bad answer can be traced later. If you run production traffic and want to measure quality over time, the site article LLM Observability: Myths vs Facts is a good next read. The response headers X-Balance-USD, X-RateLimit-Limit-Requests and X-RateLimit-Limit-Concurrency are also worth capturing.

Trying it without commitment

The cheapest way to test whether your code ports cleanly is to run it once. Create an account with Google or email and password, then claim the $0.50 trial credit from the key page. It takes one click, needs no card, is limited to one per person and stays valid for 7 days. Get your key at the API key page, set the three environment variables from above and run your existing test suite.

If the tests pass and the usage fits your budget, top up from $20, by card (Visa, Mastercard, Apple Pay, Google Pay) or crypto (USDT on TRC20, USDC on Base). Prompts are not used for training. The model is tuned to answer without content refusals for lawful adult use, with one fixed rule: no sexual content involving minors.

Questions and answers

Can I run a local LLM with an OpenAI-compatible API?

Yes. Runners such as Ollama, LM Studio, the llama.cpp server and vLLM can expose OpenAI-style endpoints, and you point the OpenAI SDK at that local address.

What do I change to move my app to this hosted API?

Three values: the base URL, the API key and the model ID. Here they are the base URL shown in the examples, a bearer key from your account and the model ID uncensored.

Does this API support embeddings or image generation?

No. It is text only, with chat completions, streaming, tool calling and JSON mode. Use a separate service for embeddings or images.

Is this the official API of a model vendor?

No. It serves one open-weight model run by an independent provider, and it is not a router across vendors.

Your key is one form away

Create an account, copy the key, change the base URL. That is the whole setup.