Authentication
Quota supports API keys for server-to-server access and OAuth for user billing. Use API keys for developer billing or OAuth tokens when end users should pay for their own usage.
Developer Account
Create a developer account to get started. All session-authenticated endpoints use the sess_... token returned at login.
Register
POST /auth/register
curl -X POST https://api.usequota.ai/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "dev@example.com",
"password": "securepassword"
}'Email must contain @. Password must be at least 8 characters.
Response (201):
{
"user": { "id": "uuid", "email": "dev@example.com", "balance": 100 },
"session_token": "sess_abc123...",
"expires_at": "2026-02-10T00:00:00.000Z"
}New accounts receive 100 welcome credits.
Registration Errors
| Status | Code | Description |
|---|---|---|
| 400 | invalid_email | Email format is invalid |
| 400 | weak_password | Password is shorter than 8 characters |
| 409 | email_exists | An account with this email already exists |
Rate limit: 3 requests/minute.
Login
POST /auth/login
curl -X POST https://api.usequota.ai/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "dev@example.com",
"password": "securepassword"
}'Response (200):
{
"user": { "id": "uuid", "email": "dev@example.com", "balance": 9500 },
"session_token": "sess_xyz789...",
"expires_at": "2026-02-10T00:00:00.000Z"
}Login Errors
| Status | Code | Description |
|---|---|---|
| 401 | invalid_credentials | Email or password is incorrect |
Rate limit: 5 requests/minute.
Get Current User
GET /auth/me
Returns the authenticated user. Requires Authorization: Bearer sess_....
{
"id": "uuid",
"email": "dev@example.com",
"balance": 9500
}Logout
POST /auth/logout
Invalidates the current session token. Requires Authorization: Bearer sess_....
{ "success": true }API Keys
Create API keys via POST /developers/keys (requires a session token). Keys use this format:
sk-quota-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThe sk-quota- prefix prevents mixups with other providers.
Managing API Keys
| Endpoint | Method | Description |
|---|---|---|
/developers/keys | POST | Create a new API key (returned only once) |
/developers/keys | GET | List your API keys (no secrets exposed) |
/developers/keys/:id | DELETE | Revoke an API key |
All key management endpoints require session authentication (Authorization: Bearer sess_...).
Using an API Key
Send your key as Authorization or X-API-Key:
Authorization: Bearer sk-quota-your-api-key
X-API-Key: sk-quota-your-api-keyExample with cURL
curl https://api.usequota.ai/v1/balance \
-H "Authorization: Bearer sk-quota-your-api-key"Example with JavaScript
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.usequota.ai/v1",
apiKey: "sk-quota-your-api-key",
});Environment Variables
We recommend storing your API key in an environment variable:
# .env
QUOTA_API_KEY=sk-quota-your-api-keyThen use it in your code:
const client = new OpenAI({
baseURL: "https://api.usequota.ai/v1",
apiKey: process.env.QUOTA_API_KEY,
});Security Best Practices
- Never commit API keys to version control
- Use environment variables in production
- Rotate keys periodically
- Use separate keys for development and production
OAuth (User Billing)
Use OAuth when end users should be billed from their own balance.
1. Register an OAuth Client
Create an OAuth client via POST /developers/apps (requires session auth):
curl -X POST https://api.usequota.ai/developers/apps \
-H "Authorization: Bearer sess_..." \
-H "Content-Type: application/json" \
-d '{
"name": "My App",
"redirect_uris": ["https://myapp.com/callback"]
}'Response:
{
"id": "...",
"name": "My App",
"client_id": "quota_client_...",
"client_secret": "quota_secret_...",
"redirect_uris": ["https://myapp.com/callback"],
"created_at": "..."
}The client_secret is only returned once. Store it securely.
Redirect URI Requirements
- Development:
http://localhost:*andhttp://127.0.0.1:*are allowed (any port) - Production: Must use HTTPS (
https://yourapp.com/callback) - No wildcards: Each URI must be an exact match — wildcard patterns like
https://*.example.comare not supported - Multiple URIs: Register separate URIs for dev, staging, and production environments
Managing OAuth Clients
| Endpoint | Method | Description |
|---|---|---|
/developers/apps | POST | Register a new OAuth client |
/developers/apps | GET | List your OAuth clients |
/developers/apps/:id | DELETE | Delete an OAuth client |
2. Authorization Flow
- Redirect users to
/oauth/authorizewithclient_id,redirect_uri,response_type=code,state, and optionalscope. - Unauthenticated users see a hosted login/register page (
/oauth/login,/oauth/register). - Exchange the returned code at
/oauth/token(form-encoded) withgrant_type=authorization_code, then storeaccess_tokenandrefresh_token. - Refresh with
grant_type=refresh_tokenwhen tokens expire. - Fetch user info from
/oauth/userinfo; revoke with/oauth/revoke.
Access and refresh tokens are opaque strings prefixed with quota_token_ and quota_refresh_.
Hosted Token Storage (X-Quota-User)
Use hosted token storage when you want Quota to manage OAuth tokens server-side. Instead of storing tokens yourself, send the user's external ID via the X-Quota-User header alongside your API key.
Quick Setup
- Create an OAuth app:
POST /developers/appswith your redirect URIs - Redirect users to authorize:
/oauth/authorize?client_id=...&redirect_uri=...&response_type=code&state=...&storage_mode=hosted&external_user_id=your_user_123 - Exchange the code:
POST /oauth/tokenwithgrant_type=authorization_code— Quota stores the token server-side - Make requests with X-Quota-User: Include
X-Quota-User: your_user_123header with your API key - Quota handles billing: Requests are automatically billed to the linked user's balance
How it works
- User connects via OAuth (same flow as above).
- Quota stores the token link server-side, keyed by an external user ID.
- Your app sends
X-Quota-User: external_idwith your API key on every request. - Quota resolves the linked user and bills their balance.
Example with cURL
curl https://api.usequota.ai/v1/chat/completions \
-H "Authorization: Bearer sk-quota-your-api-key" \
-H "X-Quota-User: user_123" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}]}'Example with OpenAI SDK
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.QUOTA_API_KEY,
baseURL: "https://api.usequota.ai/v1", // Include /v1
defaultHeaders: { "X-Quota-User": userId },
});Example with Anthropic SDK
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.QUOTA_API_KEY,
baseURL: "https://api.usequota.ai", // No /v1 suffix!
defaultHeaders: { "X-Quota-User": userId },
});Note: The Anthropic SDK adds its own /v1 prefix, so omit it from the baseURL to avoid /v1/v1/messages.
See Hosted Users API for endpoint details, Core SDK for a framework-agnostic client, or Next.js SDK for a turnkey Next.js integration.
When to Use Which
| Method | Who Pays | Use Case |
|---|---|---|
| API Key | Developer | Internal tools, backends, prototypes |
| OAuth Token | End user | User-facing apps where users pay for AI usage |
| API Key + X-Quota-User | End user | Server-side apps billing users without client-side OAuth |
Rate Limits
Default: 100 requests/minute per API key. Funding and auth endpoints use stricter limits. Rate limit headers are included in every response:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per minute |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |