{
  "openapi": "3.0.3",
  "info": {
    "title": "EDII for Developers API",
    "version": "0.1.0",
    "description": "Call **AGU**, the language model EDII runs on its own servers in Bengaluru, from your code. Your prompts are not\nsent to any other AI company. Every request and AGU's reply are stored with your account, failed ones too, with no expiry.\nAGU does not answer questions about the model behind it or how it was built.\n\n**Getting started**\n1. Sign in at [developer.edii.in](https://developer.edii.in/signin) with your Google account (Gmail only). New accounts get **10,000 free tokens**.\n2. Create an API key on the dashboard. It is shown once, so copy it somewhere safe.\n3. Send it as `Authorization: Bearer edii-sk-...` on every `/v1` request.\n\nThe `/v1` endpoints follow the OpenAI Chat Completions format, so the official OpenAI SDKs work by\npointing `base_url` at `https://api.ask.edii.in/v1`.\n\n**Tokens and pricing.** Every request costs its prompt tokens plus the tokens the model writes. After\nthe free 10,000 tokens, tokens cost **₹100 per 10,000**, bought in packs from the dashboard. Prompt\ntokens are estimated: about four characters per token for English text, one per character for other scripts such\nas Hindi, plus a few tokens of framing per request. Generated tokens are counted exactly.\nEach response returns the tokens charged in `usage` and your remaining balance in the\n`X-EDII-Balance-Tokens` header.\n\n**Limits.** 20 requests a minute and 2 at a time per account, up to 2,048 output tokens per request\n(512 by default), and 20,000 characters of conversation. AGU answers one request at a time per server and\nalso serves EDII's own school features: when it is busy you get `503 server_busy` with `Retry-After` (the OpenAI\nSDKs retry on their own). A request that takes longer than about 60 seconds is stopped and not charged. Closing the\nconnection does not stop a request: it finishes on our side and is charged like any answer. Streaming is accepted but the answer arrives as one chunk.\n",
    "contact": {
      "name": "EDII",
      "email": "contact@edii.in",
      "url": "https://www.edii.in"
    }
  },
  "tags": [
    {
      "name": "Chat",
      "description": "Generate text with AGU."
    },
    {
      "name": "Models"
    },
    {
      "name": "Account",
      "description": "Your balance, from code."
    },
    {
      "name": "Portal",
      "description": "Endpoints behind the developer.edii.in pages. They use the session token from /developer/auth/google\n(`Authorization: Bearer edii-ses-...`), not an API key. Every answer has `status`: `\"success\"`, or the error message.\n"
    }
  ],
  "paths": {
    "/v1/chat/completions": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Create a chat completion",
        "description": "Send a conversation and get the model's next message. Compatible with OpenAI's\n`POST /v1/chat/completions` for text. Images, audio, tools and `n > 1` are not supported.\n",
        "operationId": "createChatCompletion",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              },
              "examples": {
                "simple": {
                  "summary": "One question",
                  "value": {
                    "model": "agu-v2",
                    "messages": [
                      {
                        "role": "user",
                        "content": "Explain photosynthesis to a Class 7 student in three sentences."
                      }
                    ]
                  }
                },
                "conversation": {
                  "summary": "With a system message and history",
                  "value": {
                    "model": "agu-v2",
                    "max_tokens": 300,
                    "temperature": 0.3,
                    "messages": [
                      {
                        "role": "system",
                        "content": "You are a patient maths tutor. Reply in simple English."
                      },
                      {
                        "role": "user",
                        "content": "What is a prime number?"
                      },
                      {
                        "role": "assistant",
                        "content": "A prime number has exactly two factors, 1 and itself."
                      },
                      {
                        "role": "user",
                        "content": "Is 21 prime?"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The model's reply. With `stream: true` the body is `text/event-stream` chunks ending in `data: [DONE]`.",
            "headers": {
              "X-EDII-Balance-Tokens": {
                "description": "Tokens left on your account after this request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletion"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "example": "data: {\"id\":\"chatcmpl-1a2b\",\"object\":\"chat.completion.chunk\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"Hello!\"},\"finish_reason\":null}]}\n\ndata: [DONE]\n"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Not enough tokens left. Buy a pack on the dashboard.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than 256 KB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type` / `unsupported_encoding` / `unsupported_charset`: send UTF-8 JSON (Content-Type: application/json) without Content-Encoding.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "`server_busy`: AGU is busy (other developers or EDII's own features), or `model_unavailable`: the model servers are down. Nothing was charged; retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "`model_timeout`: the model took longer than about 60 seconds. Nothing was charged. Sent with `x-should-retry: false`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "tags": [
          "Models"
        ],
        "summary": "List models",
        "operationId": "listModels",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The models you can use.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "example": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Model"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/models/{id}": {
      "get": {
        "tags": [
          "Models"
        ],
        "summary": "Get a model",
        "operationId": "getModel",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "agu-v2"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Model"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Unknown model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/balance": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get your token balance",
        "operationId": "getBalance",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Your balance and lifetime totals.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "example": "balance"
                    },
                    "balance_tokens": {
                      "type": "integer",
                      "example": 8421
                    },
                    "used_tokens": {
                      "type": "integer",
                      "example": 1579
                    },
                    "free_tokens": {
                      "type": "integer",
                      "example": 10000
                    },
                    "purchased_tokens": {
                      "type": "integer",
                      "example": 0
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/developer/config": {
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "Public pricing, limits and model facts",
        "operationId": "getConfig",
        "responses": {
          "200": {
            "description": "Pricing and limits.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/developer/auth/google": {
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Sign in with Google",
        "operationId": "signInWithGoogle",
        "description": "Send a Google OAuth access token from Google Identity Services (scope `openid email`, EDII client id). Only Gmail accounts are accepted. The first sign-in creates the account with the free tokens. Send the returned `sessionToken` as `Authorization: Bearer ...` on the other portal calls.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accessToken"
                ],
                "properties": {
                  "accessToken": {
                    "type": "string",
                    "description": "Google OAuth access token"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "success"
                    },
                    "sessionToken": {
                      "type": "string",
                      "example": "edii-ses-..."
                    },
                    "sessionExpires": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "newAccount": {
                      "type": "boolean"
                    },
                    "account": {
                      "$ref": "#/components/schemas/PortalAccount"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Google did not confirm the token (expired, wrong app, unverified email).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalError"
                }
              }
            }
          },
          "403": {
            "description": "`gmail_only`: the Google account is not a Gmail address, or `account_blocked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalError"
                }
              }
            }
          },
          "429": {
            "description": "`too_many_sign_ins` from this network this hour, or `too_many_accounts`: too many new accounts from this network today.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalError"
                }
              }
            }
          }
        }
      }
    },
    "/developer/status": {
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "Service health",
        "description": "Whether the database answers (`database`) and whether a model server is available (`model`).",
        "operationId": "getStatus",
        "responses": {
          "200": {
            "description": "Health.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/developer/auth/logout": {
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Sign out",
        "operationId": "logout",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed out."
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "description": "Ends this session token."
      }
    },
    "/developer/me": {
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "The signed-in account",
        "operationId": "getMe",
        "security": [
          {
            "session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Account and balance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "account": {
                      "$ref": "#/components/schemas/PortalAccount"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          }
        }
      }
    },
    "/developer/keys": {
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "List API keys",
        "operationId": "listKeys",
        "security": [
          {
            "session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Keys, newest first. Only a masked form of each key is returned.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          }
        }
      },
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Create an API key",
        "description": "The full key is in `key.secret` in this response only. Up to 5 active keys.",
        "operationId": "createKey",
        "security": [
          {
            "session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 40,
                    "example": "My laptop"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "key": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ApiKey"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "secret": {
                              "type": "string",
                              "example": "edii-sk-..."
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Already 5 active keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          }
        }
      }
    },
    "/developer/keys/{id}/revoke": {
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Revoke an API key",
        "description": "The key stops working at once. Revoked keys stay listed.",
        "operationId": "revokeKey",
        "security": [
          {
            "session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Revoked."
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          },
          "404": {
            "description": "No such active key."
          }
        }
      }
    },
    "/developer/usage": {
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "Usage by day, and the latest calls",
        "operationId": "getUsage",
        "security": [
          {
            "session": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily totals (India time) and the 25 latest calls.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          }
        }
      }
    },
    "/developer/billing/orders": {
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "Token pack orders",
        "operationId": "listOrders",
        "security": [
          {
            "session": []
          }
        ],
        "responses": {
          "200": {
            "description": "The 20 latest orders.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "orders": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Order"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          }
        }
      },
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Start buying token packs",
        "description": "Creates a Razorpay order. Open Razorpay Checkout with the returned `checkout` options.",
        "operationId": "createOrder",
        "security": [
          {
            "session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "packs"
                ],
                "properties": {
                  "packs": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "One pack is 10,000 tokens for ₹100.",
                    "example": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order and Checkout options.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "order": {
                      "$ref": "#/components/schemas/Order"
                    },
                    "checkout": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Packs out of range."
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          },
          "429": {
            "description": "`too_many_open_orders` (3 unpaid orders from the last day) or `too_many_orders` (10 an hour).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalError"
                }
              }
            }
          },
          "503": {
            "description": "`payment_gateway_busy`: try again in a minute.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalError"
                }
              }
            }
          }
        }
      }
    },
    "/developer/billing/verify": {
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Confirm a Checkout payment",
        "description": "Send what Razorpay Checkout returned. The tokens are added once the payment is captured.",
        "operationId": "verifyPayment",
        "security": [
          {
            "session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "razorpay_order_id",
                  "razorpay_payment_id",
                  "razorpay_signature"
                ],
                "properties": {
                  "razorpay_order_id": {
                    "type": "string"
                  },
                  "razorpay_payment_id": {
                    "type": "string"
                  },
                  "razorpay_signature": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order state and balance."
          },
          "400": {
            "description": "The signature did not match."
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          }
        }
      }
    },
    "/developer/billing/orders/{orderId}/refresh": {
      "post": {
        "tags": [
          "Portal"
        ],
        "summary": "Re-check an unpaid order with Razorpay",
        "operationId": "refreshOrder",
        "security": [
          {
            "session": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order state and balance."
          },
          "401": {
            "$ref": "#/components/responses/NotSignedIn"
          },
          "404": {
            "description": "No such order."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "edii-sk-...",
        "description": "Your API key from the dashboard."
      },
      "session": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "edii-ses-...",
        "description": "The sessionToken from /developer/auth/google."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Something in the request is wrong; `error.message` says what.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, wrong or revoked API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests a minute, or too many at once. See `Retry-After`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotSignedIn": {
        "description": "No session token, or it expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PortalError"
            }
          }
        }
      }
    },
    "schemas": {
      "ChatMessage": {
        "type": "object",
        "required": [
          "role",
          "content"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "system",
              "developer",
              "user",
              "assistant"
            ]
          },
          "content": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "type",
                    "text"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "enum": [
                        "text"
                      ]
                    },
                    "text": {
                      "type": "string"
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": [
          "messages"
        ],
        "properties": {
          "model": {
            "type": "string",
            "enum": [
              "agu-v2"
            ],
            "default": "agu-v2"
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "description": "The last message must be from the user. Without a system message, the model introduces itself as AGU by EDII.",
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2048,
            "default": 512,
            "description": "Most tokens to generate. Lowered automatically when your balance cannot cover it."
          },
          "max_completion_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2048,
            "description": "Same as max_tokens (newer OpenAI name). Wins if both are sent."
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2,
            "default": 0.7
          },
          "top_p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 1
          },
          "stop": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "maxItems": 4,
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "The reply is cut at the first of these strings. AGU stops only at the end of its answer or at max_tokens, so the tokens it wrote after the cut are still counted and charged: set max_tokens too."
          },
          "stream": {
            "type": "boolean",
            "default": false,
            "description": "Server-sent events. The whole reply arrives as one chunk."
          },
          "stream_options": {
            "type": "object",
            "properties": {
              "include_usage": {
                "type": "boolean"
              }
            }
          },
          "user": {
            "type": "string",
            "description": "Your own id for the end user, kept with the usage row."
          }
        }
      },
      "ChatCompletion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "chatcmpl-9f2c4e1a7b3d"
          },
          "object": {
            "type": "string",
            "example": "chat.completion"
          },
          "created": {
            "type": "integer",
            "example": 1761264000
          },
          "model": {
            "type": "string",
            "example": "agu-v2"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer",
                  "example": 0
                },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string",
                      "example": "assistant"
                    },
                    "content": {
                      "type": "string",
                      "example": "No. 21 = 3 × 7, so it has four factors."
                    }
                  }
                },
                "finish_reason": {
                  "type": "string",
                  "enum": [
                    "stop",
                    "length"
                  ],
                  "description": "`length` means the reply hit max_tokens."
                }
              }
            }
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "prompt_tokens": {
            "type": "integer",
            "description": "Estimated.",
            "example": 64
          },
          "completion_tokens": {
            "type": "integer",
            "example": 18
          },
          "total_tokens": {
            "type": "integer",
            "description": "Tokens taken from your balance.",
            "example": 82
          }
        }
      },
      "Model": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "agu-v2"
          },
          "object": {
            "type": "string",
            "example": "model"
          },
          "created": {
            "type": "integer"
          },
          "owned_by": {
            "type": "string",
            "example": "edii"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "example": "invalid_request_error"
              },
              "code": {
                "type": "string",
                "example": "insufficient_quota"
              }
            }
          }
        }
      },
      "PortalError": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "The error message."
          },
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "code": {
                "type": "string"
              }
            }
          }
        }
      },
      "PortalAccount": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "balanceTokens": {
            "type": "integer"
          },
          "freeTokens": {
            "type": "integer"
          },
          "purchasedTokens": {
            "type": "integer"
          },
          "usedTokens": {
            "type": "integer"
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "description": "Masked.",
            "example": "edii-sk-Ab3d…x9Qz"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Order": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string"
          },
          "packs": {
            "type": "integer"
          },
          "tokens": {
            "type": "integer"
          },
          "amountPaise": {
            "type": "integer"
          },
          "currency": {
            "type": "string",
            "example": "INR"
          },
          "status": {
            "type": "string",
            "enum": [
              "created",
              "attempted",
              "paid"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "paidAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://api.ask.edii.in",
      "description": "Production"
    }
  ]
}
