Docs · OpenAI-compatible API

Using the API

The base URL is https://api.goedelmachines.com/v1. It speaks the OpenAI API: POST /chat/completions and GET /models. Authenticate with a key from the Keys page, sent as Authorization: Bearer sk-gm-free-….

The free tier is paid for with data. We keep the prompts and completions you send with free keys, people at Gödel Machines may read them, and we may use them (separated from your account) to train and improve our models. Don't send anything secret or personal. You can delete your account and ask us to delete your data at any time. Details in the privacy policy.

Quickstart

shell · curl
curl https://api.goedelmachines.com/v1/chat/completions \
  -H "Authorization: Bearer $GOEDEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "deepseek/deepseek-v4.1-flash",
       "messages": [{"role": "user", "content": "Hello!"}]}'

List the model with GET /v1/models.

Signed in? Try it in the Playground: chat with the model in your browser, no code needed.

OpenAI SDK

Python:

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.goedelmachines.com/v1",
    api_key=os.environ["GOEDEL_API_KEY"],
)

resp = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)

JavaScript / TypeScript:

javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.goedelmachines.com/v1",
  apiKey: process.env.GOEDEL_API_KEY,
});

const resp = await client.chat.completions.create({
  model: "deepseek/deepseek-v4.1-flash",
  messages: [{ role: "user", content: "Hello!" }],
});
console.log(resp.choices[0].message.content);

Connect your coding agent in one command

The installer finds the coding agents on your machine, gets you a key through your browser (free or paid, your choice) and configures each agent to use DeepSeek V4.1 Flash here. It backs up every file before changing it, and --uninstall removes what it added.

shell
curl -fsSL https://inference.goedelmachines.com/install.sh | sh

It configures OpenCode, Codex CLI, Claude Code, Aider, Crush, Goose, Continue, oh-my-pi and pi, and prints setup steps for Kilo Code, Cline and Roo Code. The key is saved once in ~/.config/goedel/api_key. The installer says which key type (free or paid) it set up. OpenCode, Claude Code, Crush, Continue, oh-my-pi and pi also show it in the model name, and Codex CLI and Goose in the provider name; Aider and the manual steps for Kilo Code, Cline and Roo Code don't show it. Use --dry-run to see the changes first, --list to see where each agent's settings go, and --new-key to sign in again for a new key, for example to switch to a paid key. You can read the script at /install.sh before running it.

Claude Code gets its own settings file and your ~/.claude is not touched. Start it with the line below; plain claude still uses your own account.

shell · Claude Code
claude --settings ~/.config/goedel/claude-code.json

Get a key from an agent or script

An agent, installer or script can get a key without a browser of its own, the way gh auth login works: it asks for a code, you approve the code while signed in, and it collects the key. When you approve you choose the key: free (prompts are stored, under the free-tier terms) or paid (zero data retention, drawing on your credit; it needs a positive balance). Either way it is an ordinary key: it shows on your Keys page and counts towards your 5 keys.

  1. POST /api/device/code on this site, optionally with {"client_name": "my-agent"}. The answer has a user_code (like ABCD-1234), a verification_uri_complete to show the user, a device_code to keep secret, expires_in (600 seconds) and interval (5 seconds).
  2. The user opens the link, signs in, and approves a free or a paid key. The page names the client so they know what they approve.
  3. POST /api/device/token with {"device_code": "..."} every interval seconds. Until the user answers it returns 400 with authorization_pending; then 200 with api_key, base_url, model, key_name and tier ("free" or "paid"; the key starts sk-gm-free- or sk-gm-paid- to match). The key is returned once.
shell · device login
SITE=https://inference.goedelmachines.com
resp=$(curl -s -X POST $SITE/api/device/code \
  -H "Content-Type: application/json" -d '{"client_name": "my-agent"}')
echo "Open $(echo "$resp" | jq -r .verification_uri_complete) and approve"
code=$(echo "$resp" | jq -r .device_code)
wait=5
while sleep $wait; do
  out=$(curl -s -X POST $SITE/api/device/token \
    -H "Content-Type: application/json" -d "{\"device_code\": \"$code\"}")
  key=$(echo "$out" | jq -r '.api_key // empty')
  [ -n "$key" ] && break
  case $(echo "$out" | jq -r .error) in
    authorization_pending|key_limit|no_credit) ;;
    slow_down) wait=$(echo "$out" | jq -r .interval) ;;
    *) echo "$out" | jq -r .error_description; exit 1 ;;
  esac
done
export GOEDEL_API_KEY=$key
error (status 400)What to do
authorization_pendingKeep polling at the interval.
slow_downPolling too fast: use the larger interval in the answer.
key_limitThe user has 5 keys. Ask them to revoke one; polling may go on until the code expires.
no_creditA paid key was approved but the balance ran out before collection. Ask them to add credit; polling may go on until the code expires.
access_deniedThe user declined. Stop.
expired_tokenTen minutes passed. Start again with a new code.
invalid_grantUnknown code, or the key was already collected. Start again.

Every error carries an error_description to show the user. Both endpoints are rate-limited per address (429 with Retry-After). Agents can read all of this as plain text at /llms.txt.

Zero data retention (paid keys and routers)

There is one endpoint for everyone: https://api.goedelmachines.com/v1. The key you send decides the data policy.

KeyWhere you get itWhat we keep
Free key (sk-gm-free-…; older keys may start sk-gm-)This console, on the Keys pagePrompts and completions are kept. People at Gödel Machines may read them, and we may use them, separated from your account, to train and improve our models. Free tier policy
Paid key (sk-gm-paid-…)This console: add credit on Billing, then create a paid key on the Keys pagePrompts and completions are not stored and never used for training. We keep only request metadata, deleted after 30 days. Privacy policy
OpenRouter†, Hugging Face†Through those platformsPrompts and completions are not stored and never used for training. We keep only request metadata, deleted after 30 days. Privacy policy

Every response carries a header that states which policy covered it: X-Data-Policy: retained for free keys, X-Data-Policy: none for paid keys and the platforms.

shell · check the header
curl -s -D - -o /dev/null https://api.goedelmachines.com/v1/chat/completions \
  -H "Authorization: Bearer $GOEDEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "deepseek/deepseek-v4.1-flash", "max_tokens": 1,
       "messages": [{"role": "user", "content": "Hi"}]}' \
  | grep -i x-data-policy

x-data-policy: retained

To use the API without retention, use a paid key (or OpenRouter† or Hugging Face†). With a free key you can delete your account and ask us to delete your data at any time.

† Coming soon.

Student pass

Free, for a university email: sign in with an address at a domain ending in ac.in, edu or edu.in (alumni addresses don't qualify), and your free keys get the Student pass on their own. It is the free tier with 3× its daily limits and 4 requests at once:

Streaming

Set stream=True to get server-sent events. While a long prompt is being processed we send keep-alive comments, so the connection stays open. Ask for include_usage to get token counts in the last chunk.

python · streaming
stream = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Write a haiku about GPUs."}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:
        print("\n", chunk.usage)

Tool calling

Pass tools and, if you want to force a choice, tool_choice.

python · tools
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

resp = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Weather in Hyderabad?"}],
    tools=tools,
)
call = resp.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)

Reasoning

Reasoning is on by default and comes back in reasoning (delta.reasoning when streaming), separate from the answer in content. Reasoning tokens count as output. To turn it off, send "chat_template_kwargs": {"thinking": false} in the request body (extra_body in the OpenAI SDK).

python · reasoning off
resp = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Hello!"}],
    extra_body={"chat_template_kwargs": {"thinking": False}},
)

Model

DeepSeek V4.1 Flash with its original weights (FP8, with FP4 experts), served on our own NVIDIA RTX PRO 6000 Blackwell GPUs in Hyderabad, India. deepseek-v4.1-flash is also accepted as the model id.

Model idContextPlan maximum outputFeatures
deepseek/deepseek-v4.1-flash1M-token context (1,048,576 tokens)235,929Streaming, tool calling, reasoning (on by default, can be turned off)

Prompt caching is automatic: repeated prompt prefixes, such as a long chat history, are served from cache and answer faster.

Errors

StatusMeaningWhat to do
400Bad requestCheck the request body.
401Missing or invalid keySend a valid key from the Keys page.
402Paid key: balance used upAdd credit on the Billing page.
413Request too large (body limit 32 MiB (33,554,432 bytes))Send a smaller request.
429Over a limit, or the service is at capacityWait for the Retry-After header, then retry with backoff.

Context and payload limits

1M-token context (1,048,576 tokens). Input and generated output share this window. Output, concurrency, request-rate and daily allowances depend on your plan: see the public Free, Student and Paid limits.

The public endpoint currently accepts request bodies up to 32 MiB (33,554,432 bytes). The full JSON body counts, including base64 screenshots, message history and tool outputs. This byte limit is separate from the model's token context window.

The browser Playground has a separate 4,000,000-byte request limit. Use the API directly for larger screenshots and histories. If a cached connection still reports the previous API limit after an update, reconnect and allow DNS to refresh.

Help

Write to hi@goedelmachines.com.