Skip to main content
Documentation

One key,
four services

OpenAI-compatible chat completions, web search, maps and hosted mail behind one base URL, one key and one prepaid balance. Every response reports what it cost.

Quickstart

Get started in three steps: create an account, generate an API key, and make your first call. All endpoints are authenticated with a bearer token sent in the Authorization header.

1. Create an account

Sign up at api.kaer.ai. A new account gets $5 of free credit for language models, once per network, device and inbox. It expires after 90 days.

2. Generate an API key

In your dashboard, navigate to Keys and create a new API key. Assign it the scopes you need (models, search, maps, mail). Copy the full key: it is shown only once, and starts with kaer_live_.

3. Make your first call

curl -X POST https://api.kaer.ai/v1/chat/completions \
  -H "Authorization: Bearer kaer_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "x1-kaer",
    "messages": [
      {"role": "user", "content": "Hello, world!"}
    ]
  }'

Authentication

Every API call requires authentication via a bearer token in the Authorization header. Tokens are account-specific, scoped to one or more services, and can include IP allowlists and monthly spending limits.

Header format

Send your API key as a bearer token:

Authorization: Bearer kaer_live_your_api_key_here

Key format and scopes

API keys always start with the prefix kaer_live_ and are followed by a random string. Each key is granted one or more scopes:

  • models: chat completions
  • search: web search and batch search
  • maps: maps, routing and places
  • mail: sending mail (Build tier and above)

IP allowlist

You can restrict a key to specific IP addresses or CIDR blocks. Empty means no restrictions. IP allowlist is checked on every request.

Key budgets and rotation

Set a monthly spending limit per key to cap runaway usage. To rotate a key, create a new one and delete the old one. Revocation takes effect at once. Closing the account revokes every key; a suspended account keeps its keys but every call is refused until it is active again.

Never ship keys to browsers

Always use the API from your backend. If a key is exposed, regenerate it immediately in the dashboard. Keys are treated as secrets, not like API IDs.

Models

GET /v1/models

Retrieve the list of available models and their live pricing.

No authentication required. Returns an OpenAI-compatible list with pricing fields in the kaer block.

curl https://api.kaer.ai/v1/models

Response shape

The response includes a kaer object with live pricing per 1M tokens:

{
  "object": "list",
  "data": [
    {
      "id": "x1-kaer",
      "object": "model",
      "owned_by": "kaer",
      "kaer": {
        "label": "Kaer X1",
        "family": "kaer",
        "pricing": {
          "input_usd_per_m": 0.001,
          "output_usd_per_m": 0.003,
          "cached_input_usd_per_m": null
        },
        "free_credit_eligible": true
      }
    }
  ]
}

Free credit applies here

New accounts receive $5 in free credit applied only to chat/models endpoints, valid for 90 days. Once free credit is exhausted or expires, you must add a payment method to continue.

Chat

POST /v1/chat/completions

Send a prompt to a model and get a completion. Fully compatible with the OpenAI API.

Request parameters

ParameterTypeDescription
modelstringRequired. Model ID from GET /v1/models.
messagesarrayRequired. 1–256 messages. Each message is { "role": "user"|"assistant"|"system", "content": "..." }. Text-only content parts.
max_tokensintegerOptional. Default 4096, max 32768. Output token limit.
temperaturenumberOptional. 0–2. Sampling temperature.
top_pnumberOptional. 0–1. Nucleus sampling parameter.
toolsarrayOptional. Function tools. OpenAI format.
streambooleanOptional. Return a stream of deltas (SSE).

Response shape

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1234567890,
  "model": "x1-kaer",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 20,
    "total_tokens": 30
  },
  "kaer": {
    "request_id": "req_...",
    "cost_usd": 0.00015,
    "free_credit_usd": 0.00015
  }
}

Cost and billing

The response includes kaer.cost_usd and a response header x-kaer-cost-usd with the exact amount charged. Costs are reserved before the call and settled based on the backend's reported token count. A held but unused reservation is never charged.

curl -X POST https://api.kaer.ai/v1/chat/completions \
  -H "Authorization: Bearer kaer_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "x1-kaer",
    "messages": [
      {
        "role": "user",
        "content": "Explain quantum computing in one paragraph."
      }
    ],
    "max_tokens": 200
  }'

Streaming

Set stream: true in the chat request to receive tokens as they arrive via Server-Sent Events (SSE). Each frame is a JSON delta, and a final frame includes complete usage information.

SSE frame format

data: {
  "id": "chatcmpl-...",
  "object": "chat.completion.chunk",
  "created": 1234567890,
  "model": "x1-kaer",
  "choices": [
    {
      "index": 0,
      "delta": { "content": "Hello" },
      "finish_reason": null
    }
  ]
}

data: [DONE]

Final usage frame

A final frame (before [DONE]) includes usage and kaer.cost_usd. Billing is based on tokens streamed, not buffered or estimated. If a client disconnects during streaming, only streamed tokens are charged.

Timeouts

Streams must produce at least one byte every 90 seconds. If no data arrives for 90s, the connection is closed and the call is settled. Maximum stream duration is 15 minutes.

curl -X POST https://api.kaer.ai/v1/chat/completions \
  -H "Authorization: Bearer kaer_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "x1-kaer",
    "messages": [{"role": "user", "content": "Count to 10."}],
    "stream": true
  }' \
  -N

Batch search

POST /v1/search/batch

Submit multiple search queries in one request. Billed per result returned, same as individual searches.

Request body

Array of search objects with the same fields as POST /v1/search.

TierMax batch size
Free0
Starter10
Build50
Scale100
Pro100
Enterprise100

Response shape

Returns an array with the same shape as POST /v1/search, in request order.

Maps

GET /v1/maps?action=...

Maps, location, routing, and travel services. Pass the action and its parameters as query strings.

Supported actions

Only these actions are available on the API platform. Session-only actions (live flights, IP geolocation) are not offered.

ActionCategoryPrice per 1k
closuresStandard$0.0500
departuresStandard$0.0500
fuel_pricesStandard$0.0500
geocodeStandard$0.0500
incidentsStandard$0.0500
journeyStandard$0.0500
place_atStandard$0.0500
poiStandard$0.0500
railStandard$0.0500
reverseStandard$0.0500
road_classesStandard$0.0500
routeStandard$0.0500
route_trafficStandard$0.0500
site_imageTiles$0.0050
site_imagesTiles$0.0050
speed_camerasStandard$0.0500
stopsStandard$0.0500
traffic_statusStandard$0.0500
transitStandard$0.0500
weatherStandard$0.0500

Example: Geocoding

curl "https://api.kaer.ai/v1/maps?action=geocode&query=1600+Pennsylvania+Ave" \
  -H "Authorization: Bearer kaer_live_..."

Mail

Build tier and above. Send transactional email from Kaer's own sending domain. Mail is paid from paid credit only, never free credit. The key needs the mail scope.

Send a message

POST /v1/mail/send. Messages leave from api-…@kaer.dev, the address assigned to your account, with the display name <from_name> via Kaer and a short footer naming your account's domain. Replies go to reply_to.

FieldTypeNotes
tostring or string[]Required. Up to your tier's recipients per message; duplicates are removed.
subjectstringRequired, up to 200 characters. Line breaks are removed.
text, htmlstringAt least one. Up to 128 KB of text and 256 KB of HTML.
from_namestringOptional, up to 64 characters.
reply_tostringOptional. Cannot be a Kaer address.

from, cc, bcc, headers and attachments are refused. Send an Idempotency-Key header to make retries safe: a repeated key returns the first result and sends nothing.

curl https://api.kaer.ai/v1/mail/send \
  -H "Authorization: Bearer $KAER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4812-receipt" \
  -d '{
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "text": "Thanks for your order.",
    "from_name": "Acme",
    "reply_to": "[email protected]"
  }'
{
  "id": "msg_63bd80dded23e6452659ed84",
  "object": "mail.message",
  "status": "sent",
  "from": "api-…@kaer.dev",
  "recipients": 1,
  "kaer": { "request_id": "req_…", "cost_usd": 0.0015 }
}

GET /v1/mail/messages/{id} returns a message's status. We keep the recipient count and their domains, never addresses, subjects or bodies.

Pricing

ItemPrice
Per message$0.0010
Per recipient$0.0005

A message that the mail server does not accept is not charged.

Limits by tier

TierRecipients per day (UTC)Messages per minuteRecipients per message
Build100510
Scale1,0003050
Pro10,000120100
Enterprise100,000600500

Over a limit the answer is 429 with mail_rate_limit or mail_daily_limit and a Retry-After header.

Account

GET /v1/me

Retrieve information about the authenticated account.

curl https://api.kaer.ai/v1/me \
  -H "Authorization: Bearer kaer_live_..."

Errors

All errors follow a standard format with an HTTP status code, a type field, and a machine-readable code field.

Error response shape

{
  "error": {
    "type": "invalid_request_error",
    "code": "model_not_found",
    "message": "The model 'invalid' does not exist on api.kaer.ai."
  }
}

Common errors

StatusTypeCodeMeaning
400invalid_request_errorinvalid_jsonThe body is not valid JSON.
400invalid_request_errormessages_requiredChat needs a non-empty messages array.
400invalid_request_errortoo_many_recipientsMore recipients than your tier allows in one message.
401authentication_errormissing_api_keyNo Authorization: Bearer or x-api-key header.
401authentication_errorinvalid_api_keyThe key is wrong or was revoked.
402insufficient_quotainsufficient_creditsThe balance cannot cover this call. Add credit or turn on automatic top-up.
402insufficient_quotamonthly_limit_reachedThe account reached its monthly limit (yours or your tier's).
402insufficient_quotakey_budget_exceededThis key reached its own monthly budget.
402insufficient_quotapayment_requiredA reversed payment left a balance to settle.
403permission_errorinsufficient_scopeThe key lacks the scope for this service.
403permission_errortier_requiredYour tier does not include this service yet.
403permission_errorip_not_allowedThe key is limited to other IP addresses.
403permission_erroraccount_inactiveThe account is suspended or closed.
404invalid_request_errormodel_not_foundNo such model on the platform.
413invalid_request_errorbody_too_largeThe request body is over the endpoint's limit.
429rate_limit_errorrate_limit_exceededRequests per minute exceeded. Wait for Retry-After.
429rate_limit_errortoo_many_streamsToo many open streams for your tier.
429rate_limit_errormail_rate_limit / mail_daily_limitA mail cap was reached. Wait for Retry-After.
502server_errorupstream_unreachableThe model service did not answer. Nothing was charged.
503server_errormodel_unavailable / search_unavailableThe service is paused. Nothing was charged.

Rate-limit headers

Every response includes rate-limit information:

  • x-ratelimit-limit-requests: requests allowed per minute for this key on your tier
  • x-ratelimit-remaining-requests: requests left in the current minute
  • x-ratelimit-reset-requests: seconds until the window resets, for example 42s

Limits

Accounts are organized into tiers, each with separate rate limits, service access, and spending caps.

TierReq/min per keyConcurrent streamsMonthly capUnlock
Free202$5Sign up
Starter605$100$5 paid
Build30020$1000$50 paid and 7 days since your first payment
Scale100050$5000$250 paid and 14 days since your first payment
Pro3000100$25000$1,000 paid and 30 days since your first payment
Enterprise10000400$250000Contract with Kaer

How tiers rise

Your tier is determined by lifetime payments (net of refunds) and days since first payment:

  • Free: Sign up
  • Starter: $5 paid
  • Build: $50 paid and 7 days since first payment
  • Scale: $250 paid and 14 days since first payment
  • Pro: $1,000 paid and 30 days since first payment
  • Enterprise: Contract with Kaer

Services by tier

TierModelsSearchMapsMail
Free✓–––
Starter✓✓✓–
Build✓✓✓✓
Scale✓✓✓✓
Pro✓✓✓✓
Enterprise✓✓✓✓

Billing

Every call reserves an upper bound of the cost before it runs, then settles the exact cost the backend reports. Accounts are strictly prepaid: you cannot run up a balance, and free credit covers only chat/models endpoints.

How prepaid works

  1. Every call reserves an upper bound (prompt estimate + max_tokens at the model's dearest band, or per-action price for other services)
  2. The backend runs and reports the exact cost
  3. The gateway settles the hold down to the real amount
  4. Unused holds are never charged
  5. If your balance falls below zero (impossible, but for completeness), the account is suspended

Insufficient credit (402)

When a call needs more than your available balance, the gateway refuses it with 402 Payment Required. Nothing is charged. Add credit or enable automatic top-up to continue.

Free credit

New accounts receive $5 in free credit, valid for 90 days. Free credit applies only to chat/models endpoints and is granted once per network/device/inbox. Once exhausted or expired, a payment method is required.

Automatic top-up

Configure automatic top-up to charge your saved card when your balance falls below a threshold. Top-ups are:

  • Fixed amounts (you set the amount, threshold, and monthly cap)
  • Processed immediately when the threshold is crossed or a call would fail
  • Capped by tier (max per top-up, max per month, max per day)
  • If a charge fails, no credit is added and nothing else is charged; two failures pause automatic top-up

Automatic top-up is available after your first successful payment and requires explicit consent. Two failures or a failed authentication pauses it.

Refunds and disputes

A refund of a top-up removes the credit that payment added, bonus included. A dispute does the same and pauses the account until it is resolved; a dispute decided in your favour restores the credit. If the credit was already spent, the difference is owed and the account stays paused until a top-up clears it.

Privacy

The request log behind your Usage page holds metadata only. It is what we bill from and what you can export as CSV.

What the request log holds

  • Time, latency and, for streams, time to first token
  • Endpoint, service, and the model, lane or action
  • Status code and error code
  • Token, query or request counts, and the cost
  • The key used, the country the call came from, and a keyed hash of the client IP, cleared after 90 days

What it does not hold

  • Prompt or completion text
  • Search queries or results
  • Map coordinates or routes
  • Email bodies
  • Your raw IP address

Special terms

Model providers and the services behind each endpoint keep their own operational logs for a limited time to run and secure them. Contractual retention terms, zero retention with model providers and a data processing agreement are arranged through enterprise.

Changelog

  • 2026-09-22 · api.kaer.ai v2: separate accounts, strictly prepaid billing, new dashboard