Quickstart
Ask your Memcode administrator for a router key. It starts withsm-openai-, followed by 32 lowercase hexadecimal characters, and is shown only once when it is created. Keep it in an environment variable on your server—never ship it in frontend JavaScript.
Install the SDK
npm install openaiSet your key
MEMCODE_API_KEYSet the base URL
https://api.memcode.in/v1JavaScript / TypeScript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.MEMCODE_API_KEY,
baseURL: "https://api.memcode.in/v1",
});
const response = await client.responses.create({
model: "gpt-5-mini",
input: "Explain vector databases in one paragraph.",
max_output_tokens: 256,
});
console.log(response.output_text);Python
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["MEMCODE_API_KEY"],
base_url="https://api.memcode.in/v1",
)
response = client.responses.create(
model="gpt-5-mini",
input="Explain vector databases in one paragraph.",
max_output_tokens=256,
)
print(response.output_text)cURL
curl https://api.memcode.in/v1/responses \
-H "Authorization: Bearer $MEMCODE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5-mini",
"input": "Explain vector databases in one paragraph.",
"max_output_tokens": 256
}'Always choose a small explicit output cap. If you omit it, the router reserves budget for 4,096 output tokens before sending the request upstream.
Authentication
Send the router key as a Bearer token on every API request. The key identifies its owner, budget, status, and rate-limit bucket.
Authorization: Bearer $MEMCODE_API_KEY- Keys are case-sensitive and cannot be recovered later.
- Do not put a key in a URL, query string, browser bundle, or log.
- Revoked keys cannot generate, but can still read their final balance.
- Do not use the upstream OpenAI key; use only your Memcode router key.
Endpoints
The router intentionally implements a small, documented subset of the OpenAI API. It is not a transparent proxy for every OpenAI feature.
| Method | Route | Purpose |
|---|---|---|
| POST | /v1/responses | Generate text with the Responses API. |
| POST | /v1/chat/completions | Generate text with Chat Completions. |
| GET | /v1/models | List the four accepted model IDs. |
| GET | /user/balance | Read budget, usage, reservations, and key status. |
Unknown routes and wrong methods return a structured404 unknown_endpoint response.
Responses API
Use POST /v1/responses for new integrations. The router accepts string input or a non-empty array of text messages, function calls, and function-call outputs.
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.MEMCODE_API_KEY,
baseURL: "https://api.memcode.in/v1",
});
const response = await client.responses.create({
model: "gpt-5-mini",
input: "Explain vector databases in one paragraph.",
max_output_tokens: 256,
});
console.log(response.output_text);model
One exact ID from the model table below.
input
Text or supported text/function items.
instructions
Optional string instructions.
max_output_tokens
Integer from 1 to 16,384.
stream
Optional boolean.
tools
Client-defined function tools only.
Chat Completions
Existing text-only Chat Completions clients can usePOST /v1/chat/completions. Messages must be non-empty and text-only.
const completion = await client.chat.completions.create({
model: "gpt-4.1-mini",
messages: [
{ role: "system", content: "Be concise." },
{ role: "user", content: "What is retrieval-augmented generation?" },
],
max_completion_tokens: 256,
});
console.log(completion.choices[0].message.content);- Use
max_completion_tokensfrom 1 to 16,384. - Legacy
max_tokensis normalized unless it conflicts withmax_completion_tokens. nmay be 1–8. Budget reservation scales with output cap × n.- Function tools are supported; hosted provider tools are not.
Streaming
Set stream: true. The router forwards OpenAI's SSE stream while inspecting the final usage event so it can settle the reservation.
const stream = await client.responses.create({
model: "gpt-5-mini",
input: "Count from one to five.",
max_output_tokens: 64,
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
}
}Settlement happens after the stream completes. The reserved balance can remain visible briefly. If the client disconnects, the stream fails, or usage is missing, the router conservatively charges the full reservation.
Models and ledger pricing
Only these exact IDs are accepted. The router does not rewrite models or silently fall back to another model.
| Model IDs | Input / 1M | Cached / 1M | Output / 1M |
|---|---|---|---|
| gpt-5-mini, gpt-5-mini-2025-08-07 | $0.25 | $0.025 | $2.00 |
| gpt-4.1-mini, gpt-4.1-mini-2025-04-14 | $0.40 | $0.10 | $1.60 |
These are router-configured ledger rates, not a guarantee of the final OpenAI invoice. Pricing can change, and calls made directly to OpenAI are outside this router's budget.
Check a key balance
Use the dashboard's Check Balance page or call the endpoint directly. This request does not call OpenAI or reserve budget, but it does consume request rate-limit capacity.
curl https://api.memcode.in/user/balance \
-H "Authorization: Bearer $MEMCODE_API_KEY"{
"budgetLimit": 10,
"balanceUsed": 1.25,
"balanceReserved": 0.05,
"remaining": 8.7,
"isActive": true
}How budgets work
Before contacting OpenAI, the router estimates a conservative maximum cost and atomically reserves it in PostgreSQL. A request is admitted only while:
balance_used + balance_reserved ≤ budget_limit- The output cap, number of choices, body size, and configured rates determine the reservation.
- Concurrent requests reserve under a row lock, so they cannot collectively pass the key budget.
- Valid token usage settles the actual charge and releases the unused portion.
- Missing usage, ambiguous upstream delivery, timeout, or stream interruption charges the full reservation.
This is a hard router-ledger limit, not a guarantee about the upstream invoice. Direct OpenAI calls, stale pricing, and costs outside this gateway are not included.
Compatibility and limits
Request body
Valid UTF-8 JSON, currently up to 256 KiB.
Output
Default 4,096; explicit maximum 16,384 tokens.
Content
Text and client-defined function tools only.
Service tier
Absent or default; the router forces default.
Queries
Query parameters are rejected.
Timeout
Current upstream timeout is 120 seconds.
Not supported
- Images, audio, files, and non-text modalities.
- Built-in/provider tools, web search, or web_search_options.
- Background responses, hosted prompts, or conversations.
- previous_response_id, prediction, or non-default service tiers.
- x-goog-* headers and browser calls from any Origin other than https://router.memcode.in. Server-side calls without an Origin header are accepted.
Fields outside this documented subset are not a compatibility promise. OpenAI may accept or reject forwarded fields.
Rate limits
Requests pass through pre-authentication and authenticated token buckets. Limits are configurable, so clients should react to response headers instead of hard-coding current values.
Per key
Burst 20; refill 5 every 10 seconds.
Global traffic
Burst 200; refill 50 every 10 seconds.
Per presented key before auth
Burst 60; refill 20 every 10 seconds.
Global auth attempts
Burst 500; refill 100 every 10 seconds.
Useful headers
x-ratelimit-remaining-requestsx-ratelimit-remaining-global-requestsx-ratelimit-reset-requests-msretry-afteron retryable limiter responsesx-router-request-idon every response
Errors
Errors use an OpenAI-style envelope with a stable router code.
{
"error": {
"message": "The requested model is not supported.",
"type": "invalid_request_error",
"param": "model",
"code": "unsupported_model"
}
}| Status / code | Meaning | Action |
|---|---|---|
| 400 invalid_request | Fix the malformed or unsupported request field. | Follow the message and code; retry only when appropriate. |
| 400 unsupported_model | Choose one exact model ID from this page. | Follow the message and code; retry only when appropriate. |
| 401 invalid_api_key | Check the key or ask the administrator for a new one. | Follow the message and code; retry only when appropriate. |
| 403 key_inactive | The key was revoked or deactivated; do not retry generation. | Follow the message and code; retry only when appropriate. |
| 413 request_too_large | Reduce the JSON body below the configured limit. | Follow the message and code; retry only when appropriate. |
| 415 unsupported_media_type | Send Content-Type: application/json. | Follow the message and code; retry only when appropriate. |
| 429 budget_exceeded | Reduce the output cap or ask for a larger budget. | Follow the message and code; retry only when appropriate. |
| 429 rate_limit_exceeded | Honor Retry-After and retry with exponential backoff. | Follow the message and code; retry only when appropriate. |
| 502 upstream_error | Retry carefully; delivery can be ambiguous and budget may settle. | Follow the message and code; retry only when appropriate. |
| 503 budget_unavailable | The budget ledger is unavailable; retry later. | Follow the message and code; retry only when appropriate. |
| 504 upstream_timeout | The upstream timed out; inspect the request ID before retrying. | Follow the message and code; retry only when appropriate. |
Include x-router-request-id when asking the operator for help. Upstream error bodies are sanitized and are not passed through verbatim.
Security and reliability
- Keep router keys only in server-side secrets.
- Set a small explicit output-token cap.
- Use HTTPS and never disable TLS verification.
- Honor 429 Retry-After and use bounded backoff.
- Log x-router-request-id, never the API key.
- Check balance before large or parallel jobs.
- Do not assume retries are idempotent.
- Rotate a key immediately if it is exposed.
For SDK installation and general OpenAI API concepts, see the official OpenAI quickstart. Memcode's supported subset and budget rules on this page take precedence for this gateway.