REST API
Implement OAuth2 + PKCE and call AI Pass endpoints from any stack — Flutter, iOS, Android, desktop, CLI, server. No SDK required.
Building a browser/web app instead? See the Web SDK — it handles PKCE, token storage, and the auth button for you.
Managing OAuth clients, payments, gift cards, or apps? See Management API.
Building with an AI agent (Claude Code, Cursor, etc.)?
npx skills add aipass-one/skill --skill aipass-oauth-appinstalls the canonical agent skill.
TL;DR flow
- Create an OAuth2 client →
- Generate PKCE + state →
- Send user to
/oauth2/authorize→ - Exchange code at
/oauth2/token→ - Store
access_token+refresh_token→ - Call
/oauth2/v1/*with Bearer token
CORS is already open on
/oauth2/token, so mobile/web apps can exchange codes directly without a custom backend.
1) Get a client ID
Register your app and obtain client_id (and optional client_secret) from the Developer Dashboard or via REST.
POST /api/v1/oauth2/clients
Content-Type: application/json
{
"clientName": "My Flutter App",
"redirectUri": "myapp://auth/callback",
"requestedScopes": ["api:access", "profile:read"]
}
Save the client secret if you generate one — it's only shown once. Public apps (Flutter, web) typically use PKCE without a client secret.
2) Generate PKCE + state
Generate these per login:
code_verifier: random 43-128 charscode_challenge:BASE64URL(SHA256(code_verifier))state: random string to prevent CSRF
JavaScript
const verifier = generateRandom(64);
const challenge = await sha256Base64Url(verifier);
const state = generateRandom(24);
Dart (Flutter)
final verifier = generateRandomString(64);
final challenge = base64UrlEncode(
sha256.convert(utf8.encode(verifier)).bytes
).replaceAll('=', '');
final state = generateRandomString(24);
Python
import secrets, hashlib, base64
code_verifier = secrets.token_urlsafe(64)[:64]
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b"=").decode()
state = secrets.token_urlsafe(16)
Keep
code_verifierandstateuntil the redirect returns so you can validate and exchange the code.
3) Launch the OAuth screen
Open the user's browser (or url_launcher in Flutter) to:
GET https://aipass.one/oauth2/authorize
?client_id=YOUR_CLIENT_ID
&response_type=code
&redirect_uri=YOUR_REDIRECT_URI
&scope=api:access profile:read
&state=STATE_VALUE
&code_challenge=PKCE_CHALLENGE
&code_challenge_method=S256
Use custom schemes like myapp://auth/callback on mobile. Validate the returned state before exchanging the code.
4) Exchange code & refresh
Exchange the authorization code
POST https://aipass.one/oauth2/token
Content-Type: application/json
{
"grantType": "authorization_code",
"code": "CODE_FROM_REDIRECT",
"codeVerifier": "ORIGINAL_CODE_VERIFIER",
"clientId": "YOUR_CLIENT_ID",
"redirectUri": "YOUR_REDIRECT_URI"
}
Response fields: access_token, refresh_token, expires_in, token_type (Bearer), scope.
Refresh tokens
POST https://aipass.one/oauth2/token
Content-Type: application/json
{
"grantType": "refresh_token",
"refreshToken": "YOUR_REFRESH_TOKEN",
"clientId": "YOUR_CLIENT_ID"
}
On
401responses from the API, refresh once, then restart OAuth if the refresh fails too.
5) Discover models — don't hardcode
Models change. Always list at runtime:
curl https://aipass.one/oauth2/v1/models \
-H "Authorization: Bearer $ACCESS_TOKEN" \
| jq '.data[] | select(.id | endswith("/edit")) | .id'
# Returns the available image-edit model IDs.
Filter by ID convention:
| Capability | Pattern |
|---|---|
| Image edit | ends in /edit (e.g. fal-ai/nano-banana-2/edit) |
| Image gen | image-provider prefix, no /edit |
| Chat / text | gpt-*, claude-*, gemini/* |
| TTS | starts with tts- |
| Transcription | contains whisper |
| Embeddings | starts with text-embedding- |
6) Make AI calls
Send the Bearer token in every request. The proxy mirrors OpenAI-style payloads.
Chat completion
curl -X POST https://aipass.one/oauth2/v1/chat/completions \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5-mini",
"messages": [
{"role":"system","content":"You answer briefly."},
{"role":"user","content":"One tip for better focus?"}
],
"max_tokens": 200,
"stream": false
}'
For streaming, set "stream": true and consume Server-Sent Events. Budget errors arrive as JSON; surface them to the user.
Image generation
curl -X POST https://aipass.one/oauth2/v1/images/generations \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "imagen4/preview/ultra",
"prompt": "A futuristic city at sunset",
"size": "1024x1024",
"n": 1,
"response_format": "url"
}'
# Always check both `url` and `b64_json` — different models return different shapes.
Image editing — single image
curl -X POST https://aipass.one/oauth2/v1/images/edits \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "image=@selfie.jpg" \
-F "prompt=Change the hairstyle to a sleek bob cut. Preserve the face and lighting." \
-F "model=fal-ai/nano-banana-2/edit" \
-F "size=1024x1024" \
-F "response_format=url"
import requests
with open("selfie.jpg", "rb") as f:
r = requests.post(
"https://aipass.one/oauth2/v1/images/edits",
headers={"Authorization": f"Bearer {access_token}"},
files={"image": f},
data={
"model": "fal-ai/nano-banana-2/edit",
"prompt": "Change the hairstyle to a sleek bob cut. Preserve the face and lighting.",
"size": "1024x1024",
"response_format": "url",
},
)
url = r.json()["data"][0].get("url") or f"data:image/png;base64,{r.json()['data'][0]['b64_json']}"
Image editing — multi-image
Pass multiple -F image=@… for models that support multi-image input (fal-ai/nano-banana-2/edit, openai/gpt-image-2/edit, fal-ai/nano-banana-pro/edit):
curl -X POST https://aipass.one/oauth2/v1/images/edits \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "image=@target.jpg" \
-F "image=@reference.jpg" \
-F "prompt=Apply the hairstyle from the second image to the person in the first." \
-F "model=fal-ai/nano-banana-2/edit"
The server treats repeated image form fields as an array.
7) Vision (multimodal)
Same /oauth2/v1/chat/completions endpoint, but content is an array:
{
"model": "gpt-5-mini",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ..."}}
]
}],
"max_tokens": 2000
}
Compress images to ~800KB before encoding to base64. Vision models support: JPEG, PNG, GIF, WebP.
8) Audio + embeddings
# TTS
curl -X POST https://aipass.one/oauth2/v1/audio/speech \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"tts-1","input":"Hello world","voice":"nova","response_format":"mp3"}' \
--output speech.mp3
# Transcribe
curl -X POST https://aipass.one/oauth2/v1/audio/transcriptions \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "file=@audio.mp3" \
-F "model=whisper-1" \
-F "language=en"
# Embeddings
curl -X POST https://aipass.one/oauth2/v1/embeddings \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"text-embedding-3-small","input":["First text","Second text"]}'
9) Usage & balance tracking
Show users their remaining budget:
GET https://aipass.one/api/v1/usage/me/summary
Authorization: Bearer ACCESS_TOKEN
// Response:
{
"success": true,
"data": {
"totalCost": 2.45,
"maxBudget": 10.00,
"remainingBudget": 7.55
}
}
Cache balance data and refresh periodically (every 5-10 minutes) to reduce API calls.
10) All allowed endpoints
All require Authorization: Bearer ACCESS_TOKEN and api:access scope. Base URL: https://aipass.one/oauth2/v1
| Category | Endpoints |
|---|---|
| Models | GET /models, GET /models/{id} |
| Chat | POST /chat/completions |
| Embeddings | POST /embeddings |
| Images | POST /images/generations, POST /images/edits, POST /images/variations |
| Audio | POST /audio/speech, POST /audio/transcriptions |
| Video | POST /videos, POST /videos/{id}/remix, GET /videos/{id}, GET /videos/{id}/content |
| User profile | GET /oauth2/userinfo (needs profile:read) |
| Usage & Balance | GET /api/v1/usage/me/summary |
| Revoke | POST /oauth2/revoke?token=ACCESS_TOKEN |
Only allowlisted endpoints above are proxied. All calls require
api:accessscope.
For management endpoints (OAuth2 clients, payments, gift cards, spaces, apps), see the Endpoints Reference.