Documentazione

La configurazione, passo a passo

Ogni frammento di questa pagina è pronto da incollare. I numeri — quote, limiti, valori predefiniti, nomi dei campi — sono letti dal codice in esecuzione: questa pagina e il server dicono la stessa cosa.

Per iniziare

Ottieni la tua chiave

Tutto qui tranne i feed RSS utilizza una chiave API. Apri il tuo account, sezione Developer API, e copiala. Il piano gratuito non richiede carta.

La chiave porta il tuo piano, e il tuo piano porta i tuoi volumi giornalieri. Due contatori funzionano affiancati: uno per l'API REST, uno per il server MCP. Un editor che fa alcune domande non consuma mai il tuo budget API.

Rigenerare la chiave dal tuo account revoca immediatamente quella vecchia. Qualsiasi cosa che la utilizza smette di funzionare — aggiorna prima le tue integrazioni.

Di che cosa ho bisogno?

Vuoi…Usare
Porre domande dal tuo editorServer MCP
Interrogare i dati dal tuo codiceREST API
Essere avvisato quando qualcosa cambiaWebhook
Collegarlo a n8n, Zapier o MakeAutomazioni
Controllare le dipendenze in ogni pull requestAzione GitHub
Segui in un lettore, nessuna chiaveFeed RSS

Server MCP

Il server MCP, in breve

MCP (Model Context Protocol) è un modo standard per un assistente AI di chiamare un servizio esterno. Incolli un indirizzo nel tuo client e l'assistente guadagna cinque strumenti che può usare mentre lavori. Quegli strumenti interrogano il catalogo olud.ai: progetti AI open-source, modelli AI con i loro prezzi e alternative open-source a prodotti commerciali.

FattoValore
Endpointhttps://olud.ai/mcp.php
MetodoPOST, JSON-RPC 2.0. GET restituisce 405 (vedi sotto)
TrasportoHTTP streamabile, un endpoint, nessun flusso SSE
Versione del protocollo2025-06-18. Se il client richiede 2025-03-26 o 2024-11-05, il server risponde in quella versione
Versione del server1.0.0
SessioneNessuna. Nessun Mcp-Session-Id da mantenere, nulla da scadere, nulla da riconnettere
Capacitàsolo strumenti. resources/list, resources/templates/list e prompts/list rispondono con liste vuote invece di un errore
AuthIntestazione della richiesta X-Api-Key. Facoltativa
BatchingNon supportato. Un array JSON-RPC viene rifiutato con HTTP 400

Il server legge. L'unica cosa che scrive è il tuo contatore di chiamate giornaliere.

Ogni risposta dello strumento porta l'URL della pagina corrispondente su olud.ai, più una linea di attribuzione: punteggi e indici sono calcolati da olud.ai, i fatti contestuali provengono da GitHub, Hugging Face, OpenRouter, PyPI, NPM e Docker Hub.

Installarlo, client per client

Stesso URL per ogni client: https://olud.ai/mcp.php. La chiave viaggia nell'intestazione X-Api-Key. Senza una chiave, il server risponde comunque, con un limite minore (25 chiamate al giorno per IP, 5 risultati per chiamata). La tua chiave e un blocco pronto da incollare si trovano nel tuo account, sezione server MCP.

Claude Code, un comando:

claude mcp add --transport http opensourceai https://olud.ai/mcp.php \
  --header "X-Api-Key: your-key"

# senza una chiave:
claude mcp add --transport http opensourceai https://olud.ai/mcp.php

# controlla cosa è stato registrato:
claude mcp list

Claude Desktop, claude_desktop_config.json:

{
  "mcpServers": {
    "opensourceai": {
      "type": "http",
      "url": "https://olud.ai/mcp.php",
      "headers": { "X-Api-Key": "your-key" }
    }
  }
}

Quel file si trova in ~/Library/Application Support/Claude/claude_desktop_config.json su macOS, e %APPDATA%\Claude\claude_desktop_config.json su Windows. Esci e riapri Claude Desktop dopo averlo modificato; legge il file all'avvio.

Se Claude Desktop mostra il server come non disponibile o non lo elenca affatto, la tua build accetta solo server locali (stdio). Collega con mcp-remote, che necessita di Node installato:

{
  "mcpServers": {
    "opensourceai": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://olud.ai/mcp.php",
               "--header", "X-Api-Key:${OSAI_KEY}"],
      "env": { "OSAI_KEY": "your-key" }
    }
  }
}
In quel blocco di collegamento, scrivi X-Api-Key:${OSAI_KEY} senza spazio dopo i due punti e metti il valore in env. mcp-remote divide un argomento di intestazione sugli spazi, e un'intestazione scritta inline perde il suo valore.

Cursor, .cursor/mcp.json nel progetto (o ~/.cursor/mcp.json per ogni progetto):

{
  "mcpServers": {
    "opensourceai": {
      "url": "https://olud.ai/mcp.php",
      "headers": { "X-Api-Key": "your-key" }
    }
  }
}

VS Code, .vscode/mcp.json nello spazio di lavoro:

{
  "servers": {
    "opensourceai": {
      "type": "http",
      "url": "https://olud.ai/mcp.php",
      "headers": { "X-Api-Key": "${input:osaiKey}" }
    }
  },
  "inputs": [
    { "id": "osaiKey", "type": "promptString",
      "description": "chiave API olud.ai", "password": true }
  ]
}
VS Code chiama l'oggetto di primo livello servers, non mcpServers. Copiare il blocco di Claude o Cursor così com'è è la ragione abituale per cui il server non appare mai. Il prompt degli input chiede la chiave al primo utilizzo, quindi il file rimane sicuro da impegnare.

Una chiave nell'URL come ?key=your-key funziona anche, perché il server la legge. Preferisci l'intestazione: le stringhe di query finiscono nella cronologia del browser, nei log del proxy e nella cronologia della shell.

Verificare che funzioni, con curl

Quando un client dice che un server non è disponibile, testa prima il server stesso. Questa chiamata elenca gli strumenti e non costa nulla: solo tools/call decrementa il tuo quota, quindi initialize, tools/list e ping sono gratuiti. Riavviare il tuo editor non consuma il giorno.

curl -s -X POST https://olud.ai/mcp.php \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: your-key" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Una risposta sana è HTTP 200 con {"jsonrpc":"2.0","id":1,"result":{"tools":[ ... ]}} e i cinque nomi all'interno. Successivamente, spendi una chiamata:

curl -s -X POST https://olud.ai/mcp.php \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: your-key" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"search_open_source_ai",
                 "arguments":{"query":"text to speech","limit":5}}}'

Una chiamata tools/call di successo porta due intestazioni di risposta da leggere: X-RateLimit-Limit è il tuo limite giornaliero, X-RateLimit-Remaining è ciò che rimane dopo questa chiamata. Sono impostati solo su tools/call.

Controllo di liveness più breve possibile. Risponde {"jsonrpc":"2.0","id":0,"result":{}} e non ha bisogno di chiave:

curl -s -X POST https://olud.ai/mcp.php \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":0,"method":"ping"}'

I cinque strumenti

Non chiami questi per nome. Fai una domanda, il client sceglie lo strumento. I nomi sono importanti quando leggi un log o scrivi tu stesso la chiamata, e sono abbinati esattamente: search_open_source_ai funziona, Search_Open_Source_AI non funziona.

StrumentoParametriLimiti e predefinitiRestituisce
search_open_source_aiquery (stringa, obbligatoria), limit (intero)limite limitato a 1 … il tuo tetto di risultati per chiamata. Predefinito 10, o il tuo tetto se è più bassocorrispondenze (totale trovato, non troncato), poi id, nome, riepilogo, stelle, linguaggio, licenza, github, pagina, punteggio di salute e etichetta, tendenza recente
get_projectprogetto (stringa, obbligatoria)Accetta uno slug (ollama-ollama), owner/repo, un URL completo di github.com, o il nome esatto del progettoTutto quanto sopra più proprietario, fork, creato, spinto, argomenti, il completo breakdown della salute, stelle guadagnate, e fino a 5 rilasci recenti
find_alternativesprodotto (stringa, obbligatoria)Nome del prodotto commerciale. Abbinato sul suo slug, poi sul suo nome esattoprodotto, pagina, e l'elenco delle alternative, a sua volta limitato dal tuo tetto di risultati per chiamata
list_modelsfornitore (string), max_price_out (numero), min_context (intero), free_only (booleano), limit (intero)fornitore è una sottostringa non sensibile al maiuscolo. max_price_out è dollari per milione di token di output. min_context è in token. limit è limitato a 1 … il tuo limite massimo, predefinito 15 o il tuo limite massimo se inferiorecorrispondenze, poi id, nome, fornitore, contesto, price_per_million (input e output), modalità, tool_calling e l'URL della leaderboard
progetti_trendingtipo (string), limit (intero)tipo è trending, emerging o top_health. Qualsiasi altra cosa torna a trending senza errore. Predefinito trending. limit è limitato a 1 … il tuo limite massimo, predefinito 10 o il tuo limite massimo se inferioretipo, le schede del progetto e il tempo di generazione dell'indice

Domande che raggiungono ogni strumento

  • search_open_source_ai — "Trova una libreria OCR open-source che posso eseguire localmente."
  • get_project — "Quanto è sano ollama/ollama in questo momento, e quando è stata l'ultima spedizione?"
  • find_alternatives — "Quale strumento open-source potrebbe sostituire Notion per noi?"
  • list_models — "Quali modelli hanno almeno 128k di contesto e costano meno di $1 per milione di token di output?"
  • trending_projects — "Quali progetti di AI open-source stanno guadagnando stelle più velocemente questa settimana?" Chiedi emerging invece per ottenere progetti sani che sono ancora poco conosciuti, o top_health per quelli meglio mantenuti.
La ricerca corrisponde al testo, non al significato. Assegna il punteggio più alto a un nome esatto, poi a un nome che inizia con le tue parole, poi a un nome che li contiene, poi a una descrizione che li contiene, e aggiunge punti per un tag tematico esatto. Una frase lunga non trova nulla; "sintesi vocale" non trova nulla che "testo in voce" non faccia. Quando una ricerca torna vuota, accorcia la query a una o due parole.

I filtri scartano ciò che non possono giudicare. Con max_price_out impostato, un modello il cui prezzo di output non abbiamo un valore è escluso piuttosto che indovinato. Con min_context impostato, un modello senza finestra di contesto registrata conta come zero ed è escluso. free_only mantiene i modelli il cui livello è esattamente gratuito.

Un limite superiore al tuo massimo non è un errore: viene limitato silenziosamente. Lo schema pubblicato dice massimo 100 perché è il più alto che qualsiasi piano consente, non ciò che la tua chiave consente. Un limite che non è un numero torna al predefinito.

Per alcuni prodotti, abbiamo una pagina di confronto scritta a mano e nessun elenco strutturato nell'indice leggibile dalla macchina. find_alternatives quindi risponde come successo con un array di alternative vuoto, dice che l'elenco strutturato non è nell'indice per questo, e fornisce l'URL della pagina. Un array vuoto lì non significa che non esista alcuna alternativa.

Volumi per piano

Nessuna chiaveGratuitoSviluppatoreProOrg
Chiamate al giorno252002,00020,000200,000
Risultati per chiamata5102550100

Due limiti, perché fermano due cose diverse: le chiamate al giorno limitano il carico, i risultati per chiamata limitano quanti cataloghi escono in una risposta.

  • Le chiamate MCP sono contate separatamente dalle chiamate API REST. Stessa chiave, due contatori. Un editor che pone alcune domande non tocca mai il tuo budget API.
  • Solo tools/call è conteggiato. initialize, tools/list e ping non costano nulla.
  • Entrambi i contatori si azzerano a 00:00 UTC.
  • Senza una chiave, il conteggio è per indirizzo IP. Tutti dietro un IP di ufficio condividono i 25.
  • Su Free e senza chiave, ogni risposta termina con una riga di nota che indica i tuoi due limiti. Le risposte Dev, Pro e Org non portano tale riga.
  • Org è il piano chiamato business all'interno del sistema. I messaggi di errore stampano il nome interno.

Quando non funziona

Uno strumento che fallisce restituisce HTTP 200 con isError impostato su true e il motivo come testo semplice. Questo è deliberato: il modello legge il motivo e può provare qualcos'altro. Significa anche che un 200 nel tuo registro proxy non è prova che la chiamata abbia funzionato. Leggi il corpo.

Chiave digitata in modo errato, o revocata. Ogni domanda fallisce con:

Quella chiave API è sconosciuta o è stata revocata. Rimuovila per utilizzare il piano gratuito,
o ottieni una nuova chiave su https://olud.ai/account.html

Una chiave errata non torna silenziosamente all'assegnazione anonima. Correggi la chiave o rimuovi completamente l'intestazione X-Api-Key, quindi riavvia il client in modo che legga di nuovo la configurazione.

Limite giornaliero raggiunto. Con una chiave, poi senza:

Quota giornaliera MCP raggiunta (200 chiamate/giorno sul piano "free"). Si azzera a 00:00 UTC.
Livelli superiori: https://olud.ai/plans.html

Limite anonimo raggiunto (25 chiamate/giorno per IP). Si azzera a 00:00 UTC.
Una chiave API gratuita lo porta a 200/giorno — https://olud.ai/account.html

Niente è rotto e niente è addebitato. Aspetta le 00:00 UTC, o passa a un piano superiore. Se non hai una chiave, una chiave gratuita ti porta da 25 a 200 chiamate e da 5 a 10 risultati per chiamata.

Nome dello strumento non uno dei cinque:

Strumento sconosciuto "list_projects". Chiama tools/list per vedere cosa è disponibile.

Un argomento richiesto è mancante. Ogni messaggio mostra la forma che desidera:

Manca "query". Esempio: {"query": "testo in voce"}
Manca "project". Esempio: {"project": "ollama/ollama"}
Manca "product". Esempio: {"product": "Midjourney"}

Niente trovato. Entrambi i messaggi ti dicono dove andare dopo:

Nessun progetto trovato per "ollamaa". Prova prima search_open_source_ai per ottenere il suo id esatto.

Non tracciamo ancora "photoshop". Corrispondenze più vicine: <fino a 8 nomi>.
Elenco completo: https://olud.ai/alternatives-hub.html

Il catalogo è in fase di ricostruzione. Aspetta un minuto e chiedi di nuovo; queste sono le quattro formulazioni, una per set di dati:

Il catalogo è in fase di ricostruzione. Prova di nuovo tra un minuto.
Quell'elenco è in fase di ricostruzione. Prova di nuovo tra un minuto.
Il catalogo dei modelli non è disponibile in questo momento.
L'indice delle alternative non è disponibile in questo momento.

Aprire https://olud.ai/mcp.php in un browser restituisce HTTP 405. Questa è la risposta corretta: l'endpoint parla JSON-RPC su POST, e la specifica richiede 405 quando un server non offre alcun flusso GET. Il corpo ti dice cosa fare e porta la configurazione da copiare. Arriva su una riga; è spaziato qui per essere letto.

{
  "server": "olud.ai MCP",
  "version": "1.0.0",
  "protocol": "2025-06-18",
  "usage": "Questo endpoint parla MCP tramite JSON-RPC 2.0. Invia una richiesta POST da un client MCP.",
  "config": { "mcpServers": { "opensourceai": { "url": "https://olud.ai/mcp.php" } } },
  "tools": ["search_open_source_ai", "get_project", "find_alternatives",
            "list_models", "trending_projects"],
  "docs": "https://olud.ai/api.html"
}

Rifiuti a livello di trasporto. Quattro di questi portano un codice di errore JSON-RPC, e i primi tre portano anche un codice di errore HTTP:

405  -32600  Usa POST con un corpo JSON-RPC 2.0.          (PUT, DELETE, HEAD…)
400  -32700  Errore di parsing: il corpo non è un JSON valido.
400  -32600  Il batching JSON-RPC non è supportato (rimosso in MCP 2025-06-18).
200  -32601  Metodo sconosciuto "tools/execute".
200  -32602  Nome dello strumento mancante nei parametri.

Se il tuo client si lamenta di un id sessione mancante, ignoralo e controlla il tipo di trasporto nella tua configurazione. Questo server non mantiene sessioni e non c'è un Mcp-Session-Id da restituire. Un client configurato per stdio o per SSE contro questo URL fallirà prima della prima chiamata; il tipo è http.

REST API

Autenticazione e chiavi

URL di base: https://olud.ai/api/v1. Ogni endpoint è un GET. L'intestazione CORS pubblicizza POST, ma v1 non ha una rotta POST: i parametri vengono sempre letti dalla stringa di query.

Invia la tua chiave nell'intestazione X-Api-Key. Un parametro di query ?key= funziona anche, per una scheda del browser o un test rapido. Se entrambi sono presenti, vince l'intestazione. Solo /meta funziona senza una chiave.

Entrambe le forme sono accettate:

curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  "https://olud.ai/api/v1/projects?limit=3"

curl -s "https://olud.ai/api/v1/projects?limit=3&key=osk_YOUR_KEY"

Per ottenere una chiave: accedi su olud.ai e apri la tua pagina account, sezione Developer API. La chiave viene creata alla tua prima visita, nel piano gratuito, e appare come osk_ seguito da 40 caratteri esadecimali. Ruotarla dalla stessa pagina elimina immediatamente la vecchia chiave — il vecchio valore restituisce quindi 403 invalid_key.

IntestazioneValoreInviato il
X-RateLimit-LimitIl tuo tetto giornaliero, come interoOgni richiesta che ha superato il controllo della chiave
X-RateLimit-RemainingRichieste rimaste oggi, arrotondate a 0Ogni richiesta che ha superato il controllo della chiave, incluso il 429
ETagMD5 quotato del tempo di costruzione del grafo dei progettiOgni endpoint tranne /meta
Access-Control-Allow-Origin*Ogni risposta, incluso OPTIONS (che risponde 204)
CORS è aperto e X-Api-Key è un'intestazione consentita, quindi un browser può chiamare direttamente l'API. Chiunque legga il sorgente della tua pagina ha quindi la tua chiave e consuma il tuo quota. Chiama l'API dal tuo server e passa i risultati.
Il controllo della chiave viene eseguito prima del routing. Un percorso scritto male senza chiave restituisce 401 missing_key, non 404. Aggiungi la chiave prima di cercare un errore di battitura nel percorso.

Involucro di risposta

Un successo è sempre HTTP 200 con tre chiavi di primo livello: ok è true, data contiene il payload, meta contiene il contesto. data è un oggetto sugli endpoint a singolo record e un array sugli endpoint di elenco.

GET /api/v1/meta, letteralmente:

{"ok":true,"data":{"name":"olud.ai API","version":"v1","generated":"2026-07-27T07:45:15+00:00","counts":{"projects":10142},"endpoints":["/project/{id}","/projects","/emerging","/alternatives/{id}","/search?q=","/models"],"docs":"https://olud.ai/api/"},"meta":{"attribution":"Punteggi & indici calcolati da olud.ai (olud.ai). Fatti contestuali da fonti pubbliche: GitHub, Hugging Face, OpenRouter, Artificial Analysis, PyPI, NPM, Docker Hub."}}

meta.attribution è impostato su ogni risposta di successo, su ogni endpoint, e non può essere disattivato. Il resto di meta varia a seconda dell'endpoint: generated, total, limit, offset, sort, freshness, points. Leggi le sezioni degli endpoint per quali campi ottieni.

Un errore porta ok false, uno stato HTTP diverso da 200, e error.code più error.message. Non c'è un oggetto meta su un errore, quindi nessun campo di attribuzione. Testa ok prima di leggere data — non assumere la forma di successo.

GET /api/v1/projects senza chiave, letteralmente:

{"ok":false,"error":{"code":"missing_key","message":"Fornisci la tua chiave API tramite l'intestazione X-Api-Key (o ?key=). Ottienila su https://olud.ai/api/"}}

Invia l'ETag come If-None-Match e riceverai 304 con un corpo vuoto quando il grafo non è stato ricostruito. Il grafo viene ricostruito ogni mattina, quindi il polling più frequente di così restituisce 304 tutto il giorno.

Due cose da sapere sull'ETag. Viene calcolato solo dal grafo dei progetti, quindi lo stesso valore viene restituito da /models, /hf e /history — invia un ETag all'endpoint da cui l'hai ricevuto, o riceverai un 304 mentre nuovi dati sono dietro di esso. E la quota viene conteggiata prima che l'ETag venga confrontato, quindi un 304 costa comunque una richiesta.

Endpoint: meta e progetti

GET /meta

Stato del grafo. L'unico endpoint senza chiave, e l'unico che non conta contro la tua quota. Restituisce il nome e la versione dell'API, generated (timestamp UTC dell'ultima costruzione del grafo), counts.projects, un elenco di endpoint e l'URL della documentazione. Nessun parametro. Se i file del grafo non sono leggibili, counts è nullo e la chiamata restituisce comunque 200 — usalo come controllo di salute e per decidere se un nuovo recupero ne vale la pena. Non invia ETag e intestazioni di limite di frequenza.

curl -s https://olud.ai/api/v1/meta

GET /project/{id}

Un progetto, record completo. Questa è la vista unificata: fatti di GitHub, il nostro punteggio di manutenzione, velocità delle stelle, rilasci, impulso di adozione.

  • Identità: id, nome, proprietario, url, pagina (percorso della pagina del progetto sul sito), desc.
  • Fatti di GitHub alla ultima costruzione: stelle, fork, lang, license, topics, created, pushed.
  • salute: punteggio su 100, etichetta, perché, più i quattro componenti di cui è composto — attività (max 30), slancio (max 20), comunità (max 30), manutenzione (max 20) — pesi v2 dal 29 luglio 2026 — e controllato. Le etichette seguono il punteggio: 85+ Fiorente, 70+ Sano, 50+ Manutenuto, 30+ In rallentamento, sotto 30 A rischio. Un progetto senza commit in quattro settimane ha il punteggio limitato a 45, quindi i componenti possono sommarsi a più del punteggio. Non tutti i progetti sono valutati; prova per il campo.
  • velocità: stelle_1d e stelle_7d, dalla nostra storia quotidiana delle stelle.
  • rilasci: tag, data, livello, url — più recente per primo.
  • strumento: slug, cat, pulse, docker_pulls, npm_month, pip_month, hn_hits, bsky_week, compare_pages. Presentato solo per progetti abbinati a uno strumento tracciato.
  • classifica, tendenza (stabile, tranquilla o in accelerazione) e segnali (stars_accel, has_page).
ParametroTipoPredefinitoComportamento
idsegmento del percorso, richiestonessunoIn minuscolo. Risolto in tre passaggi: slug esatto, poi l'indice proprietario/nome, poi proprietario-nome. Nessun segmento restituisce 400 missing_id; nessuna corrispondenza restituisce 404 not_found con un puntatore a /search.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  https://olud.ai/api/v1/project/ollama-ollama
Usa lo slug con il trattino. Una barra letterale nel percorso inizia un nuovo segmento di percorso, quindi /v1/project/ollama/ollama cerca "ollama" e restituisce 404. Gli id restituiti da /projects e /search sono sempre sicuri da passare.

GET /projects

Filtra, ordina e pagina il catalogo. I filtri si applicano per primi, poi l'ordinamento, poi offset e limite.

ParametroTipo / limitiPredefinitoComportamento
langstringanessun filtroCorrispondenza esatta sulla lingua del progetto, non sensibile al maiuscolo. lang=rust mantiene solo Rust.
licenzastringanessun filtroCorrispondenza parziale sull'id della licenza, non sensibile al maiuscolo. license=gpl mantiene GPL-2.0 e AGPL-3.0.
verticalestringanessun filtroCorrispondenza esatta, non sensibile al maiuscolo. Valori presenti nel grafico: robotica, sicurezza, finanza, scienza, sanità, istruzione, legale. La maggior parte dei progetti non ne ha, e tutti scompaiono quando imposti questo.
health_mininteronessun filtroMantiene i progetti il cui health.score è maggiore o uguale al valore. I progetti non valutati contano come 0 e vengono esclusi. Un valore non numerico diventa 0, il che non filtra nulla.
ordinastelle, salute, slancio o recentestelleSempre in ordine decrescente. lo slancio legge velocity.stars_7d, recente legge la data dell'ultimo push. Un valore sconosciuto ordina per stelle ma viene restituito letteralmente in meta.sort — controlla meta.sort se l'ordine ti sorprende.
limiteintero 1-10025I valori fuori intervallo vengono limitati ai limiti, i valori non numerici tornano a 25. Non viene sollevato alcun errore, quindi limit=500 ti dà silenziosamente 100.
offsetintero 0-1000000Limitato allo stesso modo.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  "https://olud.ai/api/v1/projects?lang=python&license=apache&sort=health&health_min=70&limit=10"

i dati sono un array di schede compatte: id, nome, url, desc, stelle, lang, licenza, salute (solo il punteggio), slancio (stars_7d), tendenza, verticale. I campi senza valore sono presenti e nulli. Per i componenti, le versioni e i dati di adozione, chiama /project/{id}. meta fornisce totale (corrispondenze dopo il filtraggio, prima della paginazione), limite, offset, ordinamento e generato.

Endpoint: ricerca, emergenti, alternative

GET /search

Cerca progetti per nome, descrizione e argomenti. Non cerca modelli o righe di Hugging Face — usa /models e /hf per quelli.

ParametroTipo / limitiPredefinitoComportamento
qstringa, obbligatorianessunoTrimmata e in minuscolo. Vuota o contenente solo spazi restituisce 400 missing_query.
limiteintero 1-5015Limitato ai limiti; non numerico torna a 15.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  "https://olud.ai/api/v1/search?q=ocr&limit=5"

Punteggio, così puoi prevedere l'ordine: corrispondenza esatta del nome 100, il nome inizia con q 60, il nome contiene q 40, la descrizione contiene q 15, e +20 quando q è esattamente uno degli argomenti del progetto. I pareggi si risolvono in base alle stelle. Qualsiasi punteggio di 0 viene scartato. La corrispondenza è una sottostringa semplice — niente stemming, nessuna tolleranza agli errori. Le schede hanno la stessa forma di /projects. meta fornisce il totale (tutte le corrispondenze, non la pagina) e q come normalizzato.

GET /emerging

L'indice di scoperta giornaliero: repository giovani con crescita sostenuta e, dove possiamo valutarli, buona salute. Classificati dal nostro Discovery Score. Le schede contengono due campi extra: segnali e rilevati, la data in cui il progetto è entrato per la prima volta nell'indice (null quando sconosciuto).

ParametroTipo / limitiPredefinitoComportamento
limiteintero 1-10025Limitato. Puoi ricevere meno righe di quelle richieste: gli id che non sono più nel grafo dei progetti vengono saltati.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  "https://olud.ai/api/v1/emerging?limit=10"

La freschezza dipende dal piano, e meta indica quale hai ottenuto. Pro e Business leggono l'indice di questa mattina e ottengono meta.freshness "realtime". Free e Dev leggono lo snapshot di ieri e ottengono "previous-day" più una meta.note. Due conseguenze da conoscere: su Free e Dev, meta.criteria è null, perché il testo dei criteri è memorizzato solo con l'indice attuale; e se il file dello snapshot di ieri è mancante, a Free e Dev viene servito l'indice attuale mentre meta.freshness continua a leggere "previous-day".

GET /alternatives/{product}

Alternative open-source a un prodotto commerciale. data restituisce nome, dominio, descrizione, pagina, categoria e un array di alternative i cui elementi contengono nome, repo, sito, licenza e descrizione. repo può essere una stringa vuota quando il progetto non ha un repository GitHub. meta fornisce generato.

ParametroTipoPredefinitoComportamento
prodottosegmento del percorso, richiestonessunoIn minuscolo. Chiave del prodotto esatta prima; in caso contrario, il primo prodotto la cui chiave o nome contiene la tua stringa, in ordine di file. Nessun segmento restituisce 400 missing_id; nessuna corrispondenza restituisce 404 not_found. Passa lo slug esatto — quello nell'URL della pagina /alternatives/<slug>.html — quando hai bisogno di un prodotto specifico, perché la corrispondenza approssimativa prende il primo colpo, non il migliore.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  https://olud.ai/api/v1/alternatives/notion

Endpoint: modelli, hf, storia

GET /models

Catalogo dei modelli costruito da OpenRouter. Ogni riga: id, nome, fornitore, tier, ctx (finestra di contesto in token), price_in e price_out (dollari USA per milione di token, arrotondati a due decimali, 0 quando la fonte non riporta alcun prezzo), modalità (ad esempio text->text o text+image+file->text), strumenti (booleano) e rank. I campi senza valore vengono scartati dalla riga, quindi controlla la presenza piuttosto che assumere che price_in esista. meta fornisce totale, limite, offset, generato e fonte.

ParametroTipo / limitiPredefinitoComportamento
fornitorestringanessun filtroCorrispondenza di sottostringa, non sensibile al maiuscolo. provider=mistral corrisponde a "Mistral AI".
tiergratuito o a pagamentonessun filtroCorrispondenza esatta, non sensibile al maiuscolo sulla tua input.
limiteintero 1-20050Limitato ai limiti; non numerico torna a 50.
offsetintero 0-1000000Applicato alla lista unita. Le righe open-weight vengono prima, poi quelle proprietarie, ciascun blocco in ordine di rank.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  "https://olud.ai/api/v1/models?tier=free&provider=mistral&limit=20"
tier non è un flag di prezzo. gratuito significa che i pesi sono pubblicati (open-weight), a pagamento significa proprietario. Un modello open-weight può avere un price_in non zero, perché il prezzo è ciò che un fornitore API addebita per eseguirlo. Inoltre, il rank riparte da 1 in ciascun tier, quindi ordinare la lista unita per rank mescola due scale.

GET /hf

Hugging Face: più scaricati e di tendenza. Nessun parametro. data ha tre array — top_llm (modelli di generazione di testo per download negli ultimi 30 giorni), top (tutti i compiti, limitato a 30 righe da questo endpoint) e trending (i salitori di oggi). Ogni riga: id, org, nome, compito, download (rolling 30 giorni), mi piace, licenza, gated, creato, aggiornato, trend (aumento dei mi piace sulle righe di tendenza, null altrove). meta fornisce generato e fonte.

curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  https://olud.ai/api/v1/hf
Questo endpoint dipende da una scansione mattutina dell'Hugging Face Hub. Prima che quel file esista, la chiamata restituisce 503 not_ready. Niente da parte tua è sbagliato; riprova più tardi nella giornata.

GET /history/{slug}

Serie giornaliera per un progetto: stelle, salute e velocità a 7 giorni. Solo chiavi Pro e Business — il piano Business è quello venduto come Org. Qualsiasi altro piano ottiene 403 pro_required. data restituisce slug, giorni (date nel formato YYYY-MM-DD, più vecchie prima) e serie con tre array, stelle, salute e velocità_7d, allineati indice per indice con i giorni. Le voci individuali possono essere null quando il valore di un giorno era mancante. meta fornisce punti e finestra.

ParametroTipoPredefinitoComportamento
slugsegmento del percorso, richiestonessunoIn minuscolo, e deve corrispondere a ^[a-z0-9][a-z0-9._-]*$ — lo stesso id di /project/{id}. Qualsiasi altra cosa restituisce 400 bad_slug. Uno slug valido senza nulla registrato restituisce 404 not_found.
curl -s -H "X-Api-Key: osk_YOUR_KEY" \
  https://olud.ai/api/v1/history/ollama-ollama
meta.window legge sempre "90 giorni rolling" — questo è il limite mantenuto al momento della costruzione, non una promessa di 90 punti. La registrazione inizia quando un progetto entra nel grafo, quindi serie brevi sono normali. Leggi meta.points per ciò che hai effettivamente ricevuto, e dimensiona il tuo grafico dai giorni, mai da un 90 hard-coded.

Quote giornaliere

Le richieste sono conteggiate per chiave, per giorno UTC. Il contatore si azzera a 00:00 UTC. Non ci sono limiti per secondo o per minuto nel codice.

Piano sulla chiaveRichieste / giornoNome pubblicoCosa cambia
gratuito500GratuitoTutto tranne /history. /emerging serve l'indice del giorno precedente.
sviluppo5000SviluppatoreStesso accesso di Free, limite più alto.
pro50000Pro/history si apre. /emerging serve l'indice di questa mattina.
business500000OrgStesso accesso di Pro, limite più alto.

Cosa conta: ogni endpoint tranne /meta, un'unità per richiesta. Il contatore viene incrementato subito dopo il controllo della chiave e prima di qualsiasi altra cosa, quindi un 304, un 404 not_found, un 400 missing_query e un 503 graph_unavailable costano tutti un'unità. Solo 401 missing_key e 403 invalid_key non costano nulla, poiché non c'è una chiave valida da addebitare.

Un campo quota impostato sulla tua chiave sovrascrive il valore predefinito del piano. X-RateLimit-Limit è l'autorità sul tuo limite, non la tabella sopra.

Superato il limite, ogni richiesta restituisce 429 quota_exceeded fino al reset. La richiesta rifiutata non viene conteggiata, nulla viene messo in coda e nulla viene addebitato. Nessun header Retry-After viene inviato — il reset è a 00:00 UTC.

Come appare una richiesta rifiutata su una chiave gratuita:

HTTP/2 429
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 0

{"ok":false,"error":{"code":"quota_exceeded","message":"Quota giornaliera raggiunta (500 richieste/giorno sul piano \"free\"). Si resetta a 00:00 UTC."}}
Il server MCP su /mcp.php ha il proprio contatore: 25 chiamate/giorno senza chiave (conteggiate per IP), 200 su Free, 2000 su Dev, 20000 su Pro, 200000 su Business. Le domande che il tuo editor pone tramite MCP non consumano la quota REST, e viceversa.
Un modo di errore da riconoscere: se il file del contatore non può essere aperto, le richieste vengono lasciate passare e X-RateLimit-Remaining legge 0. Un 200 insieme a Remaining: 0 significa che il contatore non era disponibile, non che sei a corto di quota.

Codici di errore

Ogni errore restituisce error.code come stringa stabile. Fai branching su quello, non sul testo del messaggio, che contiene slugs e nomi di piano e cambia con la richiesta.

HTTPcodiceAttivaCosa fare
401missing_keyNessun header X-Api-Key e nessun ?key=. Anche ciò che ottieni per un percorso sconosciuto quando non viene inviata alcuna chiave, poiché il controllo della chiave avviene prima del routing.Invia la chiave. Un 401 su un percorso di cui sei sicuro che esista è un header mancante, non un percorso errato.
403invalid_keyLa chiave non è nel negozio, o il suo flag attivo è falso. Ruotare la tua chiave elimina la precedente.Leggi la chiave attuale dalla tua pagina dell'account e aggiorna il chiamante. La rotazione interrompe ogni copia distribuita della vecchia chiave contemporaneamente.
403pro_required/history chiamato con una chiave gratuita o di sviluppo.Leggi i valori di oggi da /project/{id} (salute, velocità), o passa a Pro.
429quota_exceededIl contatore giornaliero ha raggiunto il tuo limite.Smetti di chiamare fino a 00:00 UTC, o aumenta il piano. Leggi X-RateLimit-Limit per confermare il tuo vero limite.
400missing_id/project o /alternatives chiamato senza segmento di percorso.Aggiungi il segmento. /v1/project da solo non è un elenco — usa /v1/projects.
400query_mancante/search con q vuoto o solo spazi bianchi.Invia un q non vuoto. Nota che la richiesta è stata comunque conteggiata.
400slug_non_valido/history slug vuoto o contenente un carattere al di fuori di ^[a-z0-9][a-z0-9._-]*$.Passa l'id esattamente come restituito da /projects o /search.
404non_trovatoID progetto sconosciuto, nessuna alternativa tracciata per quel prodotto, o nessuna storia memorizzata per quel slug.Per un progetto, riprova tramite /search?q=. Per la storia, il progetto potrebbe essere entrato nel tracciamento troppo recentemente per avere punti.
404endpoint_sconosciutoChiave valida, percorso non presente nel router.Controlla l'ortografia. /meta elenca sei endpoint e omette /hf e /history, che esistono entrambi.
503grafico_non_disponibileUn file grafico è mancante o illeggibile, il che accade mentre la build mattutina lo scrive.Riprova tra un minuto. La tua chiave è valida; non ruotarla.
503non_pronto/hf prima che la scansione mattutina di Hugging Face abbia prodotto il suo file.Riprova più tardi durante la giornata. Altri endpoint non sono influenzati.
304nessun corpoIf-None-Match ha corrisposto all'ETag corrente.Servi la tua copia cache. Ricorda che ha consumato una richiesta dal tuo quota.

Politica di ripetizione che corrisponde al codice: ripeti su 503 dopo un minuto, e su 429 solo dopo il reset UTC. Non ripetere mai un 400, 403 o 404 invariato — la risposta non cambierà e ogni tentativo costa una richiesta.

Valida i parametri da parte tua prima di inviare. I valori di limite e offset fuori intervallo vengono silenziosamente limitati piuttosto che rifiutati, quindi un valore errato ti costa una richiesta e restituisce una pagina che non hai richiesto. Confronta meta.limit e meta.offset con ciò che hai inviato quando un risultato sembra breve.

Webhook

Creazione di un webhook

Un webhook è un POST firmato al tuo endpoint per ogni evento. Scegli gli eventi, i repository e la forma del corpo. I webhook necessitano di un piano a pagamento: con una chiave gratuita, la creazione restituisce 403 paid_feature e la pagina dell'account mostra un pannello bloccato invece del modulo.

Piano riportato dall'APIWebhook consentiti
gratuito0
sviluppo3
pro10
business50

Un nome di piano che non riconosciamo torna a 1. Una volta raggiunto il tuo conteggio, la creazione restituisce 429 limit_reached — elimina uno o cambia piano.

Dal tuo account

  • Accedi e apri /account.html. La scheda Webhooks appare una volta che la tua chiave API è stata caricata, e rimane nascosta fino ad allora.
  • Incolla il tuo endpoint nel campo URL. La pagina rifiuta qualsiasi cosa che non inizi con https://.
  • Seleziona gli eventi. release e health sono selezionati per te; license e new_project non lo sono.
  • Lascia il campo repos vuoto per ricevere tutto, oppure digita le voci owner/name separate da virgole.
  • Scegli la destinazione nel selettore: il tuo stesso endpoint (JSON firmato raw), Slack o Discord.
  • Premi Crea. Il segreto appare una sola volta, in una casella verde. Copialo prima di lasciare la pagina — non verrà mostrato di nuovo.
  • Ogni riga del webhook porta quindi un pulsante Invia ping di test e un link Elimina. Eliminare ferma immediatamente le consegne.

Dall'API — crea. La tua chiave API è quella nel tuo account, inviata come X-Api-Key (o ?key=).

curl -sS -X POST https://olud.ai/api/webhooks.php \
  -H "X-Api-Key: $OSAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "url": "https://your-app.example/osai-hook",
        "events": ["release", "health", "license"],
        "repos": ["acme/inference-server", "acme/tiny-router"],
        "format": "json"
      }'

Il blocco dati della risposta. Ogni risposta porta anche un blocco meta con la nostra linea di attribuzione. Il segreto è qui e da nessun'altra parte.

{
  "id": "whk_9b41c7e2f0a5d3861c4e",
  "url": "https://your-app.example/osai-hook",
  "events": ["release", "health", "license"],
  "repos": ["acme/inference-server", "acme/tiny-router"],
  "secret": "whs_7d2a19f4c6b03e58a1d7f492c0b6e35847ac91d2e6f0b8a3",
  "note": "Conserva questo segreto ora — viene mostrato solo una volta. Verifica ogni consegna: X-OSAI-Signature == \"sha256=\" + HMAC_SHA256(raw_body, secret). Testalo: POST {\"ping\":\"whk_9b41c7e2f0a5d3861c4e\"}."
}

Cosa deve soddisfare l'URL

  • Schema https. http è rifiutato.
  • Un host deve essere presente.
  • Se scrivi una porta, deve essere 443. https://your-app.example:8443/hook è rifiutato.
  • L'host non può essere localhost e non può terminare con .local o .internal.
  • Risolviamo l'host. Se un indirizzo restituito si trova in un intervallo privato o riservato, l'URL è rifiutato.
  • Non chiamiamo il tuo endpoint durante la creazione. Un host che non riesce a risolversi supera questo controllo e fallisce più tardi, durante la consegna. Invia un ping di prova per scoprirlo.
  • Un URL errato restituisce 400 bad_url.

Quali repo accetta

  • Il predefinito è ["*"] — ogni repository che tracciamo.
  • Le voci vengono troncate e convertite in minuscolo, quindi il confronto è insensibile al maiuscolo.
  • Un'entrata deve apparire come owner/name: owner inizia con una lettera o un numero, seguito da lettere, numeri, punto, underscore, trattino.
  • Le voci che non corrispondono vengono eliminate senza parole. Se nulla sopravvive, ricevi 400 bad_repos.
  • "*" ovunque nella lista sostituisce l'intera lista. ["acme/one", "*"] è memorizzato come ["*"].
  • Più di 100 voci restituisce 400 too_many_repos. Usa "*" oltre quel punto.

I quattro eventi

Ogni evento porta un repository. Un evento è un POST — gli eventi non vengono mai raggruppati insieme. Il nome si trova nell'intestazione X-OSAI-Event e nel campo evento del corpo.

eventoSi attiva quandoChiavi all'interno dei dati
salutel'etichetta di salute di un repository cambiada, a, stelle, pagina
rilascioun nuovo tag di rilascio appare per un repositorytag, nome, url
licenzala licenza che possediamo per un repository cambiada, a
nuovo_progettoun repository entra nella directorystelle, pagina

salute

{
  "webhook_id": "whk_9b41c7e2f0a5d3861c4e",
  "event": "health",
  "repo": "acme/inference-server",
  "data": {
    "from": "Thriving",
    "to": "Slowing down",
    "stars": 58120,
    "page": "https://olud.ai/project/acme-inference-server.html"
  },
  "sent_at": "2026-07-27T05:41:12+00:00"
}

da e a sono etichette, non numeri. Le sei etichette che pubblichiamo: Thriving, Healthy, Maintained, Slowing down, At risk, Archived. stelle è il conteggio delle stelle che possediamo per il repository. Nessun evento si attiva la prima volta che un repository ottiene un'etichetta — un cambiamento ha bisogno di un valore precedente con cui confrontarsi.

rilascio

{
  "webhook_id": "whk_9b41c7e2f0a5d3861c4e",
  "event": "release",
  "repo": "acme/inference-server",
  "data": {
    "tag": "v0.6.2",
    "name": "Acme Inference Server",
    "url": "https://github.com/acme/inference-server/releases"
  },
  "sent_at": "2026-07-27T05:41:12+00:00"
}

tag è il tag git. name è il nome visualizzato del progetto nella nostra directory, non il titolo del rilascio. url punta sempre alla pagina dei rilasci del repository, mai a un rilascio specifico — costruisci tu stesso l'URL del tag se ne hai bisogno.

licenza

da e a sono le stringhe di licenza che possediamo. Questo evento non ha una chiave pagina.

{
  "webhook_id": "whk_9b41c7e2f0a5d3861c4e",
  "event": "license",
  "repo": "acme/inference-server",
  "data": {
    "from": "Apache-2.0",
    "to": "BSL-1.1"
  },
  "sent_at": "2026-07-27T05:41:12+00:00"
}

nuovo_progetto

{
  "webhook_id": "whk_9b41c7e2f0a5d3861c4e",
  "event": "new_project",
  "repo": "acme/tiny-router",
  "data": {
    "stars": 1840,
    "page": "https://olud.ai/project/acme-tiny-router.html"
  },
  "sent_at": "2026-07-27T05:41:12+00:00"
}

Al massimo 25 eventi new_project per esecuzione, conteggi di stelle più alti per primi. In una prima esecuzione, o quando più di 200 repository appaiono contemporaneamente, vengono registrati e nessuno viene inviato — quella protezione impedisce a un re-import di inondarti.

Corpo e intestazioni

Con formato json, il corpo ha cinque chiavi, in quest'ordine. Nient'altro viene aggiunto.

{
  "webhook_id": "whk_9b41c7e2f0a5d3861c4e",
  "event": "release",
  "repo": "acme/inference-server",
  "data": { },
  "sent_at": "2026-07-27T05:41:12+00:00"
}

webhook_id è l'id che hai creato: whk_ più 20 caratteri esadecimali. repo è il proprietario/nome in minuscolo, ed è nullo solo su un ping di prova. data è un oggetto, vuoto per un evento che non porta campi. sent_at è UTC, ISO 8601 con un offset.

IntestazioneValore
Content-Typeapplication/json
User-Agentolud.ai-Webhooks/1.0
X-OSAI-Eventsalute, rilascio, licenza, nuovo_progetto o ping
X-OSAI-Delivery16 caratteri esadecimali, freschi per ogni POST
X-OSAI-Signaturesha256= seguito dall'HMAC-SHA256 del corpo

Quei cinque sono l'intero insieme. X-OSAI-Delivery non è memorizzato da parte nostra — usalo per individuare un duplicato nel tuo log.

Un ping di test, inviato tramite POST {"ping":"whk_…"}. Stesse intestazioni, stessa firma, X-OSAI-Event: ping.

{
  "webhook_id": "whk_9b41c7e2f0a5d3861c4e",
  "event": "ping",
  "repo": null,
  "data": {
    "message": "Funziona. Gli eventi reali arrivano dopo ogni scansione mattutina."
  },
  "sent_at": "2026-07-27T05:41:12+00:00"
}
Rispondi 2xx e rispondi in fretta. Aspettiamo 6 secondi, poi contiamo un errore. Verifica la firma, inserisci l'evento in una coda, restituisci 200 e fai il lavoro dopo.

Verifica della firma

Ricalcola l'HMAC-SHA256 del corpo grezzo con il tuo segreto, prefisso con sha256= e confrontalo con X-OSAI-Signature. Il segreto è la stringa whs_ dalla risposta di creazione: whs_ più 48 caratteri esadecimali.

PHP

<?php
$raw    = file_get_contents('php://input');   // byte grezzi, prima di qualsiasi parsing
$sent   = $_SERVER['HTTP_X_OSAI_SIGNATURE'] ?? '';
$expect = 'sha256=' . hash_hmac('sha256', $raw, $SECRET);

if (!hash_equals($expect, $sent)) {           // tempo costante
    http_response_code(401);
    exit;
}

$event = json_decode($raw, true);             // analizza solo dopo il controllo
http_response_code(200);

Node, con Express

const crypto  = require('crypto');
const express = require('express');
const app = express();

// express.raw mantiene i byte. express.json() li distruggerebbe.
app.post('/osai-hook', express.raw({ type: 'application/json' }), (req, res) => {
  const sent   = req.get('X-OSAI-Signature') || '';
  const expect = 'sha256=' + crypto.createHmac('sha256', SECRET)
                                   .update(req.body).digest('hex');

  // timingSafeEqual genera un RangeError su buffer di lunghezza diversa,
  // quindi controlla prima la lunghezza, poi confronta in tempo costante.
  const a = Buffer.from(sent), b = Buffer.from(expect);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.sendStatus(401);
  }

  const event = JSON.parse(req.body.toString('utf8'));
  res.sendStatus(200);
});

Python, con Flask

import hmac, hashlib, json
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/osai-hook")
def osai_hook():
    raw    = request.get_data()               # byte, prima di qualsiasi parsing
    expect = "sha256=" + hmac.new(SECRET.encode(), raw, hashlib.sha256).hexdigest()
    sent   = request.headers.get("X-OSAI-Signature", "")

    if not hmac.compare_digest(expect, sent):  # tempo costante
        abort(401)

    event = json.loads(raw)
    return "", 200

Confronta con hash_equals, crypto.timingSafeEqual o hmac.compare_digest. Mai con == o ===. Un confronto di stringhe semplice si ferma al primo byte che differisce, quindi il tempo che impiega indica a un attaccante quanti byte iniziali hanno indovinato correttamente. Ripeti la misurazione e recuperano la firma byte per byte, poi ti inviano eventi falsificati. Le tre funzioni sopra leggono ogni byte, qualunque sia l'input.

  • Hash i byte grezzi, prima di qualsiasi parsing. Un corpo che un framework ha analizzato e ri-serializzato hash a qualcos'altro, e ogni consegna sembrerà non valida.
  • Il formato json esegue l'escape dei caratteri non ASCII come \uXXXX. La ri-serializzazione perde anche quello.
  • Un'intestazione mancante arriva come una stringa vuota. Tutti e tre gli esempi la rifiutano invece di andare in crash.
  • Il segreto viene mostrato una sola volta, alla creazione. Se lo perdi, elimina il webhook e creane un altro — ottieni un nuovo id e un nuovo segreto.
  • Mantieni un segreto per webhook. Due webhook non condividono mai uno.
Slack e Discord ignorano X-OSAI-Signature. Lo inviamo comunque, e copre ancora ciò che ricevono: la firma è calcolata sui byte effettivamente postati, qualunque sia il formato.

json, slack, discord

il formato è scelto alla creazione e predefinito su json. Non c'è un endpoint di aggiornamento: per cambiarlo, elimina il webhook e creane un altro. GET riporta il formato di ogni webhook; la risposta di creazione non lo riecheggia. Un valore al di fuori dei tre risponde 400 bad_format.

formatoCosa postiamoURL da incollare
jsonil payload sopra, invariatoil tuo endpoint
slacktesto, più un blocco di sezione mrkdwnun URL di webhook in entrata di Slack
discordun embed: titolo, url, descrizione, colore, piè di paginaun URL di webhook di canale Discord

slack

Un evento di rilascio, postato su Slack

{
  "text": "🚀 acme/inference-server rilasciato v0.6.2 — Acme Inference Server",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "🚀 *<https://github.com/acme/inference-server/releases|acme/inference-server rilasciato v0.6.2>*\nAcme Inference Server"
      }
    }
  ]
}

Ottieni l'URL da Slack: aggiungi un'app al workspace, attiva Incoming Webhooks, aggiungi uno per il canale che desideri, copia l'URL https://hooks.slack.com/services/… e incollalo nel campo url. Il testo è sempre compilato — è ciò che Slack mostra nella notifica e nei client che non rendono i blocchi.

discord

Un evento di licenza, postato su Discord

{
  "embeds": [
    {
      "title": "🔑 acme/inference-server ha cambiato licenza",
      "url": "https://github.com/acme/inference-server",
      "description": "Apache-2.0 → BSL-1.1",
      "color": 14427686,
      "footer": { "text": "olud.ai" }
    }
  ]
}

Ottieni l'URL da Discord: impostazioni del canale, Integrazioni, Webhook, Nuovo Webhook, Copia URL Webhook — https://discord.com/api/webhooks/… — e incollalo nel campo url. Il colore è un intero decimale: 14427686 (#DC2626) per la licenza, 6514417 (#6366F1) per il rilascio, new_project e ping.

Entrambi gli host superano il controllo dell'URL. Quando un evento di licenza non porta a nessuna pagina, il link torna a https://github.com/owner/name; health e new_project rimandano alla pagina del progetto su olud.ai; il rilascio rimanda alla pagina dei rilasci del repository.

Difetto noto, health su slack e discord solo. Il costruttore di messaggi legge da e a come numeri, ma health porta etichette. Il titolo appare come "acme/inference-server health 0 → 0", il corpo legge sempre "La manutenzione sta migliorando.", e il colore è sempre verde — incluso quando il punteggio scende. Il formato json non è influenzato: inoltra le due etichette così come sono. Usa json se hai bisogno delle etichette health.

Consegna, errore, disabilitazione

Le consegne si basano sull'allerta pass, send-alerts.php — la stessa rilevazione che produce le email dei membri. La spedizione avviene subito dopo la rilevazione, nello stesso processo. Non c'è un programma separato e nessuna coda. L'API descrive la cadenza come "giornaliera, dopo la scansione mattutina".

  • Un POST per evento, per webhook corrispondente. Un webhook riceve un evento quando il nome dell'evento è nella sua lista di eventi, e quando il repository è nella sua lista di repos o repos è ["*"]
  • Un successo è HTTP 200 a 299, entro il timeout di 6 secondi. Un 4xx, un 5xx, un timeout, un errore DNS o TLS contano tutti come fallimenti.
  • Un successo riporta fails a 0 e aggiunge 1 a delivered.
  • Un fallimento aggiunge 1 a fails. Non c'è ripetizione. L'evento non viene inviato di nuovo — la prossima consegna è il prossimo cambiamento che rileviamo.
  • Dopo 10 fallimenti consecutivi il webhook viene disabilitato, timbrato con l'ora UTC di quel momento, e gli eventi rimanenti di quel ciclo vengono saltati per esso.
  • Un webhook disabilitato rimane nella tua lista, contrassegnato come disabilitato. Non c'è chiamata per riabilitarlo: eliminalo e creane un altro, con un nuovo id e un nuovo segreto.

Lettura dello stato

curl -sS https://olud.ai/api/webhooks.php -H "X-Api-Key: $OSAI_KEY"

La risposta, meta inclusa

{
  "ok": true,
  "data": [
    {
      "id": "whk_9b41c7e2f0a5d3861c4e",
      "url": "https://your-app.example/osai-hook",
      "events": ["release", "health"],
      "repos": ["*"],
      "format": "json",
      "created": "2026-07-20T09:14:02+00:00",
      "delivered": 37,
      "fails": 0,
      "disabled": null
    }
  ],
  "meta": {
    "plan": "dev",
    "used": 1,
    "limit": 3,
    "events": ["health", "release", "license", "new_project"],
    "formats": ["json", "slack", "discord"],
    "delivery": "daily, after the morning scan",
    "signature": "X-OSAI-Signature: sha256=HMAC_SHA256(body, secret)"
  }
}

delivered è il conteggio totale dei POST riusciti. fails è la serie attuale consecutiva, quindi torna a 0 al prossimo successo. disabled è null, o il timestamp in cui ci siamo fermati. I segreti non vengono mai restituiti da GET.

Quattro modi in cui le consegne si fermano

  • Il tuo endpoint continua a fallire. Dieci fallimenti di fila e il webhook viene disabilitato. Risolvi l'endpoint, elimina il webhook, creane uno nuovo, pingalo.
  • Il tuo piano torna a gratuito — una cancellazione. Il webhook viene mantenuto e saltato ad ogni spedizione, silenziosamente. Cambiare piano di nuovo lo riattiva, stesso id, stesso segreto.
  • Ruoti la tua chiave API nel tuo account. La vecchia chiave lascia il keystore mentre il webhook continua a puntare ad essa: esce dalla tua lista, non può più essere pingato o eliminato, e ogni spedizione lo salta come una chiave gratuita. Elimina i tuoi webhooks prima di ruotare la chiave, poi ricreali con la nuova.
  • Lo elimini. Le consegne si fermano immediatamente.

Test senza aspettare

curl -sS -X POST https://olud.ai/api/webhooks.php \
  -H "X-Api-Key: $OSAI_KEY" -H "Content-Type: application/json" \
  -d '{"ping":"whk_9b41c7e2f0a5d3861c4e"}'

Entrambi i risultati

HTTP/1.1 200
{"ok":true,"data":{"ping":"delivered","http":200}}

HTTP/1.1 502
{"ok":false,"error":{"code":"ping_failed",
  "message":"Il tuo endpoint ha risposto HTTP 500 — ci si aspetta un 2xx."}}

Il ping viene inviato nel formato del webhook, firmato allo stesso modo, con evento ping e repo null. Non muove né delivered né fails, quindi un ping fallito non ti spinge mai verso la soglia di disabilitazione. Funziona anche su un piano gratuito quando il webhook esiste già, mentre le consegne programmate non lo fanno.

HTTP 0 in un messaggio ping_failed significa che non abbiamo ricevuto alcuna risposta: l'host non si è risolto, TLS non è completato, o i 6 secondi sono scaduti.

Codici di errore

Ogni fallimento torna nella stessa forma, con uno stato HTTP corrispondente.

{
  "ok": false,
  "error": {
    "code": "bad_url",
    "message": "L'URL deve essere https, raggiungibile pubblicamente, porta standard (niente localhost o intervalli privati)."
  }
}
HTTPcodiceQuando
400bad_jsonIl corpo non è un oggetto JSON.
400bad_urlL'URL ha fallito il controllo: non https, una porta diversa da 443, localhost, .local, .internal, o un indirizzo in un intervallo privato o riservato.
400bad_eventsDopo il filtraggio, gli eventi non contenevano nessuno di health, release, license, new_project.
400bad_reposNessuna voce era "*" o un proprietario/nome valido.
400too_many_reposPiù di 100 repository su un webhook.
400bad_formatil formato non era json, slack o discord.
401missing_keyNessun header X-Api-Key e nessun parametro ?key=.
403chiave_non_validaLa chiave non è nel nostro archivio chiavi. Una chiave ruotata o revocata finisce qui.
403funzione_a_pagamentoIl tuo piano consente 0 webhook.
404non_trovatoL'id in ping o in ?id= non è associato alla tua chiave.
405metodo_non_consentitoUn metodo diverso da GET, POST o DELETE.
429limite_raggiuntoHai già il numero massimo di webhook consentito dal tuo piano.
500scrittura_archivio_fallitaNon siamo riusciti a scrivere la modifica su disco. Riprova.
502ping_fallitoIl tuo endpoint ha risposto al ping di test con qualcosa di diverso da un 2xx.

Due punti pratici. La gestione dei webhook non consuma la tua quota giornaliera di richieste API — questo endpoint non tocca mai il contatore e non invia header X-RateLimit. E DELETE è assente dall'elenco dei metodi consentiti CORS, quindi una chiamata cross-origin da un browser fallisce al preflight; elimina lato server, o dalla pagina dell'account, che è same-origin.

Automazioni

n8n: leggere e ricevere

Due nodi coprono entrambe le direzioni. Un nodo HTTP Request legge i nostri dati. Un nodo Webhook riceve i nostri eventi. Nulla da installare dalla lista della community.

Leggi il catalogo

Ogni endpoint risponde a GET su https://olud.ai/api/v1, con la tua chiave nell'header X-Api-Key. /meta è l'unico endpoint che risponde senza una chiave e senza toccare la tua quota — usalo come primo nodo mentre testi, perché prova l'URL e il percorso di rete prima di spendere una chiamata.

Ricevi gli eventi

Aggiungi un nodo Webhook, metodo POST, e copia il suo URL di produzione. Registra quell'URL nel tuo account (sezione Webhook), o POSTalo su https://olud.ai/api/webhooks.php con la tua chiave. Quattro eventi tra cui scegliere: release, health, license, new_project. Le consegne vengono effettuate una volta al giorno, nella stessa passata che invia gli avvisi via email — non appena accade qualcosa.

Un corpo di consegna, con formato json (il predefinito):

Cosa si trova in data dipende dall'evento:

  • release — tag, nome, url (la pagina delle release del repository)
  • health — from, to, stars, page
  • license — from, to
  • new_project — stars, page
  • ping — message (solo consegne di test)

In un evento di salute, from e to sono etichette, non numeri: Thriving (punteggio 85 e oltre), Healthy (70+), Maintained (50+), Slowing down (30+), At risk (sotto 30). Confronta il testo nel tuo nodo IF, non interi.

Ogni consegna porta tre header: X-OSAI-Event, X-OSAI-Delivery (un id unico per consegna, usalo per eliminare i duplicati) e X-OSAI-Signature, della forma sha256=<HMAC-SHA256 del corpo con il tuo segreto webhook>. L'HMAC copre i byte esatti che abbiamo inviato, quindi se vuoi verificarlo, attiva l'opzione raw-body del nodo Webhook. Un corpo che è stato analizzato e ri-serializzato non corrisponde mai.

Incolla questo sulla tela. I due nodi sono lasciati disconnessi di proposito — ognuno è il proprio punto di partenza:

Poi metti la tua chiave nel campo header del nodo HTTP e attiva il workflow — l'URL di produzione di un nodo Webhook ascolta solo mentre il workflow è attivo.

Quando non arriva nulla

  • Registrare l'URL restituisce 400 bad_url: l'endpoint deve essere https, sulla porta 443, su un host risolvibile pubblicamente. Un n8n auto-ospitato su http, su localhost, su un nome *.local o su un intervallo IP privato viene rifiutato.
  • Registrare restituisce 403 paid_feature: i webhook iniziano dal piano Dev — 3 endpoint su Dev, 10 su Pro, 50 su Org. Una chiave Free non può crearne uno.
  • Registrare restituisce 429 limit_reached: hai già il numero massimo di webhook consentito dal tuo piano. Elimina prima uno.
  • Non aspettare domani per scoprirlo: POST {"ping":"whk_…"} a /api/webhooks.php e l'evento di test parte immediatamente, nella stessa forma di uno reale. Se il tuo endpoint non risponde 2xx ricevi 502 ping_failed con il codice che ha restituito.
  • Dieci risposte consecutive non-2xx disabilitano il webhook, silenziosamente. Un successo ripristina il contatore. Un webhook disabilitato torna solo ricreandolo. Il timeout di consegna è di 6 secondi, quindi un nodo che risponde lentamente conta come un fallimento.
  • Il webhook è stato creato ma nulla viene consegnato e non ci sono errori: controlla il piano sulla chiave che lo possiede. Se è tornato a Free, le consegne vengono saltate mentre l'endpoint rimane registrato.
  • Il segreto viene mostrato una sola volta, alla creazione. Non c'è modo di leggerlo di nuovo — elimina e ricrea.

Zapier e Make

Stesse due direzioni, stessa chiave, nessuna app da trovare nelle loro directory.

Ricevi: cattura il hook

In Zapier: Webhooks by Zapier, attiva Catch Hook. In Make: il modulo Webhooks, Custom webhook. Entrambi ti forniscono un URL https sul loro dominio, che supera il nostro controllo. Incollalo nel tuo account come endpoint webhook, scegli i tuoi eventi, poi inviati un ping e conferma che lo Zap o lo scenario lo riceve prima di costruire i passaggi dietro di esso.

Se intendi verificare X-OSAI-Signature, hai bisogno del corpo raw e delle intestazioni. In Zapier ciò significa Catch Raw Hook piuttosto che Catch Hook. In Make, attiva l'impostazione del webhook che mantiene le intestazioni della richiesta. La nostra firma è un HMAC sui byte esatti del corpo, quindi un passaggio che analizza il JSON prima di vederlo rende impossibile il confronto.

Leggi: un passaggio HTTP

Azione GET dei Webhooks di Zapier, o modulo HTTP di Make. Un passaggio, un'intestazione:

Un successo è {"ok":true,"data":[…],"meta":{…}}. Un errore è {"ok":false,"error":{"code":"…","message":"…"}} con uno stato HTTP corrispondente. Testa ok prima di mappare i campi: un corpo di errore non ha dati, e una mappatura che legge data[0] su un errore produce silenziosamente valori vuoti a valle.

  • 401 missing_key — l'intestazione non è arrivata. Controlla che il passaggio la invii ad ogni chiamata, non solo alla prima.
  • 403 invalid_key — chiave sconosciuta o revocata.
  • 429 quota_exceeded — quota giornaliera raggiunta, si resetta a 00:00 UTC. Le risposte di successo portano X-RateLimit-Limit e X-RateLimit-Remaining, così puoi vederlo arrivare.
  • 503 graph_unavailable — il grafo è in fase di ricostruzione. Riprova tra un minuto; questo è l'unico errore che vale un tentativo automatico.
  • 403 pro_required — /history/{slug} è solo per Pro e Org.
  • 404 not_found — nessun progetto o prodotto del genere. Il messaggio porta un suggerimento /search che puoi seguire.
Non programmare questo ogni minuto. Il grafo viene ricostruito una volta ogni mattina, quindi ogni ora è già più spesso di quanto i dati cambino. Le risposte portano un ETag derivato dalla data di costruzione e una richiesta ripetuta ottiene 304 Not Modified — ma la chiave viene conteggiata prima di quel confronto, quindi un 304 costa comunque una chiamata contro la tua quota giornaliera.

GitHub Action: monitoraggio delle dipendenze

L'azione legge i manifesti delle dipendenze del repository controllato, ci chiede la licenza e il record di manutenzione di ogni dipendenza, e pubblica un commento sulla richiesta di pull elencando ciò che necessita di una decisione. Riscrive lo stesso commento ad ogni esecuzione — lo trova di nuovo attraverso un marcatore nascosto — quindi una lunga richiesta di pull non si riempie di duplicati.

L'intero flusso di lavoro, con ogni input al suo valore predefinito. Solo api-key è richiesto:

actions/checkout deve venire per primo: l'azione legge i file dalla directory di lavoro, e solo alla radice a meno che tu non imposti i percorsi.

InputPredefinitoCosa fa
api-keyrichiestoInviato come X-Api-Key. Una ricerca per ogni dipendenza distinta. Una chiave gratuita funziona.
github-token${{ github.token }}Pubblica il commento. Necessita di pull-requests: scrivi sul lavoro.
health-floor45Segna una dipendenza che ottiene un punteggio inferiore a questo su 100. 0 disattiva il controllo della salute e mantiene solo le licenze. Leggi il limite noto qui sotto.
licencesAGPL-3.0,BSL-1.1,SSPL-1.0,Elastic-2.0,BUSL-1.1,NOASSERTIONSeparati da virgole, abbinati senza distinzione di maiuscole e minuscole rispetto alla licenza che possediamo. Impostarlo sostituisce l'elenco, non lo aggiunge.
fail-on-findingfalseFallisci il controllo invece di commentare solo.
pathsvuotoManifesti separati da virgole da leggere. Vuoto significa: cerca i quattro nomi noti alla radice.

NOASSERTION è nell'elenco predefinito per scelta: è ciò che possediamo quando il repository non porta un file di licenza che una macchina può riconoscere, il che è una decisione da prendere piuttosto che un dettaglio. L'azione espone un output, findings — il numero di dipendenze contrassegnate, scritto anche quando è 0.

Cosa legge

  • package.json — le chiavi delle dipendenze e devDependencies. peerDependencies e optionalDependencies non vengono letti.
  • requirements.txt — un nome per riga, commenti rimossi, righe che iniziano con - eliminate. Quindi -r other-requirements.txt non viene seguito e -e . viene ignorato.
  • pyproject.toml — solo chiavi il cui valore inizia con una virgoletta o una parentesi graffa, che è lo stile Poetry: fastapi = "^0.110". Un blocco PEP 621, dependencies = ["fastapi>=0.110"], non produce nulla.
  • go.mod — righe indentate della forma nome vX.

i percorsi possono puntare ovunque nell'albero, ad esempio apps/api/requirements.txt, ma il nome base del file deve essere uno di quei quattro. Un file chiamato requirements-dev.txt non ha un parser: viene saltato senza un messaggio.

Non fallisce il tuo controllo per impostazione predefinita. fail-on-finding è falso, quindi una scoperta è un commento, non una build rossa — un cambiamento di licenza è una decisione, e una pipeline che diventa rossa per qualcosa che nessuno può risolvere in cinque minuti insegna al team a cliccare attraverso di essa. Due cose fanno fallire il lavoro: una chiave api mancante, registrata come ::error::api-key is required, e fail-on-finding: true con almeno una scoperta.

Come fallisce

  • Nessun manifesto alla radice, o nessun passo di checkout: "Nessun manifesto di dipendenza trovato — nulla da controllare." le scoperte sono 0 e il lavoro è verde. Una corsa verde non significa un albero pulito — leggi quella riga.
  • L'evento non ha pull request, ad esempio su push: "Nessuna pull request nel contesto — commento saltato." Le scoperte sono ancora nel log.
  • pull-requests: scrivi mancante: "Impossibile pubblicare il commento (HTTP 403)." Il lavoro rimane verde e il commento non appare mai. Guarda il log, non la pull request.
  • Quota API giornaliera raggiunta a metà esecuzione: ::warning::Quota API giornaliera raggiunta — esecuzione parziale. Smette di cercare cose e commenta su ciò che è riuscito a risolvere. Una chiamata per ogni dipendenza distinta, quindi 300 dipendenze spendono 300 delle 500 chiamate giornaliere di una chiave Free.
  • Un manifesto che non verrà analizzato: "⚠ <file> illeggibile (…) — saltato". Gli altri manifesti continuano a funzionare.
  • Il passo composito esegue node dal PATH e utilizza fetch nativo. I runner ospitati da GitHub già portano Node 20. Un runner auto-ospitato ha bisogno di actions/setup-node con Node 20 o successivo.
  • licenze: '' con health-floor: '0' produce zero scoperte per sempre. Quella combinazione disattiva entrambi i controlli.

Cosa manca all'Action

Un nome di pacchetto non è un nome di repository. Ogni nome passa attraverso /api/v1/search?q=<name>&limit=5 e l'azione mantiene un risultato solo quando il nome del progetto è uguale al nome del pacchetto, ignorando il maiuscolo. Qualsiasi altra cosa viene scartata in silenzio — nessuna riga di commento, nessun avviso. Indovinare il risultato più vicino solleverebbe allarmi sul progetto sbagliato, il che è peggio che rimanere in silenzio, ma significa che il controllo copre meno del tuo albero delle dipendenze.

  • I pacchetti npm con ambito perdono il loro ambito prima della ricerca: @types/node viene cercato come node, il che può corrispondere a un repository non correlato con quel nome. Questo è l'unico caso in cui il progetto sbagliato può finire nel commento.
  • I moduli Go mantengono il loro percorso: github.com/gin-gonic/gin diventa gin-gonic/gin, che non è mai uguale a un nome di repository (gin). Le dipendenze di go.mod non si risolvono.
  • Un pacchetto il cui repository ha un nome diverso — il caso comune in Python — non si risolve mai.
  • Solo i primi cinque risultati vengono esaminati e solo la prima corrispondenza esatta viene utilizzata. Quando due repository condividono un nome, quello con più stelle vince.

La riga da leggere nel log è: Risolto N di M dipendenze · K contrassegnate. Se N è molto al di sotto di M, il controllo ha esaminato solo una frazione del tuo albero. Niente nel commento della pull request lo dice.

Limite noto su health-floor. L'azione legge il punteggio di manutenzione come un campo oggetto, mentre /api/v1/search restituisce la salute come un numero semplice. Con la risposta API di oggi, il controllo della salute non può attivarsi, qualunque sia il pavimento impostato: l'elenco delle licenze è ciò che produce scoperte. Il punteggio completo con i suoi quattro componenti è fornito da /api/v1/project/{id} se ne hai bisogno nel frattempo.

Specifica OpenAPI

Un file descrive l'API di lettura: https://olud.ai/openapi.json. OpenAPI 3.0.3, un server (https://olud.ai/api/v1), nove operazioni GET, uno schema di sicurezza — una chiave API nell'intestazione X-Api-Key. Non scrivi un'integrazione; incolli un indirizzo.

  • /meta — data di costruzione e conteggio dei progetti. Dichiarato senza sicurezza: è il controllo della salute.
  • /search — q richiesto, limite da 1 a 50, predefinito 15.
  • /projects — lang, license, vertical, health_min da 0 a 100, ordina in stars|health|momentum|recent (predefinito stars), limite da 1 a 100 (predefinito 25), offset da 0 a 100000 (predefinito 0).
  • /project/{id} — il record completo unito, inclusa la salute con i suoi componenti.
  • /emerging — limite da 1 a 100, predefinito 25.
  • /alternatives/{product} — alternative open-source a un prodotto commerciale.
  • /models — provider, tier, limite da 1 a 200 (predefinito 50), offset.
  • /hf — più scaricati e in tendenza su Hugging Face.
  • /history/{slug} — 90 giorni di stelle, salute e momentum. Pro e Org.

Importalo

  • Custom GPT — Configura, poi Azioni, poi Importa da URL. Autenticazione: Chiave API, intestazione personalizzata, nome X-Api-Key.
  • Dify, Flowise, Open WebUI — aggiungi uno strumento da uno schema OpenAPI, incolla l'URL, scegli le operazioni che vuoi esporre, aggiungi la stessa intestazione.
  • Postman, Insomnia — Importa, poi Collega. Ottieni le nove richieste, documentate. Imposta X-Api-Key una volta a livello di collezione in modo che ogni richiesta la erediti.
  • Generatori di codice — qualsiasi generatore OpenAPI produce un client tipizzato, TypeScript, Python o Go, solo da questo file.

Qualunque sia lo strumento, ci sono solo due cose da impostare: l'URL del file e la chiave come intestazione chiamata X-Api-Key. Se un'importazione mostra nove operazioni ma ogni chiamata risponde 401, l'intestazione non viene inviata — quella è la prima cosa da controllare.

Le quote sono per chiave e per giorno, ripristinate a 00:00 UTC: 500 richieste su Free, 5.000 su Dev, 50.000 su Pro, 500.000 su Org. Vengono conteggiate separatamente dal server MCP, quindi un assistente che fa domande nel tuo editor non consuma mai questo budget.

La gestione dei webhook non è in questo file. Vive su https://olud.ai/api/webhooks.php con la stessa chiave: GET elenca i tuoi endpoint con i loro conteggi di consegna e fallimento, POST crea uno o invia un ping, DELETE rimuove uno. Uno strumento che importa la specifica non può creare un webhook per te.

Quattro feed RSS

Nessuna chiave, nessuna registrazione, nessun account. feed.php accetta esattamente quattro tipi: notizie, blog, rilasci, emergenti.

URLCosa portaDa dove proviene
/feed.phpFino a 30 nuovi progetti (★stelle · proprietario/nome), i nuovi modelli del giorno (Nuovo modello: nome (fornitore), con la finestra di contesto nella descrizione), nuovi Hugging Face Spaces (Nuovo Space: nome dell'autore, con il conteggio dei like), e il documento del giorno.today-data.json, ricostruito ogni ora
/feed.php?type=releasesFino a 60 versioni rilasciate dai progetti che seguiamo: titolo progetto + tag, link al rilascio, guid proprietario/nome@tag.releases-data.json, ricostruito ogni ora
/feed.php?type=emergingFino a 40 progetti emergenti — sani, in accelerazione, ancora poco conosciuti. Descrizione: ★stelle · salute N/100 · +N stelle questa settimana.il grafico, ricostruito ogni mattina
/feed.php?type=blogArticoli sotto /blog/<slug>/, /blog/alternatives/ e /reports/. Titolo e descrizione sono il titolo e la meta descrizione della pagina; la data è il tempo di modifica del file.lettura dal disco, quindi un nuovo articolo appare da solo

Tutti e quattro rispondono a RSS 2.0 come application/rss+xml, in inglese, l'elemento più recente per primo, con Cache-Control: public, max-age=1800. Ovvero 30 minuti: un lettore che interroga più spesso ottiene la copia cache, che è la stessa risposta servita più velocemente.

I guid sono stabili e non sempre il link, che è ciò che desideri quando de-duplici in un'automazione: i rilasci usano proprietario/nome@tag, i progetti emergenti usano emerging:<id>, il documento del giorno usa il suo URL più la data, tutto il resto usa il suo link.

La trappola: un tipo sconosciuto non è un errore. ?type=release al singolare, o un errore di battitura, restituisce il feed delle notizie con HTTP 200. Se due dei tuoi feed sembrano sospettosamente identici, controlla l'ortografia di type. I valori sono trimmati e in minuscolo, quindi ?type=Releases va bene.

Punta Slack, Teams o Feedly su di essi per leggere, o usa il trigger RSS in n8n, Zapier e Make quando un programma si adatta meglio a te rispetto a un webhook — questo è anche il modo per ottenere rilasci senza un piano a pagamento. Se un file sorgente non è stato ricostruito, il feed risponde comunque 200 con un canale vuoto piuttosto che un errore, quindi un'automazione che improvvisamente non riceve nulla non è necessariamente rotta.