AIPass

REST Integration Playbook

Implement OAuth2 + PKCE and call AI Pass endpoints from any stack (Flutter, desktop, CLI, backend) without using our SDKs.

Open Developer Dashboard View Markdown
TL;DR Flow

1) Create an OAuth2 client → 2) Generate PKCE + state → 3) Send user to `/oauth2/authorize` → 4) Exchange code at `/oauth2/token` → 5) Store `access_token` + `refresh_token` → 6) 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 is 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 chars
  • code_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);

Keep code_verifier and state until 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 401 responses from the API, refresh once, then restart OAuth if it fails.

5) Call AI Pass Endpoints

Send the Bearer token in every request. The proxy mirrors OpenAI-style payloads and streams via SSE when stream: true.

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-4o-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.

6) Vision API (Multimodal)

Same /oauth2/v1/chat/completions endpoint, but with multimodal content. Send text + images for analysis.

Structure: Image + Text

The content field accepts an array of parts instead of a string:

{
  "model": "gpt-4o-mini",
  "messages": [{
    "role": "user",
    "content": [
      {
        "type": "text",
        "text": "What's in this image?"
      },
      {
        "type": "image_url",
        "image_url": {
          "url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
        }
      }
    ]
  }],
  "max_tokens": 2000
}

Receipt scanning example

{
  "model": "gemini/gemini-2.5-flash-lite",
  "messages": [{
    "role": "user",
    "content": [
      {
        "type": "text",
        "text": "Extract receipt data in JSON: {amount, currency, date, merchant, category, confidence}"
      },
      {
        "type": "image_url",
        "image_url": {
          "url": "data:image/jpeg;base64,BASE64_ENCODED_IMAGE"
        }
      }
    ]
  }],
  "temperature": 0.7,
  "max_tokens": 2000
}
Flutter
// Analyze receipt image
Future<Map<String, dynamic>> analyzeReceipt(
  String imageBase64
) async {
  final response = await http.post(
    Uri.parse('$baseUrl/oauth2/v1/chat/completions'),
    headers: {
      'Authorization': 'Bearer $accessToken',
      'Content-Type': 'application/json',
    },
    body: jsonEncode({
      'model': 'gemini/gemini-2.5-flash-lite',
      'messages': [{
        'role': 'user',
        'content': [
          {
            'type': 'text',
            'text': 'Extract: {amount, currency, date, merchant, category}'
          },
          {
            'type': 'image_url',
            'image_url': {
              'url': 'data:image/jpeg;base64,$imageBase64'
            }
          }
        ]
      }],
      'max_tokens': 2000,
    }),
  );

  final data = jsonDecode(response.body);
  final content = data['choices'][0]['message']['content'];

  // Extract JSON from response
  final jsonMatch = RegExp(r'\{[\s\S]*\}').firstMatch(content);
  return jsonMatch != null
    ? jsonDecode(jsonMatch.group(0)!)
    : {};
}
JavaScript
async function analyzeReceipt(imageBase64) {
  const response = await fetch(
    'https://aipass.one/oauth2/v1/chat/completions',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        model: 'gemini/gemini-2.5-flash-lite',
        messages: [{
          role: 'user',
          content: [
            {
              type: 'text',
              text: 'Extract: {amount, currency, date, merchant, category}'
            },
            {
              type: 'image_url',
              image_url: {
                url: `data:image/jpeg;base64,${imageBase64}`
              }
            }
          ]
        }],
        max_tokens: 2000
      })
    }
  );

  const data = await response.json();
  const content = data.choices[0].message.content;
  const jsonMatch = content.match(/\{[\s\S]*\}/);
  return jsonMatch ? JSON.parse(jsonMatch[0]) : {};
}

Compress images to ~800KB before encoding to base64. Vision models support: JPEG, PNG, GIF, WebP.

7) Usage & Balance Tracking

Monitor your AI API costs and remaining budget in real-time.

GET https://aipass.one/api/v1/usage/me/summary
Authorization: Bearer ACCESS_TOKEN

// Response:
{
  "success": true,
  "message": "Usage summary retrieved successfully",
  "data": {
    "totalCost": 2.45,
    "maxBudget": 10.00,
    "remainingBudget": 7.55
  },
  "timestamp": "2024-01-15T14:30:00Z"
}
Flutter
Future<Map<String, dynamic>> getBalance() async {
  final response = await http.get(
    Uri.parse('$baseUrl/api/v1/usage/me/summary'),
    headers: {'Authorization': 'Bearer $accessToken'},
  );

  if (response.statusCode == 200) {
    final result = jsonDecode(response.body);
    return result['data'];
  }

  throw Exception('Failed to get balance');
}
JavaScript
async function getUserBalance() {
  const response = await fetch(
    'https://aipass.one/api/v1/usage/me/summary',
    {
      headers: {
        'Authorization': `Bearer ${accessToken}`
      }
    }
  );

  const result = await response.json();

  if (result.success) {
    console.log(`Spent: $${result.data.totalCost}`);
    console.log(`Remaining: $${result.data.remainingBudget}`);
    return result.data;
  }

  throw new Error(result.message);
}

Cache balance data and refresh periodically (every 5-10 minutes) to reduce API calls.

8) All REST Endpoints

ModelsGET /oauth2/v1/models
GET /oauth2/v1/models/{id}
ChatPOST /oauth2/v1/chat/completions
EmbeddingsPOST /oauth2/v1/embeddings
ImagesPOST /oauth2/v1/images/generations
POST /oauth2/v1/images/edits
POST /oauth2/v1/images/variations
AudioPOST /oauth2/v1/audio/speech
POST /oauth2/v1/audio/transcriptions
VideoPOST /oauth2/v1/videos
POST /oauth2/v1/videos/*/remix
GET /oauth2/v1/videos/{id}
GET /oauth2/v1/videos/{id}/content
User profileGET /oauth2/userinfo (needs profile:read)
Usage & BalanceGET /api/v1/usage/me/summary
RevokePOST /oauth2/revoke?token=ACCESS_TOKEN

Only allowlisted endpoints above are proxied. All calls require api:access scope.

9) AI Agent Prompts

Copy-paste these into another agent to auto-generate platform-specific code. Text is intentionally short for LLM consumption.

Quick build
Loading prompt…
Open .md
Checklist
Loading prompt…
Open .md