Quickstart
Get up and running in 4 steps — register, login, create a key, and make your first chat request.
1. Register & Login
curl -X POST https://api.aio.dev/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your-password"}'
# Login → get JWT
curl -X POST https://api.aio.dev/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your-password"}'{"access_token": "eyJ...", "token_type": "bearer"}2. Create an API Key
curl -X POST https://api.aio.dev/v1/keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{"name":"my-project"}'{"id":"uuid","name":"my-project","key":"aio-a1b2c3...","prefix":"aio-a1b2","created_at":"2026-05-09T00:00:00Z"}3. Make a Chat Request
curl -X POST https://api.aio.dev/v1/chat/completions \
-H "Authorization: Bearer aio-<key>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello!"}]}'{"id":"chatcmpl-abc","object":"chat.completion","model":"gpt-4o","choices":[{"index":0,"message":{"role":"assistant","content":"Hello! How can I help?"},"finish_reason":"stop"}],"usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}}Authentication
AIO uses JWT for web dashboard access and API keys for the chat endpoint.
| Mechanism | Header | Used For |
|---|---|---|
| JWT | Bearer <jwt> | Web dashboard |
| API Key | Bearer aio-<32 hex> | Chat API |
/auth/registerNo authRegister a new user account.
| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Email address | |
| password | string | yes | Password |
curl -X POST https://api.aio.dev/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your-password"}'{"id": "uuid", "email": "user@example.com"}/auth/loginNo authLogin to receive a JWT access token.
curl -X POST https://api.aio.dev/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your-password"}'{"access_token": "eyJ...", "token_type": "bearer"}/auth/meBearer <jwt>Return the current user's profile.
curl https://api.aio.dev/v1/auth/me \
-H "Authorization: Bearer <jwt>"{"id": "uuid", "email": "user@example.com", "is_admin": false, "is_active": true}Chat Completions
OpenAI-compatible endpoint. Drop-in replacement with full streaming (SSE) support.
/chat/completionsBearer aio-<key>Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| model | string | yes | Model alias (e.g. gpt-4o, claude-sonnet-4) |
| messages | array | yes | List of message objects |
| messages[].role | string | yes | system, user, or assistant |
| messages[].content | string | yes | Message text content |
| stream | boolean | no | Enable SSE streaming (default false) |
| temperature | float | no | Sampling temperature (0–2) |
| max_tokens | int | no | Max tokens in the response |
| top_p | float | no | Nucleus sampling parameter |
Non-Streaming
curl -X POST https://api.aio.dev/v1/chat/completions \
-H "Authorization: Bearer aio-<key>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello!"}]}'{"id":"chatcmpl-abc","object":"chat.completion","created":1715900000,"model":"gpt-4o","choices":[{"index":0,"message":{"role":"assistant","content":"Hello! How can I help you?"},"finish_reason":"stop"}],"usage":{"prompt_tokens":25,"completion_tokens":8,"total_tokens":33}}Streaming (SSE)
curl -X POST https://api.aio.dev/v1/chat/completions \
-H "Authorization: Bearer aio-<key>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello!"}],"stream":true}'Response Headers
X-RateLimit-Limit-RPM: 60
X-RateLimit-Remaining-RPM: 58
X-RateLimit-Limit-TPM: 200000
X-RateLimit-Remaining-TPM: 199500
Models
Public endpoint — no authentication required.
/modelsNo authcurl https://api.aio.dev/v1/models[{"id":"uuid","model_id":"gpt-4o","display_name":"GPT-4o","provider_name":"openai","supports_vision":true,"supports_reasoning":false,"supports_tools":true,"supports_streaming":true,"input_cost_per_1k":0.0025,"output_cost_per_1k":0.01}]Response Fields
| Field | Type | Required | Description |
|---|---|---|---|
| model_id | string | — | Alias to use in /chat/completions |
| display_name | string | — | Human-readable name |
| provider_name | string | — | openai / anthropic / gemini / deepseek |
| supports_vision | bool | — | Image input support |
| supports_reasoning | bool | — | Deep reasoning / thinking |
| supports_tools | bool | — | Tool calling support |
| supports_streaming | bool | — | SSE streaming support |
| input_cost_per_1k | float | null | — | USD per 1K input tokens |
| output_cost_per_1k | float | null | — | USD per 1K output tokens |
API Keys
Manage API keys for the chat endpoint. All key endpoints require JWT authentication.
/keysBearer <jwt>Create a new API key. The full key value is returned only once — save it immediately.
curl -X POST https://api.aio.dev/v1/keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{"name":"my-project"}'{"id":"uuid","name":"my-project","key":"aio-a1b2c3...","prefix":"aio-a1b2","created_at":"2026-05-09T00:00:00Z"}/keysBearer <jwt>List all keys for the authenticated user. Full key values are never returned.
curl https://api.aio.dev/v1/keys \
-H "Authorization: Bearer <jwt>"{"keys":[{"id":"uuid","name":"my-project","prefix":"aio-a1b2","is_active":true,"last_used_at":null,"created_at":"2026-05-09T00:00:00Z"}]}/keys/{key_id}Bearer <jwt>Revoke a key. This is a soft-delete — the key is deactivated but usage history is preserved.
curl -X DELETE https://api.aio.dev/v1/keys/<key-id> \
-H "Authorization: Bearer <jwt>"{"detail": "key revoked"}/keys/{key_id}/rotateBearer <jwt>Rotate a key — revokes the old key and returns a new one with the same name.
curl -X POST https://api.aio.dev/v1/keys/<key-id>/rotate \
-H "Authorization: Bearer <jwt>"Providers
Manage LLM providers and their API keys. Requires admin JWT.
/admin/providersList all providers.
/admin/providersCreate a provider. The API key is encrypted at rest with Fernet.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Provider identifier |
| api_base_url | string | no | Custom base URL override |
| api_key | string | no | Provider API key (encrypted at rest) |
| priority | int | no | Routing priority — higher wins |
/admin/providers/{id}Update a provider. All fields optional.
/admin/providers/{id}Deactivate a provider.
Models (Admin)
Manage model configurations. Requires admin JWT.
/admin/modelsList all model configs (including inactive).
/admin/modelsCreate a model config that maps a user-facing alias to a specific provider model.
| Field | Type | Required | Description |
|---|---|---|---|
| provider_id | UUID | yes | Provider FK |
| model_id | string | yes | User-facing alias for /chat/completions |
| provider_model_id | string | yes | Actual model ID sent to provider |
| display_name | string | yes | Human-readable name |
| input_cost_per_1k | float | no | USD per 1K input tokens |
| output_cost_per_1k | float | no | USD per 1K output tokens |
| supports_vision | bool | no | Default false |
| supports_reasoning | bool | no | Default false |
| supports_tools | bool | no | Default false |
/admin/models/{id}Update a model. All fields optional.
/admin/models/{id}Deactivate a model.
Stats & Usage
System statistics and usage record queries. Requires admin JWT.
/admin/statsAggregated system statistics.
curl https://api.aio.dev/v1/admin/stats \
-H "Authorization: Bearer <admin-jwt>"{"total_users":42,"total_api_keys":128,"total_requests":15230,"total_tokens":8500000,"active_providers":4}/admin/usageQuery usage records with filters and pagination.
| Field | Type | Required | Description |
|---|---|---|---|
| user_id | UUID | no | Filter by user |
| provider_id | UUID | no | Filter by provider |
| model | string | no | Filter by model alias |
| status | string | no | Filter by status (success/error) |
| limit | int | no | Page size (1–200, default 50) |
| offset | int | no | Pagination offset (default 0) |
/admin/walletsList all wallets with user emails.
/admin/wallets/{user_id}/topupTop up a user's balance.
curl -X POST https://api.aio.dev/v1/admin/wallets/<user-id>/topup \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{"amount": 20.00}'{"wallet_id":"uuid","previous_balance":12.50,"amount":20.00,"new_balance":32.50,"transaction_id":"uuid"}Billing & Rate Limits
Pre-paid wallet billing with cent-level precision. All limits are configurable via environment variables.
Rate Limits
| Limit | Default | Header |
|---|---|---|
| Requests per minute | 60 | X-RateLimit-Limit-RPM |
| Tokens per minute | 200,000 | X-RateLimit-Limit-TPM |
Billing Flow
- Before each chat request: estimated cost computed from input size + max_tokens against model pricing
- If balance is below the estimated cost, the request is rejected with
402 - After the response completes: actual token cost is deducted from wallet
- All deductions and top-ups create transaction records linked to usage records via the
referencefield
Errors
All error responses follow a consistent format.
| Code | Meaning |
|---|---|
| 401 | Invalid credentials, token, or API key |
| 402 | Insufficient balance — response includes required vs available |
| 403 | Forbidden — admin access required |
| 404 | Resource not found |
| 409 | Conflict — email already registered |
| 422 | Validation error |
| 429 | Rate limit exceeded — Retry-After header included |
| 502 | Upstream provider error |
# 402 example
curl -X POST https://api.aio.dev/v1/chat/completions \
-H "Authorization: Bearer aio-<key>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello!"}]}'{"detail": "Insufficient balance. Required: $0.0125, Available: $0.0010"}