Chat models, images, transcription, web search and a page checker, all at https://api.makemode.eu. You get one key and one prepaid balance in euros. Every request runs on EU servers.
An account, a balance and a key. Open account.makemode.eu, add credit, and create a key. The key starts with sk-gw- and is shown once, so copy it when it appears. You can revoke it on the same page at any time.
The examples below read the key from an environment variable. Set it once in your terminal:
Then check that it works. This call is free and shows your balance:
Already using the terminal setup? It created a key for you. The same key works here.
Put the key in an Authorization: Bearer header. Clients built for the Anthropic API send it as x-api-key instead, and the gateway accepts that too. Both carry the same sk-gw- key.
To use an OpenAI SDK, set its base URL to https://api.makemode.eu/v1 and its API key to your sk-gw- key. For an Anthropic SDK or Claude Code, set the base URL to https://api.makemode.eu.
Browsers can call the gateway directly, because it answers cross-origin requests. A key in page source is readable by anyone who opens the page, so keep it on a server you run.
| endpoint | how it is charged |
|---|---|
| chat and messages | Per token. The provider's price in euros times 1.5. A model's input and output tokens have separate rates. For GLM-5.3 that is about €2.70 per million input tokens and €8.25 per million output tokens. |
| images | About €0.02 per picture. |
| transcription | €0.01 per minute of audio. |
| look | The cost of one small vision-model call, around €0.0004. The reply reports the exact amount. |
| search, read, models, balance | Free. |
A call that fails before it produces anything is not charged; a chat answer cut off partway is charged for the tokens it produced. Calls that cost money need a balance above zero, and they answer 402 when it runs out. Top up at account.makemode.eu. Images, look and transcription include a costEur field in the reply, so a script can add up its own spend.
The OpenAI chat format. Send a model and a list of messages, and set "stream": true to receive the answer as it is written. Get the model names from /v1/models. If you leave out max_tokens, the gateway sets it to the model's own ceiling.
The reply is the standard OpenAI shape: choices[0].message.content holds the text and usage holds the token counts. When your balance is low, the response carries the header x-makemode-balance-low: 1.
The Anthropic Messages format, for Anthropic SDKs and for Claude Code. The gateway translates your request and sends it to the same EU models as chat. No request on this path goes to Anthropic. Streaming works.
If you ask for a Claude model name, the gateway answers with an EU model instead. When it substitutes one, the response carries x-makemode-served-model with the model that actually ran. Errors on this path use the Anthropic error format.
Lists the models your key can use right now, in the OpenAI list format. Use an id from this list as the model in chat and messages.
Each entry has id, object, created and owned_by. We add context_window, the longest input the model accepts, and a makemode object with a display name, a short description and a multimodal flag. A model that is temporarily unavailable is left out of the list.
Your remaining credit in euros, and a short account of recent spending.
The reply has userId, balanceEur, low (true when the balance is nearly spent) and pace. The pace object shows what you spent today, in the current working session, and on your last request. It can be null.
Searches the web and other sources through MakeMode's own search service, and returns titles, links and short excerpts. Send a query of up to 300 characters.
| field | meaning |
|---|---|
query | Required. Cut off after 300 characters. |
n | How many results you want, 1 to 10. The default is 6. |
sources | Any of web, wikipedia, sourcelibrary, europepmc, fourtu. The default is web and wikipedia. |
The reply has query, sources and results, a list of objects with title, url and snippet (up to 500 characters). When nothing comes back, a note field says so. An empty list can mean the search service is having trouble, so check before you conclude that a topic does not exist.
Fetches one public web page and returns its text with the menus and clutter removed. Send a full http:// or https:// address of up to 2,000 characters.
The reply has url, text and chars. The text stops after 20,000 characters. If the page is private, needs JavaScript or turns readers away, text is empty and a note explains. Search and read share one allowance of 30 requests per minute for each key.
Checks a web page you built. Send its files. The gateway opens them in a real browser on an EU server, takes a screenshot, and a small vision model reports anything visibly broken: a blank page, raw markup, unreadable text, errors in the console.
files maps a file path to its text. It must include index.html. Send at most 200 files and 2 MB of text in total, with relative paths. Each key may make 6 looks per minute.
The reply has ok (true when nothing is wrong), rendered (the page opened in a browser), judged (the vision check answered), problems (a list), a plain-language summary, signals and costEur. If judged is false, the page loaded but nobody checked how it looks, and uncheckedBecause gives the reason. Look again before you trust it.
Makes a picture from a text description, in the OpenAI images format. Ask for one picture at a time.
| field | meaning |
|---|---|
prompt | Required. Cut off after 2,000 characters. |
n | Optional. Must be 1 if you send it. |
ratio | 1:1 (default), 16:9, 3:2 or 4:5. |
size | The OpenAI way to pick a shape: 1024x1024, 1792x1024 or 1024x1792. If you send both, ratio wins. |
response_format | url (default) or b64_json. |
The reply is {"created": …, "data": [ … ], "costEur": …}. With url, the data entry has a url. We store the picture on our EU storage at made.makemode.app, under a long random address. Nobody can guess it, but anyone you give it to can open it. With b64_json, the entry has b64_json (the image, base64 encoded) and content_type, and we store nothing.
Turns speech into text, in the OpenAI transcriptions format. Upload the audio as a multipart form.
| field | meaning |
|---|---|
file | Required. The audio. Keep it under about 15 MB. |
language | Optional. A language code such as nl or en. Leave it out to let the model detect the language. |
response_format | json (default) returns text and costEur. text returns plain text. verbose_json adds language, duration in seconds and segments. |
The audio is held in memory while it is transcribed and is never stored. There is a daily limit of 8 hours of audio for each account.
Errors come back with an HTTP status and a body like {"error":{"code":"insufficient_credits","message":"…"}}. Read code in a script and show message to a person.
| status | code | what to do |
|---|---|---|
| 400 | bad_request | A field is missing or wrong. The message names it. |
| 401 | missing_credential, invalid_api_key | Send the key, or check you copied all of it. Create a new key if you lost it. |
| 402 | insufficient_credits | Your balance is empty. Top up in your account. Image and transcription calls answer 402 with their own codes (image_failed, transcription_failed). |
| 413 | too_large, transcription_failed | Send fewer or smaller files (look), or a shorter recording (transcription). |
| 429 | rate_limited | Wait a minute and try again. Images and transcription also stop at a daily limit. |
| 451 | non_sovereign_blocked | The request would have left the EU, so the gateway refused it. |
| 502, 503 | upstream_unreachable, model_unavailable, image_failed | A provider is down or the model is paused. Try again shortly or choose another model. You are not charged. |
| limit | value |
|---|---|
| search and read | 30 requests per minute, shared, for each key |
| look | 6 per minute, up to 200 files and 2 MB |
| images | one per request, prompt up to 2,000 characters, daily limit |
| transcription | about 15 MB per file, 8 hours of audio per day |
The gateway runs on Scaleway in France. Chat and messages go to models hosted by Scaleway or by Mistral in the EU. Transcription runs on a Whisper model at Scaleway. Images are generated on the EU endpoint of the image provider.
Two things reach beyond the gateway, because they are their job. Search sends your query to the public sources you choose, such as Wikipedia or Europe PMC. Read fetches the web page you name. Everything else stays on EU servers.
Pictures made with url are stored on EU storage and are public to anyone with the address. Pictures made with b64_json and all audio are not stored. More on the sovereignty and your data pages.