API reference
Send a page image, get its text back in reading order, as Markdown or plain text, in the original language and script. One endpoint, one key.
Preview The API serves preview models until Rune-1 launches. $5 free credit for new accounts.
Quick start
Create a key
Sign in to the Runemic Console with GitHub or Hugging Face and create a key under API keys. It is shown once.
Store it
Keep it out of your code:
export RUNEMIC_API_KEY="rk_live_…"Send a page
PNG, JPEG, WebP or GIF, up to 4 MB.
cURL
curl https://api.runemic.com/v1/ocr \ -H "Authorization: Bearer $RUNEMIC_API_KEY" \ -F "file=@page.png" \ -F "model=preview-gemma-4"
Python
import os, requests resp = requests.post( "https://api.runemic.com/v1/ocr", headers={"Authorization": f"Bearer {os.environ['RUNEMIC_API_KEY']}"}, files={"file": open("page.png", "rb")}, data={"model": "preview-gemma-4"}, ) resp.raise_for_status() print(resp.json()["text"])
JavaScript (Node 18+)
import { readFile } from "node:fs/promises"; const form = new FormData(); form.append("file", new Blob([await readFile("page.png")], { type: "image/png" }), "page.png"); form.append("model", "preview-gemma-4"); const res = await fetch("https://api.runemic.com/v1/ocr", { method: "POST", headers: { Authorization: `Bearer ${process.env.RUNEMIC_API_KEY}` }, body: form, }); console.log((await res.json()).text);
Authentication
Every request to /v1/ocr needs your key in the Authorization header: Authorization: Bearer rk_live_…. Keys can be renamed and revoked in the console; a revoked key stops working immediately. Never put a key in a website or app that other people can inspect; call the API from your server.
POST /v1/ocr
Reads one page. Send multipart/form-data with a file, or JSON with an image.
| Parameter | Type | Description |
|---|---|---|
file | file | The page image (multipart). PNG, JPEG, WebP or GIF, max 4 MB. |
image | string | JSON alternative: a base64 data URI (data:image/png;base64,…) or a public https:// URL. |
model | string | Optional. A model ID from GET /v1/models. Default preview-gemma-4. |
format | string | Optional. markdown (default: headings, lists and tables) or text (plain text). |
instructions | string | Optional, up to 300 characters of extra guidance, for example "Only return the table". |
stream | boolean | Optional. true sends the text while the model writes it, as server-sent events (see below). |
Streaming
A full page takes several seconds to write out. With stream set, the response is text/event-stream: delta events carry pieces of text as they are written, then one done event carries the full result, with the same fields as a normal response. If the model fails, you get an error event instead, and you are not charged.
curl -N https://api.runemic.com/v1/ocr \ -H "Authorization: Bearer $RUNEMIC_API_KEY" \ -F "file=@page.png" \ -F "stream=true" event: delta data: {"text": "# Invoice No. 4821\n\nCity"} event: done data: {"id": "req_c28e0b7d9a4f13e65b02", "object": "ocr.result", "text": "# Invoice No. 4821 …", "usage": {…}}
JSON request
curl https://api.runemic.com/v1/ocr \ -H "Authorization: Bearer $RUNEMIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image": "https://example.com/page.jpg", "format": "text"}'
Response
{
"id": "req_7f3a9c2e41b8d05e6a17",
"object": "ocr.result",
"model": "preview-gemma-4",
"text": "# INVOICE No. 4821\n\nCity Library …",
"format": "markdown",
"usage": { "pages": 1, "cost_usd": 0.002, "ms": 2210 },
"balance_usd": 4.998
}
Every response also has an X-Request-Id header that matches the request in the console's Logs.
GET /v1/models
Lists the available models and their price per page. No key needed: curl https://api.runemic.com/v1/models
| Model ID | Based on | Speed | Best for | Per page |
|---|---|---|---|---|
preview-gemma-4default | Google Gemma 4 26B | Balanced | Multilingual pages, right-to-left scripts | $0.002 |
preview-mistral-small | Mistral Small 3.1 24B | Fast | Tables, forms, invoices | $0.003 |
preview-llama-4-scout | Meta Llama 4 Scout | Fastest | Clean printed pages, high volume | $0.002 |
Preview models run on Cloudflare Workers AI. When Rune-1 launches it becomes a new model ID; your key and code stay the same.
OpenAI-compatible API
Already using an OpenAI SDK, or a tool built on one? Point it at https://api.runemic.com/v1 with your Runemic key and send the page as an image in a chat message. POST /v1/chat/completions, GET /v1/models and GET /v1/models/{id} follow OpenAI's format, including streaming and error types.
from openai import OpenAI import base64, os client = OpenAI(base_url="https://api.runemic.com/v1", api_key=os.environ["RUNEMIC_API_KEY"]) image = "data:image/png;base64," + base64.b64encode(open("page.png", "rb").read()).decode() reply = client.chat.completions.create( model="preview-gemma-4", messages=[{"role": "user", "content": [ {"type": "text", "text": "Only return the table."}, # optional: how to transcribe {"type": "image_url", "image_url": {"url": image}}, ]}], ) print(reply.choices[0].message.content)
import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.runemic.com/v1", apiKey: process.env.RUNEMIC_API_KEY }); const stream = await client.chat.completions.create({ model: "preview-gemma-4", stream: true, messages: [{ role: "user", content: [{ type: "image_url", image_url: { url: "https://example.com/page.jpg" } }] }], }); for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
| In the request | What Runemic does with it |
|---|---|
messages | Exactly one image, as an image_url part in a user message: a data: URI or a public https URL (PNG, JPEG, WebP or GIF, up to 4 MB). Text in user messages becomes transcription instructions (up to 300 characters). System and assistant messages are ignored. |
model | A model ID from GET /v1/models. Leave it out to use the default with automatic fallback. |
stream, stream_options.include_usage | Streams chat.completion.chunk events and ends with data: [DONE], like OpenAI. |
format (Runemic extension) | markdown (default) or text. With the OpenAI SDKs, pass it as extra_body={"format": "text"} (Python) or add it to the request object (JavaScript). |
temperature, max_tokens, tools and other chat options | Accepted and ignored: the models only transcribe. |
The answer is the page's text as the assistant message. usage counts tokens; the price is per page, as with /v1/ocr, and is shown in the extra runemic field with cost_usd and balance_usd. Same key, limits and billing as /v1/ocr.
Use with AI assistants (MCP)
Runemic is an MCP server, so Claude, ChatGPT, Codex, Cursor, VS Code and other assistants can read pages for you. The server address is https://mcp.runemic.com/mcp.
Add it to your assistant and it sends you to Runemic to sign in (GitHub or Hugging Face) and allow access. There is no key to copy. Pages are charged to your Runemic credit, with the same prices and limits as the API.
| Assistant | How to add it |
|---|---|
| Claude (web, desktop, mobile) | Settings → Connectors → Add custom connector. Name it Runemic, paste the address, then Connect. |
| Claude Code | Run the commands below, then /mcp and choose Authenticate. |
| Codex (CLI, app, IDE) | Add the lines below; codex mcp login runemic opens the sign-in page. |
| ChatGPT | With developer mode on: Settings → Apps → Create app, paste the address and choose OAuth. |
| Cursor | Add to Cursor, or put the JSON below in ~/.cursor/mcp.json. |
| VS Code | Add to VS Code, or MCP: Add Server → HTTP and paste the address. |
| Anything else | Use the address with the Streamable HTTP transport. Clients that can't sign in can send Authorization: Bearer <your API key> instead. |
# Claude Code: add the server, then run /mcp in Claude Code to sign in claude mcp add --transport http runemic https://mcp.runemic.com/mcp # or install the plugin (the server plus a skill for local files) /plugin marketplace add runemic/runemic.github.io /plugin install runemic@runemic
# Codex: ~/.codex/config.toml [mcp_servers.runemic] url = "https://mcp.runemic.com/mcp" # then sign in once codex mcp login runemic
{
"mcpServers": {
"runemic": { "type": "http", "url": "https://mcp.runemic.com/mcp" }
}
}
| Tool | What it does |
|---|---|
read_page | Reads one page image, given as a public https URL or a data: URI (PNG, JPEG, WebP or GIF, up to 4 MB). Optional format, model and instructions, as in POST /v1/ocr. Returns the text, the model, the cost and your balance. |
upload_page | Shows a Runemic file picker in the chat (in assistants that support MCP Apps, such as Claude and ChatGPT). You choose page images from your device, even several at once, and their text is sent to the conversation. Images are read and not stored. |
list_models | The models available now, with prices. |
get_account | Your credit balance, today's pages and limit, and this month's usage. |
Assistants can't pass an image you attach in a chat to a tool, so Runemic brings its own picker: ask the assistant to read a page and choose the file in the Runemic panel that appears. Where no panel can be shown, give a link instead; in Claude Code and Codex, a file path works too, because the plugin's skill sends the file with the OCR API. To see or disconnect connected apps, open the console and go to Settings → Connected apps.
Errors
Errors return JSON like {"error": {"code": "…", "message": "…"}}. Failed requests are never charged.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_image · unknown_model · invalid_format | Check the request body. |
| 401 | invalid_api_key | Missing, wrong or revoked key. |
| 413 · 415 | too_large · unsupported_type | PNG, JPEG, WebP or GIF up to 4 MB. PDFs are coming soon. |
| 429 | rate_limited · daily_limit | Too many requests per minute, or today's page limit reached. |
| 502 | model_error | The model failed. You are not charged; retry or pick another model. |
| 503 | capacity | Today's shared preview capacity is used up. Try again after 00:00 UTC. |
| 504 | model_timeout | The model you chose didn't answer in time. You are not charged; retry or pick another model. |
Rate limits
| Requests per minute, per account (all keys together) | 20 |
| Pages per day, per account (preview) | 500 |
| Pages per day on an account's first day, or for GitHub accounts less than 14 days old | 50 |
| Image size | 4 MB |
| Active keys per account | 10 |
Need more? Email hello@runemic.com.
Data and privacy
Images are processed by the selected model and returned to you. We never store your images or their text, and never use them for training. We keep request metadata (time, model, pages, cost, latency, status) for your usage and billing. Read the privacy notice.
Changelog
- 1 Oct 2026: MCP server at
https://mcp.runemic.com/mcpfor Claude, ChatGPT, Codex, Cursor and VS Code, with sign-in, plus plugins for Claude Code and Codex. - 30 Sep 2026: OpenAI-compatible
POST /v1/chat/completions. Without amodel, another model takes over automatically if the default fails or doesn't answer; a chosen model that doesn't answer returns504 model_timeout. Request IDs are now random (req_+ 20 characters). - 25 Sep 2026:
streamparameter: get the text while it is being written. Removedpreview-qwen-3.8. - 24 Sep 2026: public preview. Four preview models,
formatandinstructionsparameters, request IDs, console with playground and usage analytics.
Ready to try it?
New accounts get $5 of free credit. No card needed.