OpenAI API for Developers: Use a Compatible Endpoint
If your code already speaks the OpenAI wire format, you can run it against this hosted endpoint by changing two values: the base URL and the key. This page shows the exact steps, with code you can paste.
Updated

Key points
- Set the base URL to https://api.openaigatewayapi.com/v1 and the model to uncensored; nothing else in your OpenAI client code has to change.
- Chat completions, streaming, tool calling and JSON mode all work through the normal SDK calls.
- Limits are 8 concurrent requests and 300 requests per minute on a full key, so build in a 429 retry.
- A one-click $0.50 trial needs no card, so you can test your integration before paying.
The short version
Most guides on the openai api for developers assume one vendor and one bill. The wire format, though, is just JSON over HTTPS, and a lot of client code, frameworks and tools can talk to any server that implements it. This site hosts one such server. You keep your SDK, change the base URL, swap in a key from this site, and set the model to uncensored.
That is the whole migration for a typical app. Here is the checklist, and the rest of the page fills in each step.
- Create an account and claim the trial credit on the API key page.
- Set the base URL to
https://api.openaigatewayapi.com/v1. - Send the key as
Authorization: Bearer <key>. The SDKs do this for you when you passapi_key. - Use
uncensoredas the model ID in every request. - Handle HTTP 429 with a short retry, as shown near the end.
Two endpoints exist: POST /v1/chat/completions and GET /v1/models. The service is text only. There is no image or audio generation, no embeddings and no fine-tuning, so if your app calls those, they will need a different provider.
Check the connection with curl
Before touching your application, confirm that the key works. The models endpoint is the cheapest test, because it generates no tokens.
export API_KEY="paste-your-key-here"
curl https://api.openaigatewayapi.com/v1/models \
-H "Authorization: Bearer $API_KEY" | grep -o uncensored
The grep prints the model ID uncensored if the list contains it; drop the grep to see the full JSON list. If you get a 401, the key is wrong or missing the Bearer prefix. Now send a real request:
curl https://api.openaigatewayapi.com/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"messages": [
{"role": "system", "content": "You are a concise technical assistant."},
{"role": "user", "content": "Explain idempotency keys in two sentences."}
],
"temperature": 0.4
}'
The response carries the usual choices and usage objects. It also includes headers worth logging: X-Request-Id for support questions, X-Balance-USD for your remaining credit, and the two X-RateLimit-Limit-* headers that show your request and concurrency ceilings.
Python with the official openai package
In Python you only touch the client constructor. Everything after it is the code you already have.
from openai import OpenAI
client = OpenAI(
base_url="https://api.openaigatewayapi.com/v1",
api_key="paste-your-key-here",
)
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "You write short, accurate release notes."},
{"role": "user", "content": "Summarise: added retry logic, fixed timeout bug."},
],
temperature=0.5,
max_tokens=200,
)
print(resp.choices[0].message.content)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)
Read the key from an environment variable in real code. The sample hardcodes it only to keep the snippet short. max_tokens is optional here; if you leave it out, the completion can use whatever is left of the 100,000-token window (prompt plus completion together). Setting it anyway is a cheap way to cap cost on a runaway generation.
Streaming
Streaming uses Server-Sent Events and the same stream=True flag you know. Usage numbers arrive at the end of the stream, so the last chunk may have an empty choices list.
from openai import OpenAI
client = OpenAI(base_url="https://api.openaigatewayapi.com/v1", api_key="paste-your-key-here")
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "List five edge cases for a date parser."}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if getattr(chunk, "usage", None):
print("\ntokens:", chunk.usage.total_tokens)
One detail matters for capacity planning. A streamed request holds its concurrency slot until the stream finishes, not until the first token. If a client abandons a stream without closing it, that slot stays busy longer than you expect.
Node.js example
The Node SDK takes the same two settings under different names.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.openaigatewayapi.com/v1",
apiKey: process.env.GATEWAY_KEY,
});
const completion = await client.chat.completions.create({
model: "uncensored",
messages: [
{ role: "user", content: "Write a regex that matches ISO 8601 dates, and explain it." },
],
temperature: 0.3,
});
console.log(completion.choices[0].message.content);
If you use a framework that has its own OpenAI integration, look for a field called base URL, API base or endpoint in its settings. Pasting the same URL there is usually all it takes. Chat front ends, agent frameworks and editor plugins mostly follow this pattern. Sampling parameters such as temperature, top_p, stop, seed and the frequency and presence penalties are passed through to the model.
Tool calling and JSON mode
Two features decide whether a model fits into a real application: calling your functions and returning data you can parse. Both are supported.
Tool calling
You declare tools with tools, optionally force a choice with tool_choice, and send results back as messages with role: "tool". Streamed responses deliver tool_calls in pieces, as with the standard format.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.openaigatewayapi.com/v1", api_key="paste-your-key-here")
tools = [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the status of an order by its ID.",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
},
}]
messages = [{"role": "user", "content": "Where is order A-1042?"}]
first = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
msg = first.choices[0].message
if msg.tool_calls:
call = msg.tool_calls[0]
args = json.loads(call.function.arguments)
result = {"order_id": args["order_id"], "status": "shipped"} # your real lookup here
messages.append(msg)
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
final = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
print(final.choices[0].message.content)
Always validate the arguments before acting on them. The model produces JSON that matches your schema most of the time, not every time, so treat call.function.arguments like any other untrusted input.
JSON mode
For extraction and classification jobs, ask for a JSON object and also say so in the prompt. Mentioning JSON in the instructions gives better results than relying on the flag alone.
from openai import OpenAI
import json
client = OpenAI(base_url="https://api.openaigatewayapi.com/v1", api_key="paste-your-key-here")
resp = client.chat.completions.create(
model="uncensored",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": "Reply with JSON only: {\"sentiment\": string, \"topics\": [string]}."},
{"role": "user", "content": "The docs are clear but the rate limits caught me off guard."},
],
)
data = json.loads(resp.choices[0].message.content)
print(data)
Limits, errors and retries
A full key allows 8 requests in flight and 300 requests per minute. The trial key allows 2 in flight and 60 per minute. The maximum request body is 8 MB. Go past a limit and you get HTTP 429, and the error code tells you which limit it was.
| Error code | Meaning | What to do |
|---|---|---|
rate_limited | Too many requests per minute | Slow the producer or spread work over the minute |
concurrency | Too many requests at once | Lower your worker count to 8 or fewer, or 2 on a trial key |
429 with Retry-After: 5 | Temporary overload | Wait the given seconds and try again |
The SDKs already retry some failures. Add your own handling for 429 so that a burst does not crash a batch job:
import time
from openai import OpenAI, RateLimitError
client = OpenAI(
base_url="https://api.openaigatewayapi.com/v1",
api_key="paste-your-key-here",
max_retries=0,
)
def ask(prompt, attempts=5):
for i in range(attempts):
try:
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
)
return r.choices[0].message.content
except RateLimitError as e:
wait = float(e.response.headers.get("retry-after", 2 ** i))
time.sleep(wait)
raise RuntimeError("still rate limited after retries")
Failed or refused requests are not charged, so a retry loop does not double your bill. A semaphore sized to your concurrency limit is the cleanest way to stay under the cap in async code.
Moving an existing app over
If you have a working app, do not hardcode the new values. Put the base URL, key and model name in environment variables so you can flip between environments without a deploy. That also lets you run the same test suite against two backends and compare the output side by side.
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ.get("LLM_BASE_URL", "https://api.openaigatewayapi.com/v1"),
api_key=os.environ["LLM_API_KEY"],
)
MODEL = os.environ.get("LLM_MODEL", "uncensored")
def complete(messages, **kw):
return client.chat.completions.create(model=MODEL, messages=messages, **kw)
Then work through a short migration routine:
- Run your existing prompt set against the new endpoint and read the outputs yourself. Automated checks catch format breaks, not tone.
- Check that any code parsing JSON still passes with
response_formatset, and keep a fallback that strips stray text around the object. - Measure the real token counts from
usage, because a different model tokenizes text differently and your old estimates may be off. - Set your worker pool to 8 or fewer so that the concurrency cap is never the first thing to fail under load.
- Ship to a small share of traffic, watch the 429 rate and the error logs, then widen.
Teams often forget the system prompt in this process. Prompts written to coax a refusal-prone model into behaving usually contain hedging lines that are unnecessary here and can clutter the output. Read yours again and cut what no longer does anything.
What to know before you switch
Compatibility covers the request and response format. It does not make this the official API of any model maker. The service runs one open-weight model, hosted by an independent provider and tuned to answer without content refusals for lawful adult use. It is not a router across vendors, so you will not find a menu of other models behind it. Sexual content involving minors is not allowed, and that limit cannot be changed.
Plan around three practical differences from a large multi-model platform:
- One model. The ID is
uncensored. If your code switches models by task, collapse that to one value. - Text only. Remove any image, audio or embedding calls from the path that goes to this endpoint.
- Prompt behavior differs. A different model reads instructions differently, so rerun your prompts and tests after switching. Tighten system prompts where the output drifts.
Prompts are not used for training. For the full parameter list see the API docs. If you are estimating spend, the pricing page lists the per-token rates: $0.15 per 1M input tokens and $0.50 per 1M output tokens, billed from prepaid credit with no subscription. Top-ups run from $20 to $500 and credit does not expire. If you are weighing a proxy layer in front of several services instead, the page on LLM gateways covers when that extra moving part pays off.
More guides
Questions and answers
Do I need a new SDK to use this endpoint?
No. The official OpenAI SDKs for Python and Node work once you set the base URL to https://api.openaigatewayapi.com/v1 and use a key from this site. Any other client that lets you set a custom endpoint works the same way.
Which model ID should I send?
Use uncensored in the model field of every chat completion request. You can confirm it with a GET request to /v1/models.
Can I test it without paying?
Yes. After sign-up you can claim $0.50 of trial credit with one click on the API key page. It needs no card, is valid for 7 days and is limited to one per person.
Does it support embeddings or image generation?
No. The API is text only and offers chat completions and a model list. For embeddings or images you need a separate provider.
Are my prompts used for training?
No, prompts are not used for training.
Your key is one form away
Create an account, copy the key, change the base URL. That is the whole setup.