Keyring β€” BYOK for every LLM, one manifest.

An open registry and client SDK for bring-your-own-key LLM access. Stop re-implementing the key-entry modal, the stale model dropdown, and the per-provider switch statement in every project. Keyring is the shared layer underneath β€” think WalletConnect, but for AI model keys.

loading registry… GET /registry.json v1 schema

Your providers

Paste an API key to light up a provider. Keys stay in localStorage; nothing is sent to token.app.

Test a chat

Picks a configured provider + model and sends a single user message directly from your browser. Some providers don't allow browser-origin requests; you'll see a CORS error if so.

response will appear here…

Drop-in usage

The dumbest possible integration β€” just fetch the registry and use it. No SDK required.

// Fetch the registry (CDN-cached, 5min SWR)
const reg = await fetch('https://token.app/registry.json').then(r => r.json());
const openai = reg.providers.find(p => p.id === 'openai');
const model  = openai.models.find(m => m.id === 'gpt-4o');

await fetch(openai.endpoints.base + openai.endpoints.chat, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    [openai.auth.headerName]: openai.auth.headerPrefix + userKey,
  },
  body: JSON.stringify({ model: model.providerModelId, messages: [...] }),
});

Or use the SDK

// npm i keyring-client
import { createKeyring } from 'keyring-client';

const kr = createKeyring();
await kr.setKey('openai', userKey);
await kr.validateKey('openai');     // β†’ { ok: true, status: 200 }

const res = await kr.chat({
  model: 'gpt-4o',             // canonical id, provider-agnostic
  messages: [{ role: 'user', content: 'hi' }],
});