ChatGPT API Documentation: Quick Reference and First Calls
Most chat APIs share the request format that the ChatGPT API made popular. This page is a short reference for the compatible endpoint on this site, with copy-paste examples.
Last updated

Summary
- Base URL https://api.gptsemfiltro.com/v1, bearer-token auth, model ID uncensored.
- Three methods: chat completions, responses and the model list; balance has its own endpoints.
- Streaming, tool calling and JSON mode are supported; context is 100,000 tokens.
- 429 errors carry a code: rate_limited or concurrency.
What this page covers
If you searched for chatgpt api documentation, you may want OpenAI's own docs for OpenAI's own models. This page is something else: a working reference for an OpenAI-compatible API hosted on this site. It runs one open-weight model, uncensored, tuned to answer without content refusals for lawful adult use. It is not the official API of OpenAI or any other vendor.
The request and response shapes follow the familiar OpenAI format, so the official SDKs and most tools work after you change the base URL and key. The full reference lives in the API documentation; this page gives you the quick version with examples you can run.
Connection basics and a first call
Connection basics
| Item | Value |
|---|---|
| Base URL | https://api.gptsemfiltro.com/v1 |
| Authentication | Authorization: Bearer YOUR_KEY |
| Model ID | uncensored |
| Chat endpoint | POST /v1/chat/completions |
| Responses endpoint | POST /v1/responses |
| Model list | GET /v1/models |
| Balance | GET /v1/balance or GET /v1/dashboard/billing/credit_grants |
| Max request body | 8 MB |
| Context window | 100,000 tokens, prompt plus completion |
Get a key on the API key page. New users can claim a $0.50 trial there with one click; it is valid for 7 days and needs no payment. You can regenerate a key at any time, and accounts that have topped up can hold up to 5 keys, label them and revoke any.
Your first call
curl https://api.gptsemfiltro.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"messages": [
{"role": "system", "content": "You answer in plain language."},
{"role": "user", "content": "What is a context window?"}
],
"temperature": 0.7
}'
from openai import OpenAI
client = OpenAI(base_url="https://api.gptsemfiltro.com/v1", api_key="YOUR_KEY")
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "You answer in plain language."},
{"role": "user", "content": "What is a context window?"},
],
)
print(resp.choices[0].message.content)
print(resp.usage)
The reply holds choices[0].message.content and a usage object with prompt and completion token counts.
Request parameters
The parameters you will use most:
model: alwaysuncensored.messages: a list of objects withrole(system,user,assistantortool) andcontent.max_tokens: optional. If you leave it out, the completion can use the rest of the 100,000-token window.temperature,top_p,stop,seed,frequency_penalty,presence_penalty: passed through to the model.stream: set totruefor server-sent events, with usage at the end.toolsandtool_choice: describe functions the model may call.response_format:{"type": "json_object"}turns on JSON mode.
Not available: image, audio or video generation, embeddings and fine-tuning. The service handles text only.
The roles work as in the OpenAI format. A system message sets behaviour for the whole chat, user messages carry the person's input, assistant messages hold earlier replies and tool messages return function results. The API keeps no memory between calls, so every request must include the history you want the model to see. Prompt and completion share the 100,000-token window, which means a long history leaves less room for the answer.
Streaming, tool calling and JSON mode
Streaming
Set stream to true and read the events as they come. Each chunk has a small delta of text, and usage arrives at the end.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.gptsemfiltro.com/v1",
apiKey: process.env.API_KEY,
});
const stream = await client.chat.completions.create({
model: "uncensored",
messages: [{ role: "user", content: "List five uses of a context window." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
A streamed request keeps its concurrency slot until the stream ends, so close streams you no longer need.
Tool calling and JSON mode
Declare functions with tools. When the model wants one, the reply has tool_calls instead of text. You run the function and send the result back as a message with role: "tool".
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.gptsemfiltro.com/v1", api_key="YOUR_KEY")
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
messages = [{"role": "user", "content": "What is the weather in Lisbon?"}]
first = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
call = first.choices[0].message.tool_calls[0]
messages.append(first.choices[0].message)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps({"city": "Lisbon", "temp_c": 21}),
})
final = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
print(final.choices[0].message.content)
In production, check that tool_calls exists before reading it, since the model may answer in plain text. For structured output without tools, add "response_format": {"type": "json_object"} and say in the prompt that you want JSON.
Limits, errors and headers
| Limit | Full key | Trial key |
|---|---|---|
| Concurrent requests | 8 | 2 |
| Requests per minute | 300 | 60 |
| Body size | 8 MB | 8 MB |
Over a limit, the API returns HTTP 429. The error code rate_limited means too many requests per minute; concurrency means too many at once. On temporary overload you also get 429, with a Retry-After: 5 header. Failed or refused requests are not charged.
Useful response headers: X-Request-Id (quote it when contacting support), X-Balance-USD, X-RateLimit-Limit-Requests and X-RateLimit-Limit-Concurrency.
A small retry helper in Node, which waits for the time in Retry-After and backs off a little more on each attempt:
async function chat(messages, tries = 4) {
for (let n = 0; n < tries; n++) {
const res = await fetch("https://api.gptsemfiltro.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ model: "uncensored", messages: messages }),
});
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") || 5);
await new Promise(function (r) { setTimeout(r, wait * 1000 * (n + 1)); });
continue;
}
return res.json();
}
throw new Error("still rate limited");
}Moving existing code and checking your balance
Moving existing code to this endpoint
If your code already calls an OpenAI-style chat endpoint, the migration is small. Change these three values and leave the rest:
- The base URL becomes
https://api.gptsemfiltro.com/v1. - The key becomes the one from the API key page.
- The model becomes
uncensored.
Then check what your code relies on. Anything text-based and chat-shaped carries over: system prompts, history, streaming, tool calls and JSON mode. Anything else does not exist here. There is no image generation, no audio or video, no embeddings and no fine-tuning, so code that calls those routes needs another provider.
The Responses endpoint is also available, for clients that prefer that format:
curl https://api.gptsemfiltro.com/v1/responses \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "uncensored", "input": "Summarise what a context window is in one sentence."}'
Test it before you ship, because different models behave differently on the same prompt. Refusals, tone and length can all change, so rerun the prompts you care about.
Checking your balance from code
Balance is available in three ways. Every response has an X-Balance-USD header. You can also call GET /v1/balance, or the OpenAI-style GET /v1/dashboard/billing/credit_grants, which some dashboards already know how to read.
curl https://api.gptsemfiltro.com/v1/balance \
-H "Authorization: Bearer YOUR_KEY"
A useful pattern is to read the header after each call, store it, and alert when it falls under a threshold you pick. Since credit is prepaid and never expires, a low balance is a prompt to top up, not a deadline.
Pricing at a glance
Input costs $0.15 per 1M tokens and output $0.50 per 1M tokens, drawn from prepaid credit. Example: 3,000 input and 600 output tokens cost 3,000 x $0.15 / 1M + 600 x $0.50 / 1M = $0.00045 + $0.0003 = $0.00075. Top-ups are whole amounts from $20 to $500 with bonuses of +5% from $50, +10% from $100 and +15% from $200, paid in USDT (TRC20) or USDC (Base). More detail is on the pricing page. Prompts are not used for training.
Troubleshooting checklist for a first integration
Most failed first calls come from a short list of causes. Work through it in order before you suspect the service.
- Status 401. The key is missing or mistyped. Print the header your client really sends and compare it with
Authorization: Bearer YOUR_KEY. If the key was pasted into a public place, regenerate it on the API key page; the old key stops working at once. - Status 404. The path is wrong. The base URL ends in
/v1, and the SDK adds/chat/completionsitself. If you call the API with plain HTTP, write the full path. - An error about the model. The only model ID is
uncensored. A name copied from another provider's docs will not match.GET /v1/modelslists what the key can use. - A very large request fails. The body limit is 8 MB. Long histories are better trimmed or summarised long before they get near that size, and the 100,000-token window is shared by prompt and completion anyway.
- Intermittent 429. Read the error code.
concurrencymeans too many calls at once, so lower your worker count.rate_limitedmeans too many per minute. ARetry-After: 5header means temporary overload, and a short wait fixes it. - Replies cut off. If you set
max_tokens, the reply stops there andfinish_reasonreadslength. Raise the cap or remove it.
Keep the X-Request-Id value from any call you cannot explain. It is the fastest way to point to one exact request when you write to support.
More guides
Frequently asked questions
Is this the official ChatGPT API?
No. It is an independent hosted open-weight model with an OpenAI-compatible interface. It is not operated by OpenAI.
Which endpoints are supported?
POST /v1/chat/completions, POST /v1/responses and GET /v1/models, plus balance endpoints at /v1/balance and /v1/dashboard/billing/credit_grants.
Do I need a different SDK?
No. The official OpenAI SDKs for Python and Node work after you change the base URL, key and model name.
How do I check my remaining credit?
Read the X-Balance-USD header on any response, or call GET /v1/balance.
Get your API key
Register, copy the key, and update your base URL. Setup is complete.