Un'API per URL shortener è una delle integrazioni più piccole nel backlog tipico di un team di ingegneria. Tre endpoint, un header di autenticazione, un payload JSON. La pagina della documentazione promette la prima chiamata in cinque minuti. Poi arriva il traffico di produzione, la logica di retry crea link duplicati, la dashboard si riempie di varianti /foo-1, /foo-2, /foo-3 della stessa destinazione, e qualcuno apre un ticket.
Questo articolo ripercorre l'integrazione reale. Autenticazione, la prima chiamata, i quattro endpoint che coprono la maggior parte dei casi d'uso, idempotenza, gestione degli errori, limiti di frequenza e le insidie di produzione che la guida rapida di cinque minuti salta. Esempi di codice in TypeScript, Python, Go, Ruby e PHP: i primi tre tramite gli SDK ufficiali (@elido/sdk, elido-python, github.com/elido/elido-go), gli ultimi due tramite semplici client HTTP.
Prerequisiti
Accedi alla dashboard, vai su /dashboard/api-keys e crea una chiave API (inizia con elido_). I token sono legati al workspace: un token emesso nel workspace A non può creare link nel workspace B. I token per utenti macchina (per sistemi CI, strumenti interni, integrazioni machine-to-machine) vengono creati sotto /dashboard/machine-users e ruotano in modo indipendente dalle chiavi personali. Entrambi i tipi hanno un ruolo di workspace preimpostato (viewer, editor o admin) piuttosto che permessi per singolo endpoint, quindi assegna editor a un job CI se si limita a creare link. La guida alle autorizzazioni delle chiavi API spiega cosa può raggiungere ciascun ruolo, incluso il motivo per cui le modifiche ai webhook richiedono admin.
L'URL di base è https://api.elido.app/v1. I domini di redirect (f.elido.me, s.elido.me, b.elido.me) sono separati dalla superficie API. I tuoi link brevi si risolvono sul dominio di redirect; l'API serve per crearli, modificarli e leggerli.
La specifica OpenAPI è pubblicata su https://elido.app/openapi.json e rispetta OpenAPI 3.1. Gli SDK ufficiali sono generati da quella specifica e ripubblicati a ogni release dell'API; puoi anche generare un tuo client in qualsiasi linguaggio supportato da OpenAPI.
La prima chiamata
Crea un link breve a partire dall'URL di destinazione. Cinque righe in TypeScript:
import { Elido } from "@elido/sdk";
const elido = new Elido({ token: process.env.ELIDO_TOKEN! });
const link = await elido.links.create({
destinationUrl: "https://shop.example.com/spring-sale",
});
console.log(link.shortUrl); // https://s.elido.me/abc123
Python:
from elido import Elido
client = Elido(token=os.environ["ELIDO_TOKEN"])
link = client.links.create(
destination_url="https://shop.example.com/spring-sale",
)
print(link.short_url) # https://s.elido.me/abc123
Go:
import "github.com/elido/elido-go/v2/elido"
client := elido.NewClient(elido.WithToken(os.Getenv("ELIDO_TOKEN")))
link, err := client.Links.Create(ctx, &elido.LinkCreateInput{
DestinationURL: "https://shop.example.com/spring-sale",
})
if err != nil {
return fmt.Errorf("create link: %w", err)
}
fmt.Println(link.ShortURL)
Ruby (nessun SDK ufficiale, si usa net/http):
require "net/http"
require "json"
uri = URI("https://api.elido.app/v1/links")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['ELIDO_TOKEN']}"
req["Content-Type"] = "application/json"
req.body = { destination_url: "https://shop.example.com/spring-sale" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
link = JSON.parse(res.body)
puts link["short_url"]
PHP (Guzzle):
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.elido.app/v1/']);
$res = $client->post('links', [
'headers' => ['Authorization' => 'Bearer ' . getenv('ELIDO_TOKEN')],
'json' => ['destination_url' => 'https://shop.example.com/spring-sale'],
]);
$link = json_decode((string) $res->getBody(), true);
echo $link['short_url'];
Tutti e cinque producono lo stesso risultato. Il corpo della risposta contiene l'URL breve, l'ID canonico del link, l'ID del workspace e il timestamp di creazione. Lo slug, abc123 nell'esempio sopra, è generato dal server a meno che tu non passi slug nella richiesta. L'alfabeto dello slug è base62 ([0-9A-Za-z]); la lunghezza predefinita è di sei caratteri.
I quattro endpoint che userai davvero
L'API ha più di quattro endpoint, ma la maggior parte delle integrazioni resta all'interno di questo insieme.
Creare un link
POST /v1/links accetta l'URL di destinazione più campi opzionali:
slug- uno slug scelto da te (deve essere unico sul dominio).domain_id- per link su dominio personalizzato; su/v1/linksviene usato il dominio breve predefinito del tuo piano se omesso. Il percorso con ambito workspace/v1/workspaces/{workspace_id}/linkslo richiede.title- un'etichetta mostrata nella dashboard.tags- un array di stringhe libere per l'organizzazione.expires_at- timestamp RFC 3339 dopo il quale il link restituisce 410 Gone.redirect_status-301,302(il valore predefinito) oppure307.password- non ancora accettato in fase di creazione; impostalo con unPATCHsubito dopo, e il redirect mostrerà una pagina con password prima di inoltrare.utmemetadata- pianificati. Oggi inserisci i parametri UTM direttamente indestination_urle conserva le tue chiavi di join intags.
Lo slug personalizzato è il campo che morde i team in produzione. Se passi uno slug già in uso da un altro link sullo stesso dominio, l'API restituisce 409 Conflict. Il gestore di retry ingenuo che aggiunge un contatore (my-slug-1, my-slug-2) produce il problema dei link duplicati descritto in apertura. Il comportamento di retry corretto è descritto nella sezione sull'idempotenza più sotto.
Leggere un link
GET /v1/links/{id} restituisce il record completo del link, incluso short_url e tutta la configurazione. I conteggi dei click non sono nel record del link; provengono dagli endpoint di analytics qui sotto. L'ID del link è l'identificatore canonico: gli slug possono cambiare, gli ID no.
GET /v1/links?host=…&tags=…&limit=… elenca i link nel workspace con filtri. La paginazione è basata su cursore; next_cursor nella risposta è opaco e va passato come parametro di query cursor nella richiesta successiva.
Aggiornare un link
PATCH /v1/links/{id} accetta gli stessi campi della creazione. Gli aggiornamenti più comuni: cambiare l'URL di destinazione (utile per la rotazione delle campagne senza ristampare i codici QR), cambiare i tag, estendere expires_at. Lo slug si cambia tramite lo stesso PATCH, inviando un nuovo slug. Il vecchio slug smette immediatamente di risolversi; un endpoint di rinomina dedicato che mantenga un 301 dal vecchio slug per un periodo di conservazione è pianificato, non ancora realizzato.
Eliminare un link
DELETE /v1/links/{id} esegue un soft delete e restituisce 204 No Content. Il link smette di eseguire il redirect e scompare dalle richieste di elenco e lettura. Una vista cestino con un endpoint di ripristino e una finestra di 90 giorni prima dell'eliminazione definitiva è pianificata; oggi non esiste una chiamata API per riportare indietro un link eliminato.
Chiavi di idempotenza
Ogni richiesta che modifica dati, POST, PATCH, DELETE, accetta un header Idempotency-Key. Il valore dell'header è una stringa opaca fino a 255 caratteri; il server memorizza il corpo della risposta e il codice di stato per 24 ore, indicizzati su (workspace_id, idempotency_key), e restituisce la risposta memorizzata se la stessa chiave viene presentata di nuovo.
Gli SDK ufficiali generano automaticamente le chiavi di idempotenza quando non vengono fornite. Puoi sovrascriverle:
const link = await elido.links.create(
{ destinationUrl: "https://shop.example.com/spring-sale" },
{ idempotencyKey: "order-12345-link" },
);
Il caso d'uso è un ciclo di retry. Se il tuo job crea un link come parte dell'elaborazione di un ordine a monte, genera la chiave di idempotenza a partire dall'ID dell'ordine. Un retry dello stesso job vede la stessa chiave, colpisce la cache di idempotenza e restituisce il link creato originariamente invece di produrne un secondo.
L'insidia principale: la cache di idempotenza vive per 24 ore, non per sempre. Un retry al terzo giorno di un job bloccato creerà un nuovo link. Se l'integrazione gira su batch multi-giorno, memorizza l'ID del link restituito dalla prima creazione riuscita e cercalo prima di riemettere la richiesta.
Una seconda insidia: l'idempotenza è per workspace. La stessa chiave in due workspace crea due link. Questa è la semantica corretta per un'API multi-workspace, ma può sorprendere i team che presumono che la chiave sia globalmente unica.
Gestione degli errori
L'API restituisce codici di stato HTTP standard più un corpo di errore strutturato:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Workspace rate limit of 100 req/s exceeded. Retry after 1 second.",
"request_id": "req_01HXYZAB123",
"retry_after": 1
}
}
I codici che vedrai più spesso:
400 invalid_request- errore di validazione del payload. Il campomessageelenca i campi specifici. Non riprovare; correggi il payload.401 unauthorized- token mancante o non valido. Non riprovare senza ruotare il token.403 forbidden- il ruolo del token non consente l'azione (una chiaveviewernon può creare link). Verifica il ruolo della chiave su/dashboard/api-keys.404 not_found- la risorsa non esiste o il token non ha accesso ad essa (restituiamo 404 invece di 403 per evitare di rivelare l'esistenza della risorsa a chiamanti non autorizzati).409 conflict- slug già in uso, oppure modifica simultanea rilevata (PATCH su una versione obsoleta). Ricarica e riprova.429 rate_limit_exceeded- rallenta in base al valore diretry_after.500 internal_server_error- guasto lato server. È sicuro riprovare con la stessa chiave di idempotenza.502 bad_gateway,503 service_unavailable,504 gateway_timeout- problemi infrastrutturali transitori. Rallenta e riprova.
Gli SDK ufficiali implementano il backoff esponenziale con jitter per 429, 500, 502, 503 e 504. Non riprovano per 400, 401, 403, 404 o 409: sono errori di programmazione o conflitti di logica di business, non guasti transitori. I client HTTP personalizzati dovrebbero seguire lo stesso schema; riprovare un 400 con lo stesso payload non produrrà un risultato diverso.
Il request_id nel corpo dell'errore è il campo da includere nei ticket di supporto. Possiamo tracciare qualsiasi richiesta a partire da quell'ID attraverso il log di audit, il log dell'applicazione e le metriche di piattaforma, e non possiamo tracciare una richiesta senza di esso.
Limiti di frequenza
I limiti di frequenza pubblicati sono 100 richieste al secondo per workspace su Pro, 500 su Business e un limite negoziato su Enterprise. Il livello Free è di 10 req/s.
Lo stato del limite di frequenza è esposto in tre header di risposta su ogni risposta dell'API:
X-RateLimit-Limit- il limite attuale al secondo.X-RateLimit-Remaining- richieste rimanenti nel secondo corrente.X-RateLimit-Reset- timestamp Unix in cui il bucket si azzera.
Il limite di 100/s è un'implementazione a token bucket con una capacità di burst di 200, il che significa che puoi emettere 200 richieste in una volta se il bucket è pieno, per poi assestarti sul tasso sostenuto di 100/s. La maggior parte dei job di creazione di link brevi rientra comodamente nel burst; le integrazioni fortemente orientate all'analytics che scorrono la cronologia degli eventi di click beneficiano del margine offerto dal livello Pro.
Per le operazioni in blocco, l'endpoint POST /v1/links/bulk accetta fino a 100 link per richiesta e conta come una singola unità di rate limit. Questo è l'endpoint giusto per qualsiasi job che crea più di cento link alla volta. Per un approfondimento su come gestire il ritmo rispetto al token bucket, su quali codici di stato riprovare e su come le chiavi di idempotenza evitano che i retry duplichino i link, vedi limiti di frequenza, retry e idempotenza in produzione.
Cosa fanno gli SDK che l'HTTP semplice non fa
Gli SDK ufficiali offrono quattro cose che si ripagano rapidamente:
- Retry automatico con backoff per i codici di stato che si possono riprovare.
- Generazione della chiave di idempotenza quando non viene fornita esplicitamente.
- Errori tipizzati, così puoi scrivere
catch (err) { if (err instanceof ElidoRateLimitError) { … } }invece di analizzare JSON nei blocchi catch. - Iteratori di paginazione, così gli endpoint di elenco espongono iteratori asincroni o generatori invece di richiedere la gestione manuale del cursore.
L'SDK Go espone inoltre il client HTTP sottostante per la strumentazione, utile se vuoi collegarlo alla tua configurazione di tracing esistente. La pagina delle funzionalità API + SDK del repository copre l'intera superficie; il riferimento API è pubblicato su /docs/api-reference.
Accesso alle analytics
Gli endpoint di analytics sono di sola lettura e si trovano sotto /v1/workspaces/{id}/analytics/; la guida all'API delle analytics dei link elenca ogni report, i relativi parametri e la struttura della risposta. Le query più comuni:
GET .../clicks/recent?from=…&to=…- singoli click, dal più recente, con paginazione tramitenext_cursor. Utile per pipeline di export.GET .../timeseries?from=…&to=…&interval=day- conteggi di click raggruppati per intervallo di tempo;intervalpuò esserehouroppureday, etzimposta il fuso orario dei raggruppamenti.GET .../breakdown/country?from=…&to=…- ripartizione geografica.GET .../breakdown/referrer?from=…&to=…- ripartizione per referrer.
Gli altri report sono summary, links/top, le restanti ripartizioni (host, device, browser, destination) e le liste dei primi risultati (top-countries, top-regions, top-cities, top-referrers, top-destinations). from e to sono date nel formato YYYY-MM-DD e to è esclusivo; aggiungi link_id per restringere qualsiasi report a un solo link e limit per dimensionare le ripartizioni e le liste dei primi risultati.
Il flusso degli eventi di click grezzi è il più grande. Un workspace con 10 milioni di click al mese produce circa 600 MB di dati JSON grezzi al mese. Per export a questa scala, la guida all'export delle analytics copre il meccanismo di export in blocco che bypassa l'involucro JSON e trasmette direttamente dal data warehouse di analytics.
Webhook per gli eventi sui link
I webhook sono l'inverso del polling: invece di chiedere tu all'API cosa è cambiato, è l'API a consegnare eventi su link e domini al tuo endpoint. Configurali su /dashboard/webhooks:
await elido.webhooks.create({
url: "https://your-app.example/webhooks/elido",
events: ["link.created", "link.updated", "link.expired"],
secret: process.env.WEBHOOK_SIGNING_SECRET,
});
Un evento click.created per singolo click è nella roadmap ma non ancora disponibile, quindi oggi i dati sui click arrivano dagli endpoint di analytics. Ogni consegna include un header X-Elido-Signature (inviato anche come X-Webhook-Signature) con valore v1=<hex>: un HMAC-SHA256, con chiave il secret del tuo endpoint, calcolato sul valore di X-Webhook-Timestamp, un punto e il corpo grezzo della richiesta. Verifica la firma prima di elaborare i dati: senza di essa, chiunque può inviare richieste al tuo endpoint webhook impersonando Elido.
La semantica di consegna è at-least-once: una consegna fallita viene riprovata con un backoff di minuti, con tre tentativi totali per impostazione predefinita. Per la struttura dettagliata e il comportamento dei retry, l'articolo webhook contro polling confronta i due pattern di integrazione.
Un esempio pratico: automazione delle campagne
L'integrazione che motiva la maggior parte delle adozioni dell'API è questa. La tua automazione di marketing crea una campagna in Customer.io o HubSpot. Un hook scatta quando la campagna viene pubblicata. Il tuo handler crea il link breve, lo collega al record della campagna e lo rimanda allo strumento di gestione campagne per sostituirlo nel template dell'email.
In TypeScript:
import { Elido } from "@elido/sdk";
const elido = new Elido({ token: process.env.ELIDO_TOKEN! });
export async function onCampaignPublished(campaign: Campaign) {
const link = await elido.links.create(
{
destinationUrl: campaign.destinationUrl,
tags: [
"campaign",
`campaign:${campaign.id}`,
`batch:${campaign.batchId}`,
campaign.channel,
],
},
{
idempotencyKey: `campaign-${campaign.id}-link`,
},
);
await campaignStore.update(campaign.id, { shortUrl: link.shortUrl });
return link;
}
La chiave di idempotenza è derivata dall'ID della campagna. Se l'hook di pubblicazione della campagna scatta due volte (succede: le consegne dei webhook sono at-least-once), la seconda chiamata restituisce lo stesso link senza crearne uno duplicato. I tag campaign: e batch: contengono le tue chiavi di join, così puoi correlare gli eventi di click di Elido alla campagna; un campo metadata dedicato è pianificato. I parametri UTM appartengono direttamente a campaign.destinationUrl finché il campo utm non sarà disponibile.
Per l'attribuzione delle campagne end-to-end con template UTM e inoltro delle conversioni, il cornerstone sul tracciamento UTM ripercorre l'intera pipeline.
Cosa manca ancora nell'API
Due cose spesso richieste, attualmente non disponibili:
- Un singolo GET di analytics per link che restituisca tutte le ripartizioni in una sola chiamata. Il modello attuale richiede chiamate separate per click, paese, referrer, dispositivo e serie temporale. L'aggregazione è nella roadmap; per ora, esegui le richieste in parallelo dal tuo codice.
- Replay dei webhook dall'API. La dashboard espone la cronologia di consegna dei webhook e supporta il replay; l'API non ancora. Anche questo è nella roadmap.
Se una funzionalità è nella specifica OpenAPI, è supportata. Se è in questo articolo ma non nella specifica, trattala come pianificata piuttosto che garantita.
Letture correlate
- Smart link spiegati - il cornerstone del cluster funzionalità; copre come il motore di redirect risolve un link all'edge.
- Webhook contro polling per il tracciamento dei click - quando usare quale pattern di integrazione.
- Tracciamento delle conversioni lato server tramite link brevi - estendere l'API nel flusso di inoltro delle conversioni.
- Import in blocco di campagne da Google Sheets - un esempio pratico dell'endpoint bulk.
- API per URL shortener: limiti di frequenza, retry, idempotenza - rendere robusta l'integrazione per il traffico di produzione.
- Autorizzazioni delle chiavi API per gli strumenti di gestione dei link - chiavi legate al workspace, limiti dei ruoli e rotazione.
- API gratuita per URL shortener: esempi di codice che funzionano - la chiamata di creazione in curl, JavaScript, Python e Go, e cosa limitano i livelli gratuiti.
- API delle analytics dei link: recuperare le statistiche dei clic con una chiave API - tutti i report, i relativi parametri di query e uno script giornaliero per Slack.
- Guida operativa: la guida al server MCP per collegare la superficie API di Elido a Claude, Cursor e altri client compatibili con MCP.
- Superficie di prodotto:
/features/api-sdkse/solutions/developers.
Prova Elido
Incolla un URL, ottieni un link breve
Senza registrazione. Il link vive 30 giorni. Iscriviti per conservarlo.
Gratis, nessuna registrazione richiesta · 2 al giorno