NovitàCollega qualsiasi agente a UberLLM: una chiave, tutti i modelli, a prezzo di listino o meno.
UberLLM

App: fatti elencare e permetti agli utenti di connettersi

Due cose per chi sviluppa app su UberLLM. Entrambe funzionano allo stesso modo di OpenRouter, quindi un'app che le implementa già deve solo cambiare il base URL.

  1. Fatti elencare. Invia due header e la tua app apparirà su uberllm.dev/apps, classificata in base ai token che invia. Le pagine dei modelli elencano le app che li usano di più.
  2. Permetti agli utenti di connettersi. Invia gli utenti a UberLLM, loro acconsentono, e la tua app ottiene una API key sul loro account. Loro pagano per il proprio utilizzo; tu non gestisci mai i loro dettagli di pagamento.

Fatti elencare nella classifica delle app

Aggiungi queste intestazioni alle tue richieste (chat, messaggi o media, qualsiasi endpoint):

Intestazione Cosa fa
HTTP-Referer L'indirizzo della tua app, ad es. https://myapp.com. Obbligatorio: è ciò che identifica la tua app. Anche Referer funziona.
X-Title Il nome della tua app come le persone dovrebbero vederlo. Anche X-OpenRouter-Title funziona.
X-OpenRouter-Categories Opzionale. Fino a 2 delle categorie seguenti, separate da virgole.
X-OpenRouter-App-Visibility Opzionale. hidden mantiene una nuova app fuori dalla classifica pubblica.
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"}]}'

Con l'SDK di 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',
  },
});

Come viene conteggiato:

  • Viene mantenuto solo l'indirizzo: https://myapp.com/some/page?user=… viene memorizzato come https://myapp.com. Percorsi, stringhe di query e login vengono eliminati. Un link GitHub, GitLab, Codeberg, Bitbucket o Hugging Face mantiene il suo owner/repo, così le app open-source ottengono la propria voce.
  • Il nome viene tagliato a 60 caratteri. Caratteri nascosti e di controllo vengono rimossi.
  • Il primo account che invia traffico per un'app ne imposta il nome e le categorie. Il traffico degli altri account conta comunque per l'app, ma non può rinominarla.
  • Gli indirizzi sulla tua macchina o rete (localhost, 127.0.0.1, IP privati, *.local) non vengono mai mostrati pubblicamente.
  • Le richieste dai browser inviano Referer autonomamente, quindi un'app web viene conteggiata anche senza le intestazioni. Aggiungi X-Title per scegliere il suo nome.
  • La classifica conteggia le richieste a cui è stata data risposta, per token, nelle ultime 24 ore, 7 giorni o 30 giorni. Si aggiorna ogni pochi minuti.

Categorie: 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. Quelle sconosciute vengono ignorate. Un'app mantiene fino a 10.

La classifica è anche un'API: GET https://uberllm.dev/api/v1/public/apps?period=day|week|month&category=<slug>.

Connetti UberLLM (OAuth PKCE)

La tua app ottiene una chiave sull'account dell'utente, nominata come la tua app. L'utente può impostare un limite di spesa per essa mentre la autorizza, e può disattivarla in qualsiasi momento sulla sua pagina delle chiavi.

1. Crea un verificatore di codice e una challenge

Il verificatore è una stringa casuale che conservi (da 43 a 128 caratteri). La challenge è il suo SHA-256, base64url-encoded senza padding.

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. Invia l'utente a UberLLM

https://uberllm.dev/auth?callback_url=https://myapp.com/uberllm/callback&code_challenge=<CHALLENGE>&code_challenge_method=S256
Parametro
callback_url Dove l'utente torna. Deve essere https://; http://localhost (qualsiasi porta) è consentito per lo sviluppo. Omettilo per mostrare il codice sullo schermo affinché l'utente lo incolli nella tua app.
code_challenge Dal passaggio 1. Obbligatorio.
code_challenge_method S256. Obbligatorio. plain non è accettato.
key_label Nome opzionale per la chiave (predefinito: nome della tua app).
state Opzionale. Inviato indietro inalterato con il codice, così puoi verificare che la risposta appartenga alla richiesta che hai avviato.

L'utente effettua l'accesso (o si registra), vede "La tua app vuole usare il tuo credito UberLLM", e sceglie Consenti o Annulla. Su Consenti vengono inviati a:

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

Su Annulla non viene inviato nulla da nessuna parte.

3. Scambia il codice con una chiave

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

La risposta è {"key": "ull_…", "key_id": "…", "name": "My App"}. Usa la chiave come Authorization: Bearer su https://api.uberllm.dev/v1. L'endpoint risponde alle richieste del browser da qualsiasi sito (CORS), quindi funziona da una web app.

Stato Codice Significato
400 invalid_code_challenge_method Usa S256.
403 invalid_code Codice errato o code_verifier, o il codice è già stato usato.
403 code_expired I codici funzionano per 10 minuti. Ricominci dal passaggio 2.
405 method_not_allowed Usa POST.
429 rate_limited Troppi tentativi da un indirizzo; aspetta un minuto.

Un codice funziona una volta. Un code_verifier errato lo consuma anch'esso, quindi un codice che è trapelato non può essere indovinato.

Differenze da OpenRouter

  • code_challenge è obbligatorio e solo S256 è accettato (OpenRouter accetta anche plain o nessuna challenge). Senza di esso, chiunque veda il codice nella cronologia o nei log del browser potrebbe prendere la chiave.
  • workspace_id / required_workspace_id non sono usati: un account UberLLM ha un unico saldo.