EN ▾
Get API key

Drop-in uncensored API, zero lock-in.

per 1M input tokens
$0.15
Output tokens / 1M
$0.50
token context
100,000
trial credit
$0.50
requests per minute
300
https://api.openaigatewayapi.com/v1

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

Two server blocks linked by a glowing cable, showing an app switching endpoints by changing one setting

Key points

  1. 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.
  2. Chat completions, streaming, tool calling and JSON mode all work through the normal SDK calls.
  3. Limits are 8 concurrent requests and 300 requests per minute on a full key, so build in a 429 retry.
  4. 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.

  1. Create an account and claim the trial credit on the API key page.
  2. Set the base URL to https://api.openaigatewayapi.com/v1.
  3. Send the key as Authorization: Bearer <key>. The SDKs do this for you when you pass api_key.
  4. Use uncensored as the model ID in every request.
  5. 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 codeMeaningWhat to do
rate_limitedToo many requests per minuteSlow the producer or spread work over the minute
concurrencyToo many requests at onceLower your worker count to 8 or fewer, or 2 on a trial key
429 with Retry-After: 5Temporary overloadWait 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:

  1. Run your existing prompt set against the new endpoint and read the outputs yourself. Automated checks catch format breaks, not tone.
  2. Check that any code parsing JSON still passes with response_format set, and keep a fallback that strips stray text around the object.
  3. Measure the real token counts from usage, because a different model tokenizes text differently and your old estimates may be off.
  4. Set your worker pool to 8 or fewer so that the concurrency cap is never the first thing to fail under load.
  5. 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.

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.

Get API keyhttps://api.openaigatewayapi.com/v1