Try a free model first

You have just made a kn- key and do not know yet whether it answers. One reply from the server settles that, and an empty balance is enough to get it.
So try :free first. That suffix gives you the free version of the same model id, billed at Rp 0, with a per-account limit behind it. The numbers are operator-tuned, so check what is live rather than memorizing anything here.
This is a beginner post, not a Claude Code or n8n setup guide. Once you have an id, point your tool at it with Point your editor at kenari or Point n8n at kenari, and if you already have a provider key, read BYOK through kenari.
What :free means
One model can have two ids. Without the suffix you get the paid version, which comes off your balance, and with :free you get the free version at Rp 0.
An example pair that was in the catalog when we checked:
step-3-7-flash → PAYG, debits balance
step-3-7-flash:free → Rp 0, limited
Both show up on GET /v1/models, and pricing.free on the second is true.
:free is best-effort, and the docs say so plainly: capacity is limited, with no guarantee that speed or availability matches the paid models. Do not make :free a production SLA.
Every account also has a read-only route named kenari-free, which points at free models, costs nothing, and is limited per account. The name is reserved, so you cannot edit or delete it. Send kenari-free as the model value and kenari picks a free id that is currently live.
Limits you can verify
Two things we deliberately do not pin down here: a count of the free models, and an RPM figure as a standing promise. The catalog moves, and the operator can change quota.
What the docs do say, and what you can check yourself:
:freeis billed at Rp 0.- There is a per-minute request limit, per account, across all
:freemodels. - There is a daily allowance with three tiers: Solo (new accounts, before a top-up reaches the threshold), Payer (topped up past that threshold), Subscription (an active plan; some plans carry their own daily quota).
- Current quota, RPM, and the top-up threshold live on the pricing page and
GET /api/public/pricing, because the operator can tune them at any time. - Daily quota used up:
HTTP 429,Retry-Afterheader, reasonfree_quota_daily. RPM used up:429free_quota_rpm. - The daily reset the docs name: 00:00 UTC.
Live snapshot as of this post (20 August 2026, from GET /api/public/pricing): rpm 5, daily 50, next.rpm 10, next.daily 1000, plan.rpm 15, plan.daily 0, threshold_idr 10000. The daily: 0 on plan means there is no daily ceiling at the default Subscription tier, while Solo currently sits at daily 50. Any of that can change tomorrow, so re-read the endpoint rather than treating this paragraph as a contract.
And please do not count how many free models there are, because GET /v1/models answers that for you. llms.txt has already named a count that did not match the live catalog on the same day.
How to pick an id from GET /v1/models

The endpoint is public, so you can read it without a key.
curl https://kenari.id/v1/models
Each entry carries id, owned_by, endpoints, pricing.free, and sometimes tool_call and reasoning, and a bare GET /v1/models returns chat models only, same as OpenRouter, so embeddings and rerank need ?modality=.
A safe way to pick one:
- Find an
idthat ends in:free, or wherepricing.free === true. - Check
endpointsincludeschatif your client uses chat completions. - If your tool is an agent (n8n AI Agent, tool calling), check for
tool_call: true.step-3-7-flash:freehad it when we checked. - Copy the id exactly, because a typo comes back as
model_not_found.
The counts from our own check make that order make sense. Of the 70 entries in the catalog, 61 are chat models. The other nine are text to speech, images, music, and transcription, and nothing in the id itself warns you, so step 2 is what stops you posting a music model to /chat/completions.
Step 3 is sneakier. Of those 61 chat models, 59 can tool call and exactly 2 cannot. Both of the 2 happen to be :free ids, so the only place that step bites is the free lane, which is precisely the lane people try first.
There were 16 :free ids when we checked. Four of them: step-3-7-flash:free, glm-4-7-flash:free, mimo-v2-5:free, hy3:free. Examples, not a fixed list, so use whatever is still in your own response.
For anything that has to work on a Rp 0 account, take a :free id straight out of your own GET /v1/models response. When we checked, step-3-7-flash:free qualified on every count: pricing.free: true, endpoints includes chat, and tool_call: true.
A rough filter:
curl -s https://kenari.id/v1/models \
| python3 -c "import sys,json; d=json.load(sys.stdin);
[print(m['id']) for m in d['data'] if m.get('id','').endswith(':free') or (m.get('pricing') or {}).get('free')]"
Do not plant that list in your code, because a stale id is a harder bug than one extra call.
:free vs PAYG vs BYOK
All three run on the same kn- key, and what separates them is who pays for the tokens.
:free |
PAYG | BYOK | |
|---|---|---|---|
| Key that calls the model | kenari pool | kenari pool | your provider key |
| Debits kenari balance | no | yes, per token | no (tokens) |
| What you need | kn- only |
kn- + balance |
kn- + a key on /byok |
| Limits | RPM + daily quota (operator) | balance; 402 if short |
your provider’s limits |
| When | tests, trying, light load | catalog models, pay Rupiah | provider quota already there |
PAYG per-token prices live on GET /v1/models as micro-Rupiah per 1 million tokens, and we keep them out of this post because those figures are live. Balance top-ups are covered in Pay for tokens with QRIS.
Tokens through your own BYOK key cost Rp 0 on kenari and still get recorded in analytics, which is a different arrangement from :free. The details are in BYOK through kenari.
The kn- key is the same in all three cases. What changes is the model value, or whether a BYOK key is attached.
One curl, no balance
Open API keys in the dashboard, click Create key, copy the kn-..., then send this:
curl https://kenari.id/v1/chat/completions \
-H "Authorization: Bearer kn-..." \
-H "Content-Type: application/json" \
-d '{
"model": "step-3-7-flash:free",
"messages": [{"role": "user", "content": "Halo!"}]
}'
If choices[0].message.content comes back with an answer in it, the connection is live. If not, the status code says why:
401: the key is wrong or truncated. The 401 body is plain text, not JSON.model_not_found: the id is wrong, so take it again fromGET /v1/models.402 insufficient_balance: you are not on:free. Change the id, or add balance.429: readRetry-After. The reason isfree_quota_rpmorfree_quota_daily.
An OpenAI-compatible client points at https://kenari.id/v1, while Claude Code uses the Anthropic protocol and needs https://kenari.id with no /v1. Get the shape wrong and you usually see 405.