# KujiChat REST API v1 — LLM Context This document is the machine-readable source of truth for helping a developer integrate with the public KujiChat REST API v1. ## Integration rules for the assisting LLM 1. Use only the endpoints and fields documented below. 2. Never expose an API key in browser code, mobile client code, URLs, logs, or public repositories. 3. Generate server-side examples. Read the key from `KUJICHAT_API_KEY` or another server-only secret. 4. Do not claim that streaming, vision, file upload, tool calling, structured JSON output, webhooks, or batch processing are supported. 5. When selecting a model, prefer the live `GET /models` response because availability depends on the account plan. 6. Handle both API-domain error objects and simple HTTP-layer error strings. 7. On HTTP 429, respect `Retry-After` and use bounded exponential backoff. 8. Do not invent OpenAI-compatible fields that are not listed here. ## Service - Product: KujiChat - API version: v1 - Base URL: `https://kujichat.com/api/v1` - Media type: JSON - Authentication: Bearer API key - API key prefix: `kc_live_` - Authorization header: `Authorization: Bearer $KUJICHAT_API_KEY` - POST content type: `Content-Type: application/json` - Cache policy: API responses use `Cache-Control: no-store` ## Access requirements The account must be verified and available. API access is enabled by a Pro, Max, or Business plan, or by a positive pay-as-you-go API balance. A key can only use models available to its current plan. A user may have at most 5 active API keys. ## Endpoint summary | Method | Path | Purpose | |---|---|---| | GET | `/models` | List models available to the current API key | | GET | `/models/{model_id}` | Get one available model object | | POST | `/chat/completions` | Generate a text chat completion | | GET | `/usage` | Read plan usage, API balance, rate limit, and key metadata | All paths below are relative to `https://kujichat.com/api/v1`. ## POST /chat/completions Generates one text response from a message history or a single prompt. ### Request headers - `Authorization` — required — `Bearer kc_live_...` - `Content-Type` — required — `application/json` ### Request body - `model`: string, optional. Defaults to `gpt`. Use a model ID returned by `GET /models`. - `messages`: array of Message objects, conditionally required. Required when none of `prompt`, `message`, or `input` contains usable text. - `prompt`: string, conditionally required. Single-user-message alternative to `messages`. Maximum 12,000 characters after conversion to text. - `message`: string, conditionally required. Alias of `prompt`. - `input`: string, conditionally required. Alias of `prompt`. - `stream`: boolean, optional, defaults to false. `true` is rejected with `400 streaming_not_supported`. Unknown fields are currently ignored and should not be relied on. ### Message object - `role`: required string. Allowed values: `system`, `user`, `assistant`. - `content`: required non-empty string. Leading/trailing whitespace is removed. Each accepted message is truncated to 12,000 characters. Invalid message entries, invalid roles, and empty content are discarded. At least one valid message or prompt must remain. ### Input limits - Maximum JSON request body: 64 KiB. - Maximum combined content length of accepted messages: 24,000 characters. - Maximum content retained per message or fallback prompt: 12,000 characters. - Streaming is not supported. ### Minimal request ```bash curl -X POST https://kujichat.com/api/v1/chat/completions \ -H "Authorization: Bearer $KUJICHAT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kuji-v0", "messages": [ {"role": "user", "content": "یک پاسخ فارسی کوتاه بنویس."} ] }' ``` ### Successful response HTTP 200: ```json { "id": "chatcmpl_", "object": "chat.completion", "created": 1786642500, "model": "kuji-v0", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Generated text" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 18, "completion_tokens": 21, "total_tokens": 39, "credits": 2, "billing_source": "plan" } } ``` ### Response fields - `id`: unique completion ID prefixed with `chatcmpl_`. - `object`: always `chat.completion`. - `created`: Unix timestamp in seconds. - `model`: model ID used for the request. - `choices[0].index`: currently 0. - `choices[0].message.role`: currently `assistant`. - `choices[0].message.content`: generated text. - `choices[0].finish_reason`: currently `stop`. - `usage.prompt_tokens`: estimated input token count. - `usage.completion_tokens`: estimated output token count. - `usage.total_tokens`: sum of prompt and completion token estimates. - `usage.credits`: credits charged for this request. - `usage.billing_source`: `plan` or `api_balance`. If the upstream model fails, reserved credits are refunded before a 502 response is returned. ## GET /models Lists only models available to the current key and plan. ```bash curl https://kujichat.com/api/v1/models \ -H "Authorization: Bearer $KUJICHAT_API_KEY" ``` Response shape: ```json { "object": "list", "data": [ { "id": "kuji-v0", "object": "model", "display_name": "Kuji v0", "provider": "kujichat", "type": "chat", "description": "Model description", "credits_per_request": 2, "capabilities": { "chat": true, "reasoning": false, "vision": false, "streaming": false, "tools": false, "json_output": false }, "pricing": { "billing_unit": "request", "credits": 2, "payg_amount": 200, "currency": "IRT" }, "available": true, "status": "available", "preview": false, "deprecated": false, "replacement_model": null } ] } ``` Use `data[].id` as the `model` value for chat completions. `IRT` means Iranian toman. Model cost is fixed per request, not per token. ## GET /models/{model_id} Returns one model object directly, without a `data` wrapper. ```bash curl https://kujichat.com/api/v1/models/kuji-v0 \ -H "Authorization: Bearer $KUJICHAT_API_KEY" ``` Returns `404 model_not_found` if the model does not exist or is unavailable to the current key. ## GET /usage Returns current monthly usage, pay-as-you-go balance, rate-limit state, and key metadata. ```bash curl https://kujichat.com/api/v1/usage \ -H "Authorization: Bearer $KUJICHAT_API_KEY" ``` Response shape: ```json { "object": "usage", "plan": "pro", "period": "2026-08", "api_credits": { "used": 128, "limit": 1000, "remaining": 872 }, "pay_as_you_go": { "balance": 2400 }, "rate_limit": { "limit_per_minute": 240, "remaining": 238, "resets_at": "2026-08-13T18:32:00.000Z" }, "key": { "id": "", "name": "Production" } } ``` The period format is `YYYY-MM`. `api_credits.remaining` never goes below zero. ## Billing - One API credit currently equals 100 toman. - Model cost is returned as `credits_per_request` by `GET /models`. - Plan credits are reserved first when sufficient. - If plan credits are unavailable or insufficient, the API attempts to use the separate pay-as-you-go API balance. - A successful completion reports the source in `usage.billing_source`. - An upstream provider failure refunds the reserved plan credits or API balance. - A positive pay-as-you-go balance can enable API access for an account without an API-enabled plan; that access uses the Pro rate-limit level. ## Response headers Authenticated API responses can include: - `X-RateLimit-Limit`: request limit in the current one-minute window. - `X-RateLimit-Remaining`: requests remaining in the current window. - `X-RateLimit-Reset`: reset time as Unix timestamp seconds. - `X-API-Usage-Period`: current `YYYY-MM` usage period. - `X-API-Usage-Limit`: monthly plan credit limit. - `X-API-Usage-Used`: credits used in the current period. - `X-API-Credit-Balance`: current pay-as-you-go API balance. - `Retry-After`: seconds to wait after a 429 response. ## Error formats Most domain errors use: ```json { "error": { "code": "error_code", "message": "Technical explanation", "details": {} } } ``` HTTP parsing errors such as invalid JSON, incorrect Content-Type, or a body larger than 64 KiB use a simple string form: ```json { "error": "Invalid JSON body." } ``` An integration must handle both `error` as an object and `error` as a string. ## Domain errors | HTTP | Code | Meaning | Recommended action | |---|---|---|---| | 400 | `streaming_not_supported` | `stream` was true | Remove it or set it to false | | 401 | `missing_api_key` | Authorization header missing | Send a Bearer token | | 401 | `invalid_api_key` | Key shape invalid, key unknown, or key revoked | Replace/check the key | | 402 | `upgrade_required` | No API-enabled plan and no positive API balance | Upgrade or add API balance | | 402 | `api_credits_exhausted` | Plan credits and API balance cannot cover model cost | Check usage/add balance | | 403 | `account_unavailable` | Account unavailable, banned, or unverified | Fix account status | | 404 | `model_not_found` | Model missing or unavailable to key | Refresh `GET /models` | | 413 | `input_too_large` | Accepted message content exceeds 24,000 characters | Shorten input/history | | 422 | `messages_required` | No valid message or prompt remains | Send valid messages or prompt | | 429 | `rate_limit_exceeded` | Account, key, or pre-auth rate limit exceeded | Respect `Retry-After`; use backoff | | 502 | `upstream_error` | Model provider failed | Retry with a bounded policy | | 503 | `system_stopped` | Service temporarily not accepting API traffic | Retry later | HTTP-layer responses may also include: - 400 `{ "error": "Invalid JSON body." }` - 413 `{ "error": "Request body is too large." }` - 415 `{ "error": "Content-Type must be application/json." }` ## Safe retry guidance - Retry 429 only after `Retry-After`, with bounded exponential backoff and jitter. - Retry transient 502 and 503 responses with a small maximum attempt count. - Do not blindly retry 400, 401, 402, 403, 404, 413, 415, or 422; fix the request/account condition first. - Set an HTTP client timeout. The public examples use 60 seconds. ## Unsupported in public REST API v1 - Streaming responses - Image or file input - File upload - Tool or function calling - Structured JSON output mode - Webhooks - Batch processing - Assistant or project management endpoints ## Security checklist - Keep the key in a server-side secret manager or environment variable. - Use separate keys per environment. - Validate and limit user input before forwarding it. - Set network timeouts and bounded retry policies. - Do not log full keys or sensitive user content. - Rotate a suspected key by creating and deploying a new key before revoking the old one. - Monitor `/usage`, 401, 402, 429, and 5xx rates. ## Canonical human-readable documentation - Overview: `https://kujichat.com/docs` - Quick start: `https://kujichat.com/docs/quick-start` - Endpoint reference: `https://kujichat.com/docs/endpoints` - Models: `https://kujichat.com/docs/models` - Pricing: `https://kujichat.com/docs/pricing` - Limits: `https://kujichat.com/docs/limits` - Errors: `https://kujichat.com/docs/errors` - Security: `https://kujichat.com/docs/security` End of KujiChat REST API v1 context.