Quickstart
Four steps from nothing to a first result. Every endpoint lives under https://api.kaer.ai/v1.
1. Create an account
Sign up at api.kaer.ai. New accounts get $10 of free credit, valid for 90 days.
2. Open search with a top-up
Search is locked on the Free tier and answers 403 tier_required there. Your first top-up of $5 or more moves you to Starter at once: search opens, and the free credit pays for it too.
3. Make a key with the search scope
In the dashboard, open Keys, create a key and tick search. Copy it right away: it starts with kaer_live_ and is shown only once. Keep it on your server.
4. Search
curl https://api.kaer.ai/v1/search \
-H "Authorization: Bearer $KAER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "eu packaging regulation importers",
"lane": "deep",
"num_results": 3
}'The answer names the lane that ran and what it cost:
{
"object": "search.result",
"lane": "deep",
"served_lane": "deep",
"results": [
{
"title": "The PPWR: EU Regulation for a More Circular Economy and Less Packaging Waste",
"url": "https://everwave.de/en/2026/07/13/the-ppwr-eu-regulati…",
"snippet": "The PPWR—Packaging and Packaging Waste Regulation; EU Regulation 2025/40—will take effect on August 12,…",
"source": ["kaer_web"],
"text": "The PPWR (Packaging and Packaging Waste Regulation, EU Regulation 2025/40) will take effect on 12 August 2026 and introd…",
"text_source": "page",
"text_truncated": false
},
{ "title": "Regulation (EU) 2025/40 on packaging and packa…", … },
{ "title": "EU Packaging Regulation Training – Become PPWR…", … }
],
"kaer": { "request_id": "req_…", "cost_usd": 0.003 }
}Authentication
Every call except GET /v1/models needs a key. This page shows you how to send it, which scopes it needs and the order in which a request is checked.
Before you begin
- A key from the dashboard. If you do not have one, follow the Quickstart.
- A list of the endpoints you plan to call, so you can give the key only the scopes they need.
Send your key
Send the key as a bearer token:
Authorization: Bearer kaer_live_...Or send it in an x-api-key header. When Authorization holds a bearer token, it wins.
Choose scopes
Each scope covers the endpoints listed, and works once your tier reaches the one in Opens at.
| Scope | Endpoints | Opens at |
|---|---|---|
models | POST /v1/chat/completions, GET /v1/me | Free |
search | POST /v1/search, POST /v1/search/batch, POST /v1/images | Starter |
maps | GET /v1/maps | Starter |
mail | POST /v1/mail/send, GET /v1/mail/messages/{id} | Build |
Find out why a request was refused
The gateway runs these checks in order and stops at the first one that fails. The error code tells you which check it was.
- The key exists and is not revoked or expired: else 401
invalid_api_key(no key at all:missing_api_key). - The account is active: else 403
account_inactive. - The caller's IP is on the key's allow-list, when it has one: else 403
ip_not_allowed. - The key has the endpoint's scope: else 403
insufficient_scope. - Your tier includes the service: else 403
tier_required. - Rate limits: else 429
rate_limit_exceeded. - A hold for the call's maximum cost: else 402 (
insufficient_credits,monthly_limit_reachedorkey_budget_exceeded).
To limit a key further with allow-lists, budgets, expiry and rotation, see Key security.
Search
api.kaer.ai/v1/search- Scope
search- Tier
- Starter and up
- Price
- $0.0005 to $0.003 per query, see Search pricing
- Free credit
- Yes, once Starter opens it
Search Kaer's own index, alone or racing the live web, and get ranked results.
Before you begin
- A key with the
searchscope. See Authentication. - An account on the Starter tier or above. Search is locked on the Free tier until your first top-up.
- A lane for your query. See Choose a lane.
Request body
| Field | Type | Default | Description |
|---|---|---|---|
queryRequired | string | · | 1 to 512 characters after trimming. |
lane | string | auto | web, fast, deep or auto, case-insensitive. Anything else is a 400. |
num_results | integer | 5 | Results per query, 1 to 25. Numbers outside are clamped; anything that is not a number is a 400. Also read as numResults. |
include_domains | string[] | · | Only results from these hosts or their subdomains, up to 20. The web lane applies it before ranking; the others filter after retrieval. Also includeDomains. |
exclude_domains | string[] | · | Never return results from these hosts or their subdomains, up to 20. Also excludeDomains. |
fields | string[] | · | Result keys to keep, 1 to 20 of title, url, snippet, source, published_date, text, text_truncated, text_source. Leave it out for all of them. Any other name is a 400 invalid_fields. |
Any other field is not applied, and the response lists it in kaer.ignored_params, so a filter you expected never fails silently. The body is limited to 16 KB.
Choose a lane
| Lane | What it does | Per query | Timeout |
|---|---|---|---|
web | Kaer's index alone. Fastest and cheapest. | $0.0005 | 6 s |
fast | The index racing the live web. | $0.001 | 12 s |
deep | Every lane, re-ranked. Results carry the page's text, up to 4,000 characters, when it could be read. | $0.003 | 40 s |
auto | Kaer picks a lane per query. Billed at the lane that served it. | As served | 40 s |
A query that runs past its lane's timeout fails with 504 search_timeout and is not charged.
Not sure which lane to use? Send auto: Kaer picks one per query, and you pay for the lane that served it.
Response
| Field | Type | Description |
|---|---|---|
object | string | search.result |
query | string | The query, trimmed. |
lane | string | The lane you asked for. |
served_lane | string | The lane that ran, and the one billed. |
results[].title | string | Page title. |
results[].url | string | Page address. |
results[].snippet | string | Text from the page that matches the query. |
results[].source | string[] | Which engines returned the page. |
results[].published_date | string | Publication time (RFC 3339), when known. |
results[].text | string | Deep only: the page's main text, up to 4,000 characters. |
results[].text_truncated | boolean | Deep only: the text was cut. |
results[].text_source | string | Deep only: page, or snippet when the site would not serve us the page. |
kaer.request_id | string | Same as x-request-id. |
kaer.cost_usd | number | What the query cost. |
kaer.ignored_params | string[] | Fields that were not applied, when there are any. |
{
"object": "search.result",
"query": "latest ai research",
"lane": "fast",
"served_lane": "fast",
"results": [
{
"title": "…",
"url": "https://…",
"snippet": "…",
"source": ["kaer_web"]
}
],
"kaer": { "request_id": "req_…", "cost_usd": 0.001 }
}Headers: x-request-id and the x-ratelimit-* headers. Search sends no x-kaer-cost-usd header: the cost is kaer.cost_usd in the body.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_json | The body is not valid JSON. Images also needs a JSON object. |
| 400 | query_required | query is missing or blank. |
| 400 | query_too_long | query is over 512 characters (search) or 300 (images). |
| 400 | invalid_lane | lane is not web, fast, deep or auto. |
| 400 | invalid_num_results | num_results is not a number. |
| 400 | invalid_domains | include_domains or exclude_domains is not an array of up to 20 host names. |
| 403 | tier_required | Your tier does not include this service yet. |
| 413 | body_too_large | The body is over the endpoint's limit: chat 1 MB, search 16 KB, batch 64 KB, images 8 KB, mail 512 KB. |
| 502 | search_failed | The search service failed. Nothing was charged. |
| 503 | search_busy | Search is at capacity. Nothing was charged. |
| 504 | search_timeout | Search ran out of time. Nothing was charged. |
| 502 or 503 | search_unavailable | Search is unreachable or paused. Nothing was charged. |
Run a search
curl https://api.kaer.ai/v1/search \
-H "Authorization: Bearer $KAER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "latest ai research",
"lane": "fast",
"num_results": 5
}'Batch search
api.kaer.ai/v1/search/batch- Scope
search- Tier
- Starter and up
- Price
- Per served row, at search prices
- Free credit
- Yes, once Starter opens it
Send many queries in one round trip. Every row shares the lane, the result count and the domain filters.
Request body
| Field | Type | Default | Description |
|---|---|---|---|
queriesRequired | string[] | · | 1 to your tier's batch size. Each query is 1 to 512 characters after trimming. |
lane | string | auto | web, fast, deep or auto, case-insensitive. Anything else is a 400. |
num_results | integer | 5 | Results per query, 1 to 25. Numbers outside are clamped; anything that is not a number is a 400. Also read as numResults. |
include_domains | string[] | · | Only results from these hosts or their subdomains, up to 20. The web lane applies it before ranking; the others filter after retrieval. Also includeDomains. |
exclude_domains | string[] | · | Never return results from these hosts or their subdomains, up to 20. Also excludeDomains. |
fields | string[] | · | Result keys to keep, 1 to 20 of title, url, snippet, source, published_date, text, text_truncated, text_source. Leave it out for all of them. Any other name is a 400 invalid_fields. |
Unread fields come back in kaer.ignored_params. The body is limited to 64 KB, and the whole batch to 35 seconds.
| Tier | Queries per batch |
|---|---|
| Starter | 10 |
| Build | 50 |
| Scale | 100 |
| Pro | 100 |
Understand how a batch is billed
- Each row that comes back with
ok: trueis billed like a single search, at the lane that served it. - Queries that match after trimming, lowercasing and collapsing spaces run once and are billed once; the repeats come back with
charged: falseandduplicate_of. - Rows that fail carry
charged: falseand cost nothing. - While the batch runs, the gateway holds the dearest possible price for every row (
autoholds the deep price). - If the whole batch fails, nothing is charged.
Response
| Field | Type | Description |
|---|---|---|
object | string | search.batch |
lane | string | The lane you asked for. |
count | integer | Rows requested. |
served | integer | Rows served, repeats included. See billed_queries for what was billed. |
billed_queries | integer | Distinct queries served and billed. |
deduplicated | integer | Rows that repeated an earlier query and were not billed. |
duration_ms | integer | Time the batch took, in milliseconds. |
results[].index | integer | Position in queries. |
results[].query | string | The query. |
results[].ok | boolean | Whether the row was served. |
results[].served_lane | string | Served rows: the lane billed. |
results[].results | array | Served rows: the hits, shaped like Search results; deep rows carry text, text_truncated and text_source. |
results[].charged | boolean | false on rows that failed and on repeats. |
results[].duplicate_of | integer | Repeats: the index of the row that ran the query. |
results[].deep | boolean | Deep rows: true when pages were read, false when the row fell back to snippets. |
results[].degraded_reason | string | Deep rows with deep: false: timeout, engines_failed or pages_unreadable. |
results[].quality | object | partial (boolean), coverage (0 to 1) and result_count, when the lane reports them. |
results[].code | string | Failed rows: timeout, backpressure, upstream_unavailable, invalid_query, no_results or internal. |
results[].error | string | Failed rows: a fixed message for code. |
kaer.cost_usd | number | What the batch cost. |
Rows carry only the fields above. Retry timeout, backpressure and upstream_unavailable rows; fix invalid_query rows; internal is ours to fix.
Headers: x-request-id and the x-ratelimit-* headers. The cost is kaer.cost_usd in the body; there is no x-kaer-cost-usd header.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_json | The body is not valid JSON. Images also needs a JSON object. |
| 400 | queries_required | queries is missing or empty. |
| 400 | batch_too_large | More queries than your tier's batch size. |
| 400 | invalid_query | A batch query is blank or over 512 characters. |
| 400 | invalid_lane | lane is not web, fast, deep or auto. |
| 400 | invalid_num_results | num_results is not a number. |
| 400 | invalid_domains | include_domains or exclude_domains is not an array of up to 20 host names. |
| 403 | tier_required | Your tier does not include this service yet. |
| 413 | body_too_large | The body is over the endpoint's limit: chat 1 MB, search 16 KB, batch 64 KB, images 8 KB, mail 512 KB. |
| 502 | search_failed | The search service failed. Nothing was charged. |
| 503 | search_busy | Search is at capacity. Nothing was charged. |
| 504 | search_timeout | Search ran out of time. Nothing was charged. |
| 502 or 503 | search_unavailable | Search is unreachable or paused. Nothing was charged. |
curl https://api.kaer.ai/v1/search/batch \
-H "Authorization: Bearer $KAER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queries": ["solar panel efficiency 2026", "heat pump grants uk"],
"lane": "web",
"num_results": 3
}'Images
api.kaer.ai/v1/images- Scope
search- Tier
- Starter and up
- Price
- $0.002 per call
- Free credit
- Yes, once Starter opens it
Find real photos, diagrams and illustrations for a subject, from Kaer's picture index with live Wikimedia Commons and Pexels results when the index is thin. Every picture is checked and comes with its licence, a ready-made credit line and whether a business website may reuse it.
Request body
| Field | Type | Default | Description |
|---|---|---|---|
queryRequired | string | · | What to picture, 1 to 300 characters ("sourdough bread", "water cycle diagram"). |
count | integer | 12 | 1 to 30 pictures. Anything else, a numeric string included, is a 400. |
reusable | boolean | false | Only pictures a business website may use with the returned credit. |
Other fields come back in kaer.ignored_params. The body is limited to 8 KB; a call times out after 15 seconds.
Price
One call costs $0.002 whatever count is, even when it finds no pictures. A call that fails is not charged.
Response
| Field | Type | Description |
|---|---|---|
object | string | images.result |
query | string | The query, trimmed. |
subject | string | The subject the index searched for. |
count | integer | Pictures returned. |
reusable_only | boolean | Echoes reusable. |
withheld | object | Present when some pictures were held back. |
results[].id | string | Stable picture id. |
results[].kind | string | photo, diagram or illustration. |
results[].title | string | Picture title. |
results[].image_url | string | Full-size image (https). |
results[].thumb_url | string | Thumbnail (https). |
results[].page_url | string | The page the picture comes from. |
results[].host | string | That page's host. |
results[].width, height | integer | Pixel size, when known. |
results[].source | string | wikimedia_commons, pexels or web. |
results[].license | object | name, code, label and url. |
results[].credit | string | Author or owner. |
results[].attribution | string | Attribution text from the source. |
results[].credit_line | string | A ready-made credit to publish with the picture. |
results[].attribution_required | boolean | Publish credit_line next to the picture when true. |
results[].share_alike | boolean | Derivatives must keep the same licence. |
results[].commercial_ok | boolean | A business website may use it. |
{
"object": "images.result",
"query": "sourdough bread",
"subject": "sourdough bread",
"count": 12,
"reusable_only": true,
"results": [
{
"id": "commons:sourdough.jpg",
"kind": "photo",
"title": "Sourdough loaf",
"image_url": "https://upload.wikimedia.org/…",
"thumb_url": "https://upload.wikimedia.org/…/500px-…",
"page_url": "https://commons.wikimedia.org/wiki/File:…",
"host": "commons.wikimedia.org",
"width": 4000,
"height": 3000,
"source": "wikimedia_commons",
"license": { "name": "…", "code": "cc-by-sa", "label": "CC BY-SA 4.0", "url": "https://creativecommons.org/licenses/by-sa/4.0/" },
"credit": "Ann K",
"attribution": "…",
"credit_line": "…",
"attribution_required": true,
"share_alike": true,
"commercial_ok": true
}
],
"kaer": { "request_id": "req_…", "cost_usd": 0.002 }
}Headers: x-request-id and the x-ratelimit-* headers. The cost is kaer.cost_usd in the body; there is no x-kaer-cost-usd header.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_json | The body is not valid JSON. Images also needs a JSON object. |
| 400 | query_required | query is missing or blank. |
| 400 | query_too_long | query is over 512 characters (search) or 300 (images). |
| 400 | invalid_count | count is not an integer from 1 to 30. |
| 400 | invalid_reusable | reusable is not true or false. |
| 403 | tier_required | Your tier does not include this service yet. |
| 413 | body_too_large | The body is over the endpoint's limit: chat 1 MB, search 16 KB, batch 64 KB, images 8 KB, mail 512 KB. |
| 502 | images_failed | The picture search failed. Nothing was charged. |
| 503 | images_busy | Images are at capacity. Nothing was charged. |
| 502 or 503 | images_unavailable | Images are unreachable, timed out or paused. Nothing was charged. |
curl https://api.kaer.ai/v1/images \
-H "Authorization: Bearer $KAER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "sourdough bread", "count": 20, "reusable": true}'Choosing a lane
Every lane takes the same request and returns the same shape. Pick by how far the answer has to come from.
| Lane | Searches | Send it for | Per 1,000 |
|---|---|---|---|
web | Kaer's index alone. | High volume on known topics, at the lowest price. | $0.50 |
fast | The index racing the live web. | Pages the index may not hold yet. | $1.00 |
deep | Every lane, re-ranked, with each page's text. | Grounding a model in the source, not a snippet. | $3.00 |
auto | Kaer picks a lane per query. | When you would rather not choose. | As served |
On deep, each result also carries text (the page's main text, up to 4,000 characters), text_truncated and text_source: page, or snippet when a site would not serve the page.
auto holds the deep price while it runs, then settles at the lane that answered. served_lane names it, so you always know what you paid for.
Use from assistants
Kaer's MCP server lets Claude, ChatGPT, Cursor and other MCP clients ask Kaer, and Kaer's web search runs on this index. It is billed to your Kaer account, not to an API platform balance.
It takes a Kaer account key (kaer_sk_…, made in the Kaer app), not a kaer_live_ API key:
claude mcp add --transport http kaer https://app.kaer.ai/api/mcp \
--header "Authorization: Bearer kaer_sk_…"Every client, step by step: Connect Claude and ChatGPT over MCP.
Pricing
Search is billed per query, not per result: a query costs the same with 1 result or 25. The price is set by the lane that served it.
| Lane | Per query | Per 1,000 | Per 100,000 |
|---|---|---|---|
web | $0.0005 | $0.50 | $50.00 |
fast | $0.001 | $1.00 | $100.00 |
deep | $0.003 | $3.00 | $300.00 |
auto | $0.0005 to $0.003 | As served | As served |
Images (POST /v1/images) | $0.002 per call | $2.00 | $200.00 |
Know what is billed
- A served query is billed whatever
num_resultsis and however many results come back, an empty list included. autoholds the deep price ($0.003) while it runs, then settles at the lane that served it;served_lanenames it. If the lane cannot be read, the query is billed asdeep.- In a batch, every served row is billed like a single search, duplicates included. Failed rows are free. The hold is the dearest lane price times the number of rows.
- Queries that fail or time out are not charged.
- Free credit pays for search and images on Starter and up. Search is not open on the Free tier.
Estimate your cost
10,000 web searches | 10,000 × $0.0005 | $5.00 |
|---|---|---|
10,000 fast searches | 10,000 × $0.001 | $10.00 |
10,000 deep searches | 10,000 × $0.003 | $30.00 |
100 auto searches: 60 served by web, 30 by fast, 10 by deep | 60 × $0.0005 + 30 × $0.001 + 10 × $0.003 | $0.09 |
A batch of 50 fast queries, 2 rows failed | 48 × $0.001 (hold while running: 50 × $0.001) | $0.048 |
| 1,000 image calls | 1,000 × $0.002 | $2.00 |
Errors
When a call fails, the response tells you why. To handle an error:
- Read
error.codein the body. It is the precise reason. - Find the code in the tables below, grouped by cause.
- Apply the fix in the What to do column.
Errors are OpenAI-shaped, so any OpenAI client shows them sensibly:
{
"error": {
"message": "The model 'gpt-9' does not exist on api.kaer.ai.",
"type": "invalid_request_error",
"param": null,
"code": "model_not_found"
}
}type is the OpenAI class; code is the precise reason, so branch on code. A call that fails with an error status is not charged; a stream that breaks after it started is charged for what it sent. The maps service's own errors keep their shape, see Maps.
When you write to support, quote the x-request-id header. It names the exact call.
Keys and access
| Code | Status | Meaning | What to do |
|---|---|---|---|
missing_api_key | 401 | No key in Authorization: Bearer or x-api-key. | Send your key. |
invalid_api_key | 401 | The key is malformed, unknown, revoked or expired. | Check the key, or create a new one. |
account_inactive | 403 | The account is suspended or closed, or owes a reversed payment. | If the message mentions a balance owed, add credit. Otherwise write to [email protected]. |
ip_not_allowed | 403 | The caller's IP is not on the key's allow-list. | Add the address or range to the key, or call from an allowed host. |
insufficient_scope | 403 | The key does not have the endpoint's scope. | Add the scope to the key in the dashboard. |
tier_required | 403 | Your tier does not include this service yet. | Search, images and maps open at Starter ($5 paid). Mail opens at Build. |
unknown_endpoint | 404 | No such endpoint under /v1. | Check the path against this page. |
not_found | 404 | The path is not part of the API. | Call https://api.kaer.ai/v1/.... |
Balance and spend
| Code | Status | Meaning | What to do |
|---|---|---|---|
insufficient_credits | 402 | Your balance cannot cover the call's hold. Free credit never pays for mail. | Top up, turn on automatic top-up, or lower max_tokens to shrink the hold. |
monthly_limit_reached | 402 | This month's spend plus open holds would pass your monthly cap (your budget or your tier's). | Raise your budget in Settings, move up a tier, or wait for the new month (UTC). |
key_budget_exceeded | 402 | The key's monthly budget is used up. Open holds count. | Raise or clear the key's budget. |
payment_required | 402 | A refunded or disputed payment left a balance owed. | Add credit to clear it. |
Rate limits
| Code | Status | Meaning | What to do |
|---|---|---|---|
rate_limit_exceeded | 429 | Too many requests this minute for the key or the account, or too many invalid keys from your address. | Wait for Retry-After, then back off. See Rate limits and tiers. |
too_many_streams | 429 | Your account already has its tier's maximum of open streams. | Wait for a stream to finish. |
key_shared | 429 | A Free tier key was used from too many networks within an hour. | Keep keys on your server. A top-up moves you off the Free tier. |
mail_rate_limit | 429 | Messages in the last minute reached your tier's cap. | Wait 60 seconds (Retry-After). |
mail_daily_limit | 429 | Recipients today (UTC) would pass your tier's cap. | Wait until 00:00 UTC (Retry-After) or move up a tier. |
Request
| Code | Status | Meaning | What to do |
|---|---|---|---|
invalid_json | 400 | The body is not valid JSON. Images also needs a JSON object. | Send a JSON object with Content-Type: application/json. |
body_too_large | 413 | The body is over the endpoint's limit: chat 1 MB, search 16 KB, batch 64 KB, images 8 KB, mail 512 KB. | Send less. |
query_required | 400 | query is missing or blank. | Send a query. |
query_too_long | 400 | query is over 512 characters (search) or 300 (images). | Shorten it. |
invalid_lane | 400 | lane is not web, fast, deep or auto. | Use one of the four lanes. |
invalid_num_results | 400 | num_results is not a number. | Send an integer from 1 to 25. |
invalid_domains | 400 | include_domains or exclude_domains is not an array of up to 20 host names. | Send arrays of host names. |
queries_required | 400 | queries is missing or empty. | Send an array of query strings. |
batch_too_large | 400 | More queries than your tier's batch size. | Split the batch, or move up a tier. |
invalid_query | 400 | A batch query is blank or over 512 characters. | Fix or drop that query. |
invalid_count | 400 | count is not an integer from 1 to 30. | Send an integer from 1 to 30. |
invalid_reusable | 400 | reusable is not true or false. | Send a boolean. |
Service
| Code | Status | Meaning | What to do |
|---|---|---|---|
search_failed | 502 | The search service failed. Nothing was charged. | Retry. |
search_busy | 503 | Search is at capacity. Nothing was charged. | Retry in a few seconds. |
search_timeout | 504 | Search ran out of time. Nothing was charged. | Retry, or use a faster lane. |
search_unavailable | 502 or 503 | Search is unreachable or paused. Nothing was charged. | Retry later. |
images_failed | 502 | The picture search failed. Nothing was charged. | Retry. |
images_busy | 503 | Images are at capacity. Nothing was charged. | Retry in a few seconds. |
images_unavailable | 502 or 503 | Images are unreachable, timed out or paused. Nothing was charged. | Retry later. |
Rate limits and tiers
Your tier is earned by money paid in (net of refunds) and time since your first payment, never by spend.
| Tier | Req/min per key | Req/min per account | Open streams | Monthly cap |
|---|---|---|---|---|
| Free | 20 | 30 | 2 | $10 |
| Starter | 60 | 120 | 5 | $100 |
| Build | 300 | 600 | 20 | $1,000 |
| Scale | 1,000 | 2,000 | 50 | $5,000 |
| Pro | 3,000 | 6,000 | 100 | $25,000 |
| Enterprise | Custom | Custom | Custom | Custom |
Move up a tier
| Tier | Unlock | Services | Batch size | Active keys |
|---|---|---|---|---|
| Free | Sign up | Models | None | 3 |
| Starter | $5 paid | Models, Search, Maps | 10 | 10 |
| Build | $50 paid and 7 days since your first payment | Models, Search, Maps, Mail | 50 | 25 |
| Scale | $250 paid and 14 days since your first payment | Models, Search, Maps, Mail | 100 | 50 |
| Pro | $1,000 paid and 30 days since your first payment | Models, Search, Maps, Mail | 100 | 100 |
| Enterprise | Contract with Kaer | All | Custom | Custom |
Understand how limits apply
- Requests are counted in fixed 60-second windows, per key and per account; whichever runs out first answers 429
rate_limit_exceededwithRetry-After. - An edge gateway also caps each key at 12,000 requests a minute (bursts up to 2000), so the per-key limit is the lower of that and your tier's figure.
- Open streams are counted per account; over the limit, 429
too_many_streams. - The monthly cap counts settled spend plus open holds in the calendar month (UTC). Your own budget in Settings can only lower it.
- The dashboard playground has its own limit of 20 calls a minute.
- Restricted accounts run at Free tier limits.
On the Free tier only models are open and spend is capped at $10 a month, even with $10 of free credit. A first top-up of $5 moves you to Starter at once.