API Documentation
Everything you need to integrate Gyanis AI into your EdTech product. Standard REST API with two model tiers — works with any HTTP client in any language.
Base URL
https://api.gyanis.ai/platform/v1All endpoints are relative to this base URL. HTTPS is required for all requests.
Authentication
Authenticate by passing your API key in the Authorization header. Keys follow the format gyn_sk_live_<32chars> for production or gyn_sk_test_<32chars> for testing.
Authorization: Bearer gyn_sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345API Key Scopes
| Scope | Grants Access To |
|---|---|
| * | All endpoints (default) |
| chat | POST /chat |
| chat.stream | POST /chat/stream |
| keys | Key management (create, list, revoke) |
| usage | GET /usage |
| webhooks | Webhook management |
| entities | Entity CRUD + history |
| billing | Checkout, purchases, billing status |
| compliance | Data export and deletion |
Models
If no model is specified, your tenant's default tier is used. Model routing is admin-configurable with automatic failover via circuit breakers.
Chat Completion
/platform/v1/chatscope: chatSend a conversation to the AI and receive a complete response.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| messages | array | Yes | Array of message objects (1–100) |
| messages[].role | string | Yes | "user", "assistant", or "system" |
| messages[].content | string | Yes | Message content (1–16,000 chars) |
| model | string | No | "mobius" (default) or "oloid" |
| max_tokens | integer | No | Max response tokens (1–16,384, default: 4,096) |
| entity_id | string | No | Your external entity ID for conversation continuity |
| subject | string | No | Subject context (e.g., "math", "biology") |
| grade | string | No | Grade level (e.g., "8", "12") |
| metadata | object | No | Custom key-value pairs (returned in response) |
| json_mode | boolean | No | Request structured JSON output |
{
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor for 8th graders."
},
{
"role": "user",
"content": "Explain the Pythagorean theorem with an example."
}
],
"model": "mobius",
"max_tokens": 1024,
"entity_id": "student_abc123",
"subject": "math",
"grade": "8"
}curl -X POST https://api.gyanis.ai/platform/v1/chat \
-H "Authorization: Bearer gyn_sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "content": "What is photosynthesis?" }
],
"model": "mobius",
"entity_id": "student_abc123"
}'const response = await fetch("https://api.gyanis.ai/platform/v1/chat", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.GYANIS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ role: "user", content: "What is photosynthesis?" }],
model: "mobius",
entity_id: "student_abc123",
}),
});
const data = await response.json();
console.log(data.choices[0].message.content);import requests
response = requests.post(
"https://api.gyanis.ai/platform/v1/chat",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"messages": [{"role": "user", "content": "What is photosynthesis?"}],
"model": "mobius",
"entity_id": "student_abc123",
},
)
data = response.json()
print(data["choices"][0]["message"]["content"])<?php
$ch = curl_init("https://api.gyanis.ai/platform/v1/chat");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"messages" => [["role" => "user", "content" => "What is photosynthesis?"]],
"model" => "mobius",
"entity_id" => "student_abc123",
]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo $data["choices"][0]["message"]["content"];{
"id": "req_a1b2c3d4e5f6g7h8i9j0k1l2",
"object": "chat.completion",
"created": 1709834400,
"model": "mobius",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Photosynthesis is the process by which green plants convert sunlight, water, and carbon dioxide into glucose and oxygen..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 42,
"completion_tokens": 185,
"total_tokens": 227
}
}Streaming Chat (SSE)
/platform/v1/chat/streamscope: chat.streamStream a chat completion as Server-Sent Events (SSE). Ideal for real-time UIs where you want to display tokens as they arrive. The request body is identical to the chat endpoint.
curl -X POST https://api.gyanis.ai/platform/v1/chat/stream \
-H "Authorization: Bearer gyn_sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345" \
-H "Content-Type: application/json" \
-N \
-d '{
"messages": [
{ "role": "user", "content": "What is gravity?" }
],
"model": "mobius",
"entity_id": "student_abc123"
}'const response = await fetch("https://api.gyanis.ai/platform/v1/chat/stream", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.GYANIS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ role: "user", content: "What is gravity?" }],
model: "mobius",
entity_id: "student_abc123",
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value);
for (const line of text.split("\n")) {
if (line.startsWith("data: ") && line !== "data: [DONE]") {
const chunk = JSON.parse(line.slice(6));
process.stdout.write(chunk.choices[0]?.delta?.content || "");
}
}
}import requests, json
response = requests.post(
"https://api.gyanis.ai/platform/v1/chat/stream",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"messages": [{"role": "user", "content": "What is gravity?"}],
"model": "mobius",
"entity_id": "student_abc123",
},
stream=True,
)
for line in response.iter_lines():
line = line.decode("utf-8")
if line.startswith("data: ") and line != "data: [DONE]":
chunk = json.loads(line[6:])
content = chunk["choices"][0].get("delta", {}).get("content", "")
print(content, end="", flush=True)<?php
$ch = curl_init("https://api.gyanis.ai/platform/v1/chat/stream");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"messages" => [["role" => "user", "content" => "What is gravity?"]],
"model" => "mobius",
"entity_id" => "student_abc123",
]),
CURLOPT_WRITEFUNCTION => function ($ch, $data) {
foreach (explode("\n", $data) as $line) {
if (str_starts_with($line, "data: ") && $line !== "data: [DONE]") {
$chunk = json_decode(substr($line, 6), true);
echo $chunk["choices"][0]["delta"]["content"] ?? "";
}
}
return strlen($data);
},
]);
curl_exec($ch);
curl_close($ch);data: {"id":"req_a1b2c3d4e5f6","object":"chat.completion.chunk","created":1709834400,"model":"mobius","choices":[{"index":0,"delta":{"content":"Gravity"},"finish_reason":null}]}
data: {"id":"req_a1b2c3d4e5f6","object":"chat.completion.chunk","created":1709834400,"model":"mobius","choices":[{"index":0,"delta":{"content":" is"},"finish_reason":null}]}
data: {"id":"req_a1b2c3d4e5f6","object":"chat.completion.chunk","created":1709834400,"model":"mobius","choices":[{"index":0,"delta":{"content":" a fundamental"},"finish_reason":null}]}
data: {"id":"req_a1b2c3d4e5f6","object":"chat.completion.chunk","created":1709834400,"model":"mobius","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":38,"completion_tokens":195,"total_tokens":233}}
data: [DONE]SSE Event Format
| Event | Description |
|---|---|
| data: {chunk} | Content delta — append delta.content to your output |
| data: [DONE] | Stream complete — close the connection |
| : ping | Heartbeat comment every 15s — ignore in your client |
Rate limit: 60 requests/minute per key (vs 120/min for non-streaming). Token usage stats are included in the final chunk with finish_reason.
Entity Context
Pass entity_id with your chat request to maintain conversation continuity per entity. The platform stores up to 50 recent messages per entity, scoped to your tenant.
{
"messages": [{ "role": "user", "content": "What is a variable in math?" }],
"entity_id": "student_abc123"
}{
"messages": [{ "role": "user", "content": "Can you give me an example?" }],
"entity_id": "student_abc123"
}Omit entity_id to use the API statelessly — manage the full message history yourself by passing all messages in each request.
Error Codes
All errors return a consistent JSON structure:
{
"error": {
"code": "insufficient_credits",
"message": "Tenant has insufficient token credits.",
"type": "billing_error",
"request_id": "req_a1b2c3d4e5f6g7h8i9j0k1l2"
}
}| Code | HTTP | Description |
|---|---|---|
| missing_api_key | 401 | No API key provided in request headers |
| invalid_api_key | 401 | Key not found, malformed, or revoked |
| expired_api_key | 401 | Key has passed its expiration date |
| endpoint_not_allowed | 403 | Key scopes do not include this endpoint |
| account_suspended | 403 | Tenant account suspended by admin |
| insufficient_credits | 402 | Prepaid credit balance is zero |
| budget_exceeded | 402 | Monthly token budget reached |
| rpm_exceeded | 429 | Requests per minute limit exceeded |
| tpm_exceeded | 429 | Tokens per minute limit exceeded |
| invalid_request | 400 | Validation error (missing fields, wrong types) |
| message_too_long | 400 | Message exceeds 16,000 character limit |
| too_many_messages | 400 | Messages array exceeds 100-message limit |
| content_policy_violation | 400 | Flagged by content moderation |
| model_unavailable | 503 | AI model provider temporarily unavailable |
| timeout | 504 | AI model request timed out |
Rate Limits
Rate limits are enforced per API key with a sliding window. Defaults can be customized per tenant.
| Metric | Default | Description |
|---|---|---|
| RPM | 60 | Requests per minute |
| TPM | 100,000 | Tokens per minute |
| Daily Requests | Unlimited | Requests per day (0 = unlimited) |
| Chat Endpoint | 120 RPM | POST /chat specific throttle |
| Stream Endpoint | 60 RPM | POST /chat/stream specific throttle |
Response Headers
| Header | Description |
|---|---|
| X-Request-Id | Unique request identifier (req_<24chars>) |
| X-RateLimit-Limit-Requests | Maximum RPM for this key |
| X-RateLimit-Remaining-Requests | Remaining requests in current window |
| X-RateLimit-Reset-Requests | Seconds until rate limit reset |