← mrnine.net
API Gateway docs
OpenAI-compatible. Endpoint: https://api.mrnine.net/v1. Key dạng sk-mrnine-*, tạo trong Dashboard.
Endpoints
POST /v1/responses— chuẩn mới, dùng bởi Codex CLI (wire_api = "responses").POST /v1/chat/completions— OpenAI SDK / Cursor / Claude Code / mọi client OpenAI cũ. Hỗ trợstream=true.GET /v1/models— list model active.GET /v1/usage/me— balance + usage 30 ngày.GET /health— public, không cần auth.
Models đang bật (1)
claude-opus-4-8curl — chat completions stream
bashcurl -N https://api.mrnine.net/v1/chat/completions \
-H "Authorization: Bearer sk-mrnine-..." \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4",
"messages": [{"role":"user","content":"đếm từ 1 đến 5"}],
"stream": true
}'Python — OpenAI SDK
pythonfrom openai import OpenAI
client = OpenAI(
base_url="https://api.mrnine.net/v1",
api_key="sk-mrnine-...",
)
# Chat
r = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "hi"}],
stream=True,
)
for chunk in r:
print(chunk.choices[0].delta.content or "", end="")
# Responses (mới — multi-turn server-side)
r = client.responses.create(model="gpt-5.4", input="hi")
print(r.output_text)Codex CLI
Sửa ~/.codex/config.toml:
tomlmodel_provider = "MrNine"
model = "gpt-5.4"
review_model = "gpt-5.4"
model_reasoning_effort = "xhigh"
model_context_window = 1000000
[model_providers.MrNine]
name = "MrNine"
base_url = "https://api.mrnine.net"
wire_api = "responses"
requires_openai_auth = trueSet env trước khi chạy:
bashexport OPENAI_API_KEY=sk-mrnine-...Cursor / Claude Code / SDK khác
Mọi client OpenAI-compatible đều dùng được — chỉ cần cấu hình:
- Base URL:
https://api.mrnine.net/v1 - API key:
sk-mrnine-*của bạn - Model: lấy từ
/v1/modelshoặc trang Dashboard
Function calling (tools)
Pass-through hoàn toàn — gateway forward field tools và tool_choice sang upstream. Phía model trả tool_calls, bạn execute tool và gửi roletool message kèm tool_call_id.
pythonfrom openai import OpenAI
import json
client = OpenAI(base_url="https://api.mrnine.net/v1", api_key="sk-mrnine-...")
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Lấy thời tiết hiện tại theo thành phố",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"type": "string", "enum": ["c", "f"], "default": "c"},
},
"required": ["city"],
},
},
}]
messages = [{"role": "user", "content": "Trời Hà Nội hôm nay thế nào?"}]
r = client.chat.completions.create(model="gpt-5.4", messages=messages, tools=tools)
msg = r.choices[0].message
messages.append(msg)
if msg.tool_calls:
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = lookup_weather(args["city"]) # bạn tự implement
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result),
})
r2 = client.chat.completions.create(model="gpt-5.4", messages=messages, tools=tools)
print(r2.choices[0].message.content)tool_choice có thể là "auto", "required", "none", hoặc {"type":"function","function":{"name":"..."}} để ép gọi tool cụ thể.
Embeddings
pythonr = client.embeddings.create(
model="text-embedding-3-small",
input=["Hello", "Xin chào"],
)
for d in r.data:
print(d.index, len(d.embedding))Audio transcription
pythonwith open("audio.mp3", "rb") as f:
r = client.audio.transcriptions.create(
model="whisper-1",
file=f,
language="vi",
)
print(r.text)Image generation
pythonr = client.images.generate(
model="dall-e-3",
prompt="A red panda coding at a desk, studio ghibli style",
size="1024x1024",
n=1,
)
print(r.data[0].url)Image edit (inpainting)
pythonr = client.images.edit(
model="dall-e-2",
image=open("input.png", "rb"),
mask=open("mask.png", "rb"),
prompt="Replace masked area with a sunflower field",
n=1,
size="1024x1024",
)
print(r.data[0].url)Image variations
pythonr = client.images.create_variation(
model="dall-e-2",
image=open("input.png", "rb"),
n=2,
size="1024x1024",
)
for d in r.data:
print(d.url)Moderation (free)
pythonr = client.moderations.create(
model="omni-moderation-latest",
input="Some text to check",
)
print(r.results[0].flagged, r.results[0].categories)Rerank (Cohere/Jina format)
bashcurl https://api.mrnine.net/v1/rerank \
-H "Authorization: Bearer sk-mrnine-..." \
-H "Content-Type: application/json" \
-d '{
"model": "rerank-multilingual-v3",
"query": "AI gateway giá rẻ",
"documents": [
"MrNine bán API key OpenAI compatible",
"Hôm nay trời mưa",
"VietQR thanh toán nhanh"
],
"top_n": 2
}'Text-to-speech
pythonr = client.audio.speech.create(
model="tts-1",
voice="alloy",
input="Xin chào, tôi là MrNine.",
)
r.stream_to_file("hello.mp3")Batch API (50% rẻ hơn)
Upload .jsonl input → tạo batch → poll status → download output. Hoàn thành trong 24h, giá rẻ ~50%.
python# 1. Upload input
f = client.files.create(
file=open("requests.jsonl", "rb"),
purpose="batch",
)
# 2. Tạo batch
batch = client.batches.create(
input_file_id=f.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
print(batch.id, batch.status)
# 3. Poll status
batch = client.batches.retrieve(batch.id)
if batch.status == "completed":
out = client.files.content(batch.output_file_id)
print(out.text)Rate limit & quota
- Default RPM = 60 / phút, TPM = 200K tokens / phút mỗi key.
- Daily token cap = 1M tokens / key (admin tăng theo nhu cầu).
- Vượt → 429 + body OpenAI-style error.
- Hết balance → 402 Payment Required, kèm link tới trang nạp.
Headers ghi log
X-MrNine-Request-Id— request id (mỗi request) để tra log khi hỗ trợ.X-Accel-Buffering: no— server-side, đảm bảo SSE không buffer qua reverse proxy.
Error format
json{
"error": {
"message": "Insufficient balance. Please top up at https://mrnine.net/dashboard/billing",
"type": "insufficient_balance",
"code": "balance_required"
}
}Hỗ trợ
Hỏi nhanh: hello@mrnine.net. Khi báo lỗi, kèm X-MrNine-Request-Id để tra cứu.