arctic
OpenOpen the app
API & CLI

Connect an app or your terminal

Arctic speaks OpenAI's Chat Completions over free model hosts. Keep your SDK, change the base URL, use a free client key.

Base URL
https://www.arctic.qpon/api/v1
StreamingToolsJSON modeImage inputIdempotent retriesauto routing$0 per call

curl

curl https://www.arctic.qpon/api/v1/chat/completions \
  -H "Authorization: Bearer $ARCTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [{"role": "user", "content": "Name three glaciers in Greenland."}],
    "stream": true
  }'

JavaScript · OpenAI SDK

import OpenAI from "openai";

const arctic = new OpenAI({
  baseURL: "https://www.arctic.qpon/api/v1",
  apiKey: process.env.ARCTIC_API_KEY,
});

const r = await arctic.chat.completions.create({
  model: "auto:quality",
  messages: [{ role: "user", content: "Explain permafrost in two sentences." }],
});
console.log(r.choices[0].message.content, r.model);

Python · OpenAI SDK

import os
from openai import OpenAI

arctic = OpenAI(base_url="https://www.arctic.qpon/api/v1", api_key=os.environ["ARCTIC_API_KEY"])

stream = arctic.chat.completions.create(
    model="auto",
    messages=[{"role": "user", "content": "Write a haiku about sea ice."}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

Tool calling

const r = await arctic.chat.completions.create({
  model: "auto",
  messages: [{ role: "user", content: "What's the ice extent today?" }],
  tools: [{
    type: "function",
    function: {
      name: "ice_extent",
      description: "Arctic sea ice extent in million km²",
      parameters: { type: "object", properties: { date: { type: "string" } } },
    },
  }],
});

Vercel AI SDK

import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { streamText } from "ai";

const arctic = createOpenAICompatible({
  name: "arctic",
  baseURL: "https://www.arctic.qpon/api/v1",
  apiKey: process.env.ARCTIC_API_KEY,
});

const result = streamText({ model: arctic("auto:speed"), prompt: "Hello" });

Every call has a receipt

Buffered responses carry an arctic object with the host that served them and what the call would cost on a paid API. Streams end with a : arctic.usage comment that standard clients ignore. GET /api/v1/usage returns the key's totals.

Arctic CLI 0.4

Run a local coding task

One file, no install, Node 18 or newer. Chat, list models, or run an agent in the current folder that lists, reads, searches, writes and runs commands, and asks you first every time.

  • --read-only turns off writing and commands.
  • --yes approves file reads only; writes and commands always ask.
  • Paths outside the folder are refused.
  • Exit codes: 0 done, 2 stopped at the turn limit, 1 error.
curl -fsSLO https://www.arctic.qpon/cli/arctic.mjs
export ARCTIC_API_KEY=arc_live_…
node arctic.mjs doctor
node arctic.mjs models llama
node arctic.mjs ask "What is a nunatak?"
node arctic.mjs run "add a test for the date parser" --model auto:quality

OpenCode

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "arctic": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Arctic",
      "options": { "baseURL": "https://www.arctic.qpon/api/v1", "apiKey": "{env:ARCTIC_API_KEY}" },
      "models": { "auto": {}, "auto:quality": {} }
    }
  }
}

Continue, Cline, Zed, LangChain and LlamaIndex work the same way: an OpenAI-compatible provider with the base URL above.