ROK Logo
Back to sign in

Developers

Free OpenAI-Compatible API

Chat completions with no API key, no account, and native tool calling — point any OpenAI SDK at ROK and it just works.

ROK is a free agentic AI — it browses the web, works with files, generates images, and reviews code in a single chat, no account required. This is the API behind it: free, keyless, and with native tool calling.

1. Overview — a free OpenAI-compatible API with no key

ROK exposes a public, OpenAI-compatible chat completions API at https://rokremasteredapi.rokteam.org/v1. Point any OpenAI SDK client at it by changing base_url — requests and responses use the same schema as the OpenAI API.

  • No authentication required. This endpoint is public by design — no API key or account required to use it.
  • Native tool calling. tools and tool_choice are forwarded to the engine and tool_calls are surfaced in OpenAI format (streaming and non-streaming). It is a passthrough — your client runs the tools locally and sends results back as role: "tool" messages.
  • Rate limited. 5 requests per minute per IP — excess requests return 429.

2. Authentication

No authentication is required. The official OpenAI SDKs insist on a non-empty api_key, so pass any placeholder string — it is accepted and ignored server-side:

python
from openai import OpenAI

client = OpenAI(
    base_url="https://rokremasteredapi.rokteam.org/v1",
    api_key="unused",  # any non-empty string; not checked server-side
)

3. Available models

GET https://rokremasteredapi.rokteam.org/v1/models returns the list in the standard OpenAI shape ( {"object": "list", "data": [{id, object, created, owned_by}]} ):

ParameterTypeDescription
rok-hermesdefaultROK's standard model. Used when the model field is omitted.
rok-hermes-spicyadult-contentROK's adult-content variant with a fixed server-side personality prompt. Explicit and edgy creative content is allowed, but it still refuses real-world harm — minors, non-consensual content of real people, targeted harassment, and real-world weapons/explosives instructions.
rok-hermes-spicy is an adult-content model
Both the ROK app and this public API allow calling rok-hermes-spicy without an age gate. It still refuses real-world harm (minors, non-consensual content of real people, targeted harassment, and real-world weapons/explosives instructions). Use it accordingly.
The ROK app has a larger in-app lineup
Inside the ROK app, signed-in users can also use ROK's managed cloud models — currently GLM 5.3 Flash and the GPT-5.6 Lunapair — selected from the chat's model picker. These are app-only and metered against ROK's own budget, so they are deliberately NOT exposed on this public API. The models above are the complete public set.

An unknown model name is rejected with a 400 model_not_found error. Omitting model (or sending an empty string) silently defaults to rok-hermes.

4. Quickstart — curl

Non-streaming request:

bash
curl https://rokremasteredapi.rokteam.org/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "rok-hermes",
    "messages": [
      {"role": "user", "content": "Write a haiku about the ocean."}
    ]
  }'

Streaming request — the -Nflag disables curl's output buffering so chunks arrive as they are generated:

bash
curl -N https://rokremasteredapi.rokteam.org/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "rok-hermes",
    "stream": true,
    "messages": [
      {"role": "user", "content": "Tell me a short joke."}
    ]
  }'

List available models:

bash
curl https://rokremasteredapi.rokteam.org/v1/models

5. Quickstart — OpenAI SDK

The official openai SDKs work identically to using real OpenAI — just point base_url at ROK.

Python

python
from openai import OpenAI

client = OpenAI(
    base_url="https://rokremasteredapi.rokteam.org/v1",
    api_key="unused",
)

completion = client.chat.completions.create(
    model="rok-hermes",
    messages=[
        {"role": "user", "content": "Write a haiku about the ocean."}
    ],
)
print(completion.choices[0].message.content)

# Streaming works too:
stream = client.chat.completions.create(
    model="rok-hermes",
    messages=[{"role": "user", "content": "Tell me a joke."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

JavaScript / TypeScript

ts
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://rokremasteredapi.rokteam.org/v1",
  apiKey: "unused",
});

const completion = await client.chat.completions.create({
  model: "rok-hermes",
  messages: [{ role: "user", content: "Hello!" }],
});
console.log(completion.choices[0].message.content);

6. Request parameters

POST https://rokremasteredapi.rokteam.org/v1/chat/completions — all fields except messages are optional.

ParameterTypeDescription
messagesarray (required)Chat messages as [{role, content}]. Roles: system, user, assistant, tool. Tool results use {role: "tool", tool_call_id, content}; assistant messages may carry tool_calls. Empty content is allowed on tool results and on assistant messages with tool_calls.
toolsarrayFunction definitions forwarded to the engine. Returned tool_calls describe CLIENT-side tools — the server never executes them. See the tool-calling callout below.
tool_choicestring | object"auto" (default), "none", or {"type": "function", "function": {"name": "..."}} to force a specific tool.
modelstringModel name. Optional — defaults to "rok-hermes". See Available models.
streambooleanWhen true, return a server-sent-event (SSE) stream instead of a single JSON body.
temperaturenumberSampling temperature. Defaults to 0.7.
top_pnumberNucleus sampling probability mass.
max_tokensintegerMaximum tokens to generate. Values above the cap are clamped, not rejected.
max_completion_tokensintegerAlias for max_tokens. Cannot be combined with max_tokens in the same request.
frequency_penaltynumberPenalizes tokens based on how often they appear so far.
presence_penaltynumberPenalizes tokens that have already appeared in the conversation.
stopstring | string[]Up to a few strings where the model should stop generating.
seedintegerReproducibility hint for the sampler.
stream_optionsobjectSet {"include_usage": true} to append a final usage chunk to a stream.
Tool calling is a passthrough
tools and tool_choice are forwarded to the engine and tool_calls are returned in OpenAI format — but the server never executes tools. Run them on the client (files, commands, etc.) and send each result back as a role: "tool" message with the matching tool_call_id, then continue the conversation.
max_tokens is capped
max_tokens is clamped to a sane ceiling (4,096 by default) rather than forwarded as-is — requesting more never errors, it just generates up to the cap.

7. Streaming format

With stream: true the response is a server-sent-event (SSE) stream of chat.completion.chunk objects. The first chunk carries the role; subsequent chunks carrydelta.content; a final chunk reports finish_reason; and the stream always terminates with data: [DONE].

raw SSE
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755461120,"model":"rok-hermes","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755461120,"model":"rok-hermes","choices":[{"index":0,"delta":{"content":" world"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755461120,"model":"rok-hermes","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

Pass stream_options: {"include_usage": true} to receive one final usage chunk ( "choices": [] with a usage field) just before [DONE].

8. Errors

Errors follow the OpenAI shape: {"error": {"message", "type", "param", "code"}}.

json
{
  "error": {
    "message": "The model 'gpt-4o' does not exist or is not accessible via this API. Available models: rok-hermes, rok-hermes-spicy.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_not_found"
  }
}
Statuserror.typeWhen
400invalid_request_errorMalformed body, empty messages, unsupported role or empty content, invalid model name, or misuse of max_tokens/max_completion_tokens.
429rate_limit_errorRate limit exceeded (5 requests/minute per IP). Includes Retry-After and X-RateLimit-* headers.
502server_errorThe upstream model service returned an error.
503server_errorThe model service is not configured on this server, unreachable, or temporarily rate limited.

429 responses include Retry-After (seconds until the window resets) plus X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers:

json
{
  "error": {
    "message": "Rate limit exceeded: 5 requests per minute per IP. Please slow down and retry.",
    "type": "rate_limit_error",
    "param": null,
    "code": "rate_limit_exceeded"
  }
}

9. Rate limits

The public API allows 5 requests per minute per IP. The client IP is taken from the CF-Connecting-IP header when present (ROK sits behind Cloudflare), falling back to the direct connection address — so the limit applies to the real caller, not a shared proxy.

  • Requests beyond the limit are rejected with 429 rate_limit_error — the request is not queued, and the limit resets on a rolling per-minute window.
  • Streaming counts as a single request regardless of how many chunks it produces.
  • GET /v1/models is deliberately not rate limited — it returns a static list, so SDKs can probe it freely.