NovoConecte qualquer agente ao UberLLM: uma chave, todos os modelos, pelo preço de tabela ou menos.
UberLLM

Aplicativos: sejam listados e permitam que usuários se conectem

Duas coisas para pessoas que desenvolvem aplicativos no UberLLM. Ambas funcionam da mesma forma que no OpenRouter, então um aplicativo que já as faz só precisa mudar a base URL.

  1. Seja listado. Envie dois headers e seu aplicativo aparecerá em uberllm.dev/apps, classificado pelos tokens que envia. As páginas dos modelos listam os aplicativos que mais os utilizam.
  2. Permita que usuários se conectem. Envie usuários para o UberLLM, eles aceitam, e seu aplicativo recebe uma API key na conta deles. Eles pagam pelo próprio uso; você nunca lida com os detalhes de pagamento deles.

Seja listado no ranking de aplicativos

Adicione estes cabeçalhos às suas requisições (chat, mensagens ou mídia, qualquer endpoint):

Cabeçalho O que faz
HTTP-Referer Endereço do seu aplicativo, ex: https://myapp.com. Obrigatório: é o que identifica seu aplicativo. Referer também funciona.
X-Title Nome do seu aplicativo como as pessoas devem vê-lo. X-OpenRouter-Title também funciona.
X-OpenRouter-Categories Opcional. Até 2 das categorias abaixo, separadas por vírgula.
X-OpenRouter-App-Visibility Opcional. hidden mantém um novo aplicativo fora do ranking público.
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"}]}'

Com o SDK da OpenAI:

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',
  },
});

Como é contado:

  • Apenas o endereço é mantido: https://myapp.com/some/page?user=… é armazenado como https://myapp.com. Caminhos (paths), query strings e logins são descartados. Um link do GitHub, GitLab, Codeberg, Bitbucket ou Hugging Face mantém seu owner/repo, então aplicativos de código aberto recebem sua própria entrada.
  • O nome é cortado para 60 caracteres. Caracteres ocultos e de controle são removidos.
  • A primeira conta que envia tráfego para um aplicativo define seu nome e categorias. O tráfego de outras contas ainda conta para o aplicativo, mas não pode renomeá-lo.
  • Endereços na sua própria máquina ou rede (localhost, 127.0.0.1, IPs privados, *.local) nunca são mostrados publicamente.
  • Requisições de navegadores enviam Referer por conta própria, então um aplicativo web é contado mesmo sem os cabeçalhos. Adicione X-Title para escolher seu nome.
  • O ranking conta requisições que foram respondidas, por tokens, nas últimas 24 horas, 7 dias ou 30 dias. Ele é atualizado a cada poucos minutos.

Categorias: 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. As desconhecidas são ignoradas. Um aplicativo mantém até 10.

O ranking também é uma API: GET https://uberllm.dev/api/v1/public/apps?period=day|week|month&category=<slug>.

Conectar UberLLM (OAuth PKCE)

Seu aplicativo obtém uma chave na própria conta do usuário, nomeada com o nome do seu aplicativo. O usuário pode definir um limite de gastos para ela ao permiti-la, e pode desativá-la a qualquer momento em sua página de chaves.

1. Crie um verificador de código e um desafio

O verificador é uma string aleatória que você mantém (43 a 128 caracteres). O desafio é seu SHA-256, base64url-encoded sem preenchimento.

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. Envie o usuário para o UberLLM

https://uberllm.dev/auth?callback_url=https://myapp.com/uberllm/callback&code_challenge=<CHALLENGE>&code_challenge_method=S256
Parâmetro
callback_url Para onde o usuário retorna. Deve ser https://; http://localhost (qualquer porta) é permitido para desenvolvimento. Omita-o para mostrar o código na tela para o usuário colar em seu aplicativo.
code_challenge Do passo 1. Obrigatório.
code_challenge_method S256. Obrigatório. plain não é aceito.
key_label Nome opcional para a chave (padrão: nome do seu aplicativo).
state Opcional. Enviado de volta inalterado com o código, para que você possa verificar se a resposta pertence à solicitação que você iniciou.

O usuário faz login (ou se cadastra), vê "Seu aplicativo quer usar seu crédito UberLLM", e escolhe Permitir ou Cancelar. Em Permitir, eles são enviados para:

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

Em Cancelar, nada é enviado para lugar nenhum.

3. Troque o código por uma chave

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"}'

A resposta é {"key": "ull_…", "key_id": "…", "name": "My App"}. Use a chave como Authorization: Bearer em https://api.uberllm.dev/v1. O endpoint responde a solicitações de navegador de qualquer site (CORS), então funciona a partir de um aplicativo web.

Status Código Significado
400 invalid_code_challenge_method Use S256.
403 invalid_code Código errado ou code_verifier, ou o código já foi usado.
403 code_expired Os códigos funcionam por 10 minutos. Comece novamente do passo 2.
405 method_not_allowed Use POST.
429 rate_limited Muitas tentativas de um mesmo endereço; espere um minuto.

Um código funciona uma vez. Um code_verifier errado também o consome, então um código que vazou não pode ser adivinhado.

Diferenças do OpenRouter

  • code_challenge é obrigatório e apenas S256 é aceito (o OpenRouter também aceita plain ou nenhum desafio). Sem ele, qualquer um que veja o código no histórico do navegador ou em um log poderia pegar a chave.
  • workspace_id / required_workspace_id não são usados: uma conta UberLLM tem um único saldo.