Migrating to Gopuram
Swap any OpenAI-compatible provider for Gopuram — base URL, models, images, OCR, and the differences that matter.
Gopuram speaks the OpenAI wire format, so migrating from OpenAI, OpenRouter, or any OpenAI-compatible provider is a base URL + API key swap for chat, and small, mechanical changes for images and documents. This page is the complete reference for performing that swap.
The two-line swap
from openai import OpenAI
client = OpenAI(
base_url="https://api.gopuram.net/v1", # was: your old provider
api_key=os.environ["GOPURAM_API_KEY"], # sk-gpm-…
)
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://api.gopuram.net/v1',
apiKey: process.env.GOPURAM_API_KEY, // sk-gpm-…
});
Everything below is what to check after the swap, endpoint by endpoint.
Model IDs
Model ids are vendor/model (openai/gpt-5.2, anthropic/claude-sonnet-5,
google/gemini-3.7-flash). Map your old ids against the live catalog:
curl -s https://api.gopuram.net/v1/models | jq -r '.data[].id'
Pricing shapes in the catalog tell you the modality: pricing.prompt/
pricing.completion (per token, chat), pricing.image (per image),
pricing.page (per page, OCR). Never hardcode the list — it changes.
Chat completions
POST /v1/chat/completions — streaming and non-streaming, tools, vision
input (image_url content parts, data URLs included), structured outputs,
and the OpenRouter-style reasoning request object with reasoning deltas
in the stream.
Differences that matter when migrating:
- Stateless only. There are no server-side threads or conversation ids — send the full message history each call. If your old provider managed state, move that to your client.
- Cost is in-band. The final chunk (and every non-streamed response)
carries
usage.cost— the exact billed USD. Delete any code that made a second metering call or estimated cost from token counts. - Wrong-endpoint 400s help you. Sending an image or OCR model to chat
returns a
400naming the correct endpoint.
Image generation
POST /v1/images/generations with {model, prompt, n?, size?} — the OpenAI
client.images.generate() shape.
- Responses are
b64_jsononly.response_format: "url"returns a400(hosted artifact URLs arrive in a later phase). If your old code downloaded from a URL, replace it with a base64 decode — this also removes a network round trip and works in sandboxed/native apps. - Remixing is
POST /v1/images/edits(multipart, OpenAIclient.images.edit()compatible):imagefile(s) up to 8MB each +prompt. Models with theREFERENCEScapability in the catalog accept it; the rest return a clear400. - Cost is per image (or token-billed for the gpt-image family), exact, in
usage.cost.
OCR & documents
POST /v1/ocr with {model: "mistral/mistral-ocr", document: {...}}:
- PDFs:
{"type": "document_url", "document_url": "data:application/pdf;base64,…"}— https URLs work too; base64 data URLs are fully supported, so no file hosting is needed. - Single images:
{"type": "image_url", "image_url": "data:image/png;base64,…"}. - Response:
pages[].markdown(+usage.cost, billed per processed page).
Light OCR also works through chat with any vision model — see OCR & document extraction.
No public URLs required — native apps
Every input path accepts inline bytes: chat vision takes data URLs, image
edits take multipart file uploads, OCR takes base64 data URLs. Every output
returns inline bytes (b64_json, markdown). An iOS/macOS/desktop app never
needs to host a file at a public URL to use any Gopuram endpoint. There is
deliberately no separate file-upload step in v1 — send the bytes with
the request.
Keys, credits, errors
GET /v1/key— the key's limits and remaining allowance;GET /v1/credits— account balance.- Errors are OpenAI-shaped:
{"error": {"message", "type", "code", "param"}}. Codes to handle:insufficient_credits(top up),rate_limited/too_many_concurrent(respectRetry-After),model_not_found,model_not_allowed(key allowlist or free tier). - Every response carries
X-Gopuram-Request-Id— log it; support can trace any request by it.
Migration checklist
- Swap
baseURLtohttps://api.gopuram.net/v1and set thesk-gpm-…key. - Map model ids against
GET /v1/models; remove any hardcoded catalogs. - Chat: delete provider-specific cost/metering calls — read
usage.cost. - Images: replace URL downloads with base64 decoding; move remix flows to
/v1/images/editsmultipart. - Documents: point OCR flows at
/v1/ocrwith data-URL documents. - Smoke test: one streamed chat call, one image generation, one edit with a
reference image, one OCR call — confirm each response's
usage.costmatches your dashboard's ledger.