Skip to content
docs

Sign in with Xava

Let people sign in to your app with their Xava Inference account, read their balance, and spend their credits on models or marketplace tools within a monthly cap they choose.

Standard OAuth 2.1 authorization code with PKCE (S256 only). Register your app in My Clients to get a client ID. MCP clients that register themselves (dynamic registration or a Client ID Metadata Document) use the same server: see MCP sign-in.

Register your app

  • In My Clients: a name (1 to 80 characters), your app's https website, 1 to 10 callback URLs (https, http on a loopback address with any port, or a native app scheme; matched exactly), the permissions the client may ask for, and optionally one of your community apps.
  • Type: a server app gets a client secret (client_secret_basic; keep it on your backend); a browser or native app is a public PKCE client with no secret.
  • The secret is shown once. Rotate it any time: the old secret stops working at once, and access tokens already issued last until they expire. Disable a client to stop new sign-ins and disconnect every user.
  • Up to 50 clients per account. Your client's page shows how many tool calls succeeded through it and what they charged in total, never a user's balance.
  • Changing a client's permissions or required tools can ask its users to connect again.

Permissions

scopespends creditswhat the user is shown
profilenoKnow which account you are: your account name (email, X handle or wallet) and Reward Status
inferenceyesRun text, image, video and audio models, charged to your balance (within the monthly cap)
account:readnoSee your balance and usage
tools:callyesCall the marketplace tools listed below, charged to your balance (within the monthly cap)

A registered client that asks for no scope gets profile account:read. Asking for a scope your client is not allowed is invalid_scope, and a client with required tools must ask for tools:call.

The flow

authorization code + PKCE
# 1. send the user to the consent screen (fresh state, S256 code challenge)
https://xavainf.com/oauth/authorize?response_type=code&client_id=xc_...
  &redirect_uri=https://app.example/callback&state=...
  &scope=profile%20account:read%20tools:call
  &code_challenge=<43 chars>&code_challenge_method=S256&resource=https://xavainf.com

# 2. exchange the code (single use, valid 5 minutes) on your backend
curl https://xavainf.com/oauth/token -u "xc_...:<client secret>" \
  -d grant_type=authorization_code -d code=... -d code_verifier=... \
  -d redirect_uri=https://app.example/callback
# {"access_token":"xat_...","token_type":"Bearer","expires_in":3600,"refresh_token":"xrt_...","scope":"..."}

# 3. who signed in (profile), and their balance (account:read)
curl https://xavainf.com/oauth/userinfo -H "Authorization: Bearer xat_..."
# {"sub":"<account id>","name":"...","reward_status":"noob","holder":false,"status":"active",
#  "balance":{"available_usd":"...","held_usd":"...","topup_url":"https://xavainf.com/dashboard/billing"}}
curl https://xavainf.com/oauth/account -H "Authorization: Bearer xat_..."
# balance + "connection": {monthly_cap_usd, spent_this_month_usd, remaining_budget_usd, period_ends_at, ...}
  • Access tokens last 1 hour; refresh tokens last 30 days and rotate on every use. Reusing an old refresh token disconnects the app. A refresh cannot change the permissions.
  • The resource is this site's origin (the default for registered clients), /mcp, /mcp/account or /v1. Use the origin when the app calls both the account endpoints and MCP.
  • Each connection can make up to 600 requests per minute. Revoke a token at /oauth/revoke; /oauth/connection shows the connection's budget and its accepted tools.
  • With inference, send the access token as the key on the OpenAI-compatible API.
  • The user sees "Allow <your app> to use your Xava Inference account?", your website, what the app will be able to do, and where they will be sent back. Your app's name is shown as you registered it, with "The app chose its own name."
  • An app that only reads (profile, account:read) gets no spending question.
  • An app that spends gets a monthly spending cap: $20, $50 (the default), $100, $250, $500, no cap. No cap allows spending up to the available balance. The user must also tick that they allow your app to spend their balance, purchased credits included. The cap resets on the first of each month at 00:00 UTC.
  • Models, uploads and tool calls through your app share that one monthly budget per user. The user's own monthly usage limit, if set, applies too.
  • Each required tool is listed with its description, "Required by this app" and its price per call, and whether it needs the user's own account with the tool's provider. If you also built that tool, the screen says that the app's developer earns the listed tool fee.
  • Users change the cap, see the accepted tools or disconnect your app in their dashboard under API keys, Connected apps.

Calling marketplace tools

  • In your client's settings, choose the tools it requires: up to 100 exact tools (no wildcards), from tools approved and listed on Connections. Your own private servers cannot be required. Enable the tools:call permission first.
  • Send tools/call to /mcp/account with the access token: one tool call per request, with an Idempotency-Key header of 1 to 200 visible ASCII characters, unique per operation. Without it the request is refused with HTTP 400.
  • Retries never run the tool twice. The same key with the same tool and arguments returns a receipt with the operation's state (in_progress, succeeded, failed or outcome_unknown). Arguments and results are not stored, so a retry cannot return the result. The same key with different input is idempotency_conflict.
  • If the provider's outcome is unknown (a timeout, for example), the operation will not run again by itself: check with the provider before you start a new one with a new key.
  • Your app can call only the tools the user accepted that are still on your client's list and still approved. If a tool's price rises above what the user accepted, or its definition changes, the call returns consent_required: send the user through sign-in again.
  • Tools that need the user's own account with a provider (for example Google Calendar) have a separate connection step; /oauth/connection returns each tool's provider_state and a setup_url.
  • Calls are charged at the tool's listed price and only when the tool succeeds (see how tool calls are billed).
one marketplace tool call
curl https://xavainf.com/mcp/account \
  -H "Authorization: Bearer xat_..." \
  -H "Idempotency-Key: order-1234-create-event" \
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"<server>__<tool>","arguments":{}}}'

Errors

whereerrormeaning
API, uploads402 spending_cap_reachedthe connection reached its monthly cap; the body has cap_usd, spent_this_month_usd, required_usd and manage_url
API, uploads402 monthly_limit_reachedthe user's own monthly usage limit would be passed
API403 insufficient_scopethe connection was not granted inference
API403 oauth_policy_changedthe connection changed or was disconnected; connect again
MCP401 invalid_tokenthe token expired or was revoked: refresh it, or sign in again
MCP403 insufficient_scopethe connection lacks the scope the call needs (tools:call for marketplace tools)
MCP400, JSON-RPC -32600no Idempotency-Key, or more than one tool call in the request
tool resultmonthly spending capisError with the cap in the message, plus manage_url and required_usd: not an HTTP 402
tool resultlow balanceisError with required_usd, available_usd and topup_url
tool resultidempotency_conflictthis key was already used for a different tool or arguments
tool resultoperation_pendingnot confirmed yet; retry with the same key
tool resultoutcome_unknownthe provider's outcome is unknown; it will not run again automatically
tool resultconsent_requiredthe tool's terms or the connection changed; the user must connect again
tool resulttool_unavailablethe tool is not accepted for this connection, or no longer approved
/oauth/userinfo403 insufficient_scopethe connection was not granted profile

Tool-result errors carry code in structuredContent where shown. API errors use the shape in errors & rate limits.

What you earn

Builders earn from their own published tools: each charged call of your approved community tool earns you your fee, through your app or anyone else's (see payouts). Requiring someone else's tool does not change who earns its fee. Nothing is paid to an app's developer for what users spend on models through the app.