Documentation

Quickstart and API reference · Last updated: August 6, 2026

MyAppToken is a reverse proxy: your app calls the provider's native API through api.myapptoken.com, and the proxy injects your provider API key server-side. The integration is a base-URL swap plus a lightweight per-user token.

Quickstart

1. Create an app and a service

Sign in to the dashboard with Google and create an application — it gets a UUID app ID, shown in the dashboard (e.g. 550e8400-e29b-41d4-a716-446655440000). Then add a service pointing at your provider's base URL:

openai  →  https://api.openai.com/v1

Base URLs must use https:// — plain-http upstreams are rejected.

2. Store your provider key

Paste the provider API key into the service's token vault. It is stored server-side, encrypted at rest, and masked from that moment on — no API or dashboard screen returns the full value again. You can add several keys per service with priorities for failover, and rotate or revoke them without an app release.

3. Get a user token and call the proxy

Your app exchanges its app ID and a user identifier for a short-lived JWT. Two prerequisites: set APP_ID to your app's UUID (copy it from the application's page in the dashboard — the example below will 404 as-is), and jq, used only to extract the token:

APP_ID=550e8400-e29b-41d4-a716-446655440000   # ← replace with your App ID

JWT=$(curl -s -X POST https://api.myapptoken.com/api/v1/auth/simple \
  -H 'Content-Type: application/json' \
  -d "{\"app_id\": \"$APP_ID\", \"user_id\": \"user-123\"}" | jq -r .access_token)

No jq? Run the curl alone and set JWT=<access_token from the response> by hand. The full response:

{
  "access_token": "eyJhbGciOiJIUzI1NiIs…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "expires_at": "2026-08-06T20:00:00Z",
  "services": {
    "openai": {
      "limits": {
        "requests": 100, "remaining": 100, "window": "hour",
        "disabled": false, "resets-in": 3600
      }
    }
  }
}

disabled and resets-in (seconds) reflect the user's rate-limit cooldown state — see rate limits.

Then call the provider through the proxy — same paths, same request and response shapes, with the JWT in place of the provider key:

curl https://api.myapptoken.com/api/v1/proxy/$APP_ID/openai/images/generations \
  -H "Authorization: Bearer $JWT" \
  -H 'Content-Type: application/json' \
  -d '{"model": "gpt-image-1", "prompt": "a lighthouse at dusk", "size": "1024x1024"}'

(Image generation is a good first test: responses are buffered today, so non-streaming endpoints show the proxy at its best. Chat completions work the same way — minus token-by-token streaming, which is in development.)

In app code the whole change is the base URL and the credential:

// Swift — before
let baseURL = "https://api.openai.com/v1"
let apiKey  = "sk-proj-…"          // shipped with the app

// after — <app-id> is your app's UUID from the dashboard
let baseURL = "https://api.myapptoken.com/api/v1/proxy/<app-id>/openai"
let apiKey  = sessionJWT           // from /auth/simple, expires in 1 h

Authentication reference

EndpointDescription
POST /api/v1/auth/simple Body {"app_id", "user_id"} → JWT valid for 3600 seconds. The response includes the per-service rate-limit budget for that user.
POST /api/v1/auth/refresh Header Authorization: Bearer <jwt> → fresh JWT with a new one-hour expiry.

Threat model, stated plainly: auth/simple takes a caller-chosen user ID and no other proof. Anyone who discovers your app ID can mint tokens for fresh user IDs, so per-user rate limits alone are damage control — they contain accidental overuse and unsophisticated abuse, not a determined attacker. For production mobile apps, enable Firebase App Check: proxy calls then additionally require proof they come from a genuine build of your app.

Proxy reference

Every HTTP method is supported. The URL format is:

https://api.myapptoken.com/api/v1/proxy/{app_id}/{service_name}/{provider_path}

app_id is the application's UUID; service_name is the name you gave the service (e.g. openai).

The proxy validates the JWT, applies the user's rate limit, selects an active provider key (by priority, with failover), forwards the request to the service's base URL with the key injected, and returns the provider's response unchanged.

Rate limits

Each service has a per-user request limit over a rolling window, configurable in the dashboard. A user who exceeds it is temporarily disabled for one window and receives:

HTTP 429
{
  "error": "rate_limit_exceeded",
  "message": "Temporarily disabled: rate limit exceeded",
  "limit": 100,
  "window": "hour",
  "retry_after_seconds": 3540
}

The /auth/simple response carries each service's remaining budget, so your app can show "N requests left" without extra calls. You can also disable a specific user for a service permanently, in one click, from the dashboard.

Firebase App Check

Enable App Check per application in the dashboard (with your Firebase project number and app IDs). Once enabled, every proxy call must carry a valid App Check token:

X-Firebase-AppCheck: <token from the App Check SDK>

Calls without a valid token get 401 {"error": "appcheck_failed"}. This is the mechanism that restricts proxy access to genuine builds of your app.

For strongest protection, enter explicit Firebase App IDs. Leaving the app-ID list empty accepts tokens from any app in that Firebase project — fine for a single-app project, too broad otherwise.

Data handling

Beta limits

Up to 5 applications per account, unlimited services and keys. There is no published request cap during beta — we contact heavy users before any restriction. Pricing and limit changes come with at least 30 days' notice; see pricing.

Questions? hello@myapptoken.com