新把任何智能体接入 UberLLM:一个密钥,所有模型,价格不高于官方价。
UberLLM

应用:上架并让用户连接

为在 UberLLM 上构建应用的人准备的两件事。这两件事的工作方式与在 OpenRouter 上相同,因此已经这样做的应用只需更改 base URL 即可。

  1. 上架。 发送两个 headers,您的应用就会显示在 uberllm.dev/apps,并根据其发送的 tokens 进行排名。 模型页面会列出使用它们最多的应用。
  2. 让用户连接。 将用户发送到 UberLLM,他们同意后,您的应用 就会在他们的账户上获得一个 API key。他们支付自己的使用费用;您永远 不会处理他们的支付详情。

让你的应用登上排行榜

将以下请求头添加到你的请求中(聊天、消息或媒体,任何端点):

请求头 作用
HTTP-Referer 你的应用地址,例如 https://myapp.com。必填:这是识别你应用的依据。Referer 也可以。
X-Title 你的应用名称,即用户将看到的名称。X-OpenRouter-Title 也可以。
X-OpenRouter-Categories 可选。最多 2 个以下类别,用逗号分隔。
X-OpenRouter-App-Visibility 可选。hidden 可让新应用不显示在公开排行榜上。
curl https://api.uberllm.dev/v1/chat/completions \
  -H "Authorization: Bearer $UBERLLM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "HTTP-Referer: https://myapp.com" \
  -H "X-Title: My App" \
  -H "X-OpenRouter-Categories: cli-agent" \
  -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"Hello"}]}'

使用 OpenAI SDK:

import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://api.uberllm.dev/v1',
  apiKey: process.env.UBERLLM_API_KEY,
  defaultHeaders: {
    'HTTP-Referer': 'https://myapp.com',
    'X-Title': 'My App',
  },
});

如何统计:

  • 只保留地址:https://myapp.com/some/page?user=… 会被存储为 https://myapp.com。路径、查询字符串和登录信息会被丢弃。GitHub、 GitLab、Codeberg、Bitbucket 或 Hugging Face 链接会保留其 owner/repo,因此 开源应用会获得自己的条目。
  • 名称会被截断至 60 个字符。隐藏字符和控制字符会被移除。
  • 第一个为某个应用发送流量的账户会设置其名称和 类别。其他账户的流量仍会计入该应用,但无法更改其名称。
  • 你本机或网络上的地址(localhost、127.0.0.1、 私有 IP、*.local)绝不会公开显示。
  • 来自浏览器的请求会自行发送 Referer,因此即使没有请求头,网页应用也会被统计。添加 X-Title 来选择其名称。
  • 排行榜会统计在过去 24 小时、7 天或 30 天内,按 token 计数的已响应请求。它每隔几分钟刷新一次。

类别:cli-agent、ide-extension、cloud-agent、programming-app、 native-app-builder、creative-writing、video-gen、image-gen、 audio-gen、writing-assistant、general-chat、personal-agent、legal、 roleplay、game。未知类别会被忽略。一个应用最多保留 10 个类别。

排行榜也是一个 API:GET https://uberllm.dev/api/v1/public/apps?period=day|week|month&category=<slug>。

连接 UberLLM (OAuth PKCE)

您的应用将在用户自己的账户下获取一个以您的应用命名的密钥。用户在授权时可以为其设置消费限额,并可以随时在他们的密钥页面]上关闭它。

1. 生成代码验证器和挑战码

验证器是一个您需要保留的随机字符串(43到128个字符)。挑战码是其 SHA-256, base64url-encoded(无填充)的结果。

function base64url(bytes) {
  return btoa(String.fromCharCode(...new Uint8Array(bytes)))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

const codeVerifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const codeChallenge = base64url(
  await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier)),
);
sessionStorage.setItem('uberllm_verifier', codeVerifier);

2. 将用户发送到 UberLLM

https://uberllm.dev/auth?callback_url=https://myapp.com/uberllm/callback&code_challenge=<CHALLENGE>&code_challenge_method=S256
参数
callback_url 用户返回的地址。必须是https://;http://localhost(任何端口)允许用于开发。如果省略,则会在屏幕上显示代码,供用户粘贴到您的应用中。
code_challenge 来自步骤1。必需。
code_challenge_method S256。必需。不接受plain。
key_label 密钥的可选名称(默认:您的应用名称)。
state 可选。随代码原样返回,以便您可以检查回复是否属于您发起的请求。

用户登录(或注册)后,会看到“您的应用希望使用您的 UberLLM 额度”,并选择允许或取消。选择允许后,他们将被发送到:

https://myapp.com/uberllm/callback?code=<CODE>&state=<STATE>

选择取消后,不会发送任何内容。

3. 用代码换取密钥

const code = new URLSearchParams(location.search).get('code');
const res = await fetch('https://uberllm.dev/api/v1/auth/keys', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    code,
    code_verifier: sessionStorage.getItem('uberllm_verifier'),
    code_challenge_method: 'S256',
  }),
});
const { key } = await res.json(); // ull_…  Store it like a password.
curl https://uberllm.dev/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -d '{"code":"<CODE>","code_verifier":"<VERIFIER>","code_challenge_method":"S256"}'

回复是{"key": "ull_…", "key_id": "…", "name": "My App"}。将密钥用作Authorization: Bearer在https://api.uberllm.dev/v1上。该 endpoint 响应来自任何站点的浏览器请求 (CORS),因此它适用于 Web 应用。

状态 代码 含义
400 invalid_code_challenge_method 使用S256。
403 invalid_code 错误的代码或code_verifier,或代码已被使用。
403 code_expired 代码在10分钟内有效。从步骤2重新开始。
405 method_not_allowed 使用POST。
429 rate_limited 来自同一地址的尝试次数过多;请等待一分钟。

一个代码只能使用一次。错误的code_verifier也会消耗它,因此泄露的代码无法被猜测利用。

与 OpenRouter 的区别

  • code_challenge 是必需的,并且只接受S256(OpenRouter 也接受plain或不带挑战码)。如果没有它,任何在浏览器历史记录或日志中看到代码的人都可能获取密钥。
  • workspace_id / required_workspace_id 不使用:一个 UberLLM 账户只有一个余额。