Eine URL-Shortener-API gehört zu den kleineren Integrationen im Backlog eines typischen Engineering-Teams. Drei Endpunkte, ein Auth-Header, ein JSON-Payload. Die Dokumentationsseite verspricht den ersten Aufruf in fünf Minuten. Doch sobald der Produktivverkehr einsetzt, erzeugt die Retry-Logik doppelte Links, das Dashboard füllt sich mit den Varianten /foo-1, /foo-2, /foo-3 desselben Ziels, und jemand erstellt ein Ticket.
Dieser Beitrag führt durch die tatsächliche Integration. Auth, der erste Aufruf, die vier Endpunkte, die die meisten Anwendungsfälle abdecken, Idempotenz, Fehlerbehandlung, Rate-Limits und die Tücken der Produktion, die der Fünf-Minuten-Quickstart überspringt. Codebeispiele in TypeScript, Python, Go, Ruby und PHP – die ersten drei über die offiziellen SDKs (@elido/sdk, elido-python, github.com/elido/elido-go), die letzten beiden über einfache HTTP-Clients.
Voraussetzungen#
Melden Sie sich im Dashboard an, navigieren Sie zu /settings/api und erstellen Sie ein persönliches Access-Token. Tokens sind auf Workspaces beschränkt – ein in Workspace A ausgestelltes Token kann keine Links in Workspace B erstellen. Service-Account-Tokens (für CI-Systeme, interne Tools, Machine-to-Machine-Integration) werden auf demselben Bildschirm ab Pro aufwärts erstellt; sie haben explizite Scopes (links:write, analytics:read, domains:write) und rotieren unabhängig von persönlichen Tokens.
Die Basis-URL lautet https://api.elido.app/v1. Die Redirect-Domains (f.elido.me, s.elido.me, b.elido.me) sind von der API-Oberfläche getrennt. Ihre Kurzlinks werden über die Redirect-Domain aufgelöst; die API dient zum Erstellen, Ändern und Auslesen dieser Links.
Die OpenAPI-Spezifikation ist unter https://api.elido.app/v1/openapi.json veröffentlicht und entspricht OpenAPI 3.1. Die offiziellen SDKs werden aus dieser Spezifikation generiert und bei jedem API-Release neu veröffentlicht; Sie können auch Ihren eigenen Client in jeder von OpenAPI unterstützten Sprache generieren.
Der erste Aufruf#
Erstellen Sie einen Kurzlink aus der Ziel-URL. Fünf Zeilen 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 (kein offizielles SDK – Verwendung von 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'];
Alle fünf liefern das gleiche Ergebnis. Der Response-Body enthält die Kurz-URL, die kanonische Link-ID, die Workspace-ID und den Zeitstempel der Erstellung. Der Slug – abc123 im obigen Beispiel – wird vom Server generiert, sofern Sie im Request nicht custom_slug übergeben. Das Slug-Alphabet ist Base62 ([0-9A-Za-z]); die Standardlänge beträgt sechs Zeichen.
Die vier Endpunkte, die Sie tatsächlich nutzen werden#
Die API verfügt über mehr als vier Endpunkte, aber die meisten Integrationen beschränken sich auf dieses Set.
Einen Link erstellen#
POST /v1/links akzeptiert die Ziel-URL sowie optionale Felder:
custom_slug– ein von Ihnen gewählter Slug (muss innerhalb des Workspace eindeutig sein).domain_id– für Links mit eigener Domain; die primäre Domain des Workspace wird verwendet, falls ausgelassen.tags– ein Array von Freitext-Strings zur Organisation.utm– Kampagnenparameter, die zum Zeitpunkt des Redirects an das Ziel angehängt werden.expires_at– ISO 8601 Zeitstempel, nach dem der Link 410 Gone zurückgibt.password– falls gesetzt, zeigt der Redirect vor der Weiterleitung eine Passwortseite an.metadata– opakes JSON-Objekt, das der Redirect nicht interpretiert; nützlich für Ihre eigenen Join-Keys.
Der benutzerdefinierte Slug (Custom Slug) ist das Feld, das Teams in der Produktion oft Probleme bereitet. Wenn Sie einen Slug übergeben, der bereits von einem anderen Link im selben Workspace verwendet wird, gibt die API einen 409 Conflict zurück. Der naive Retry-Handler, der einen Zähler anhängt (my-slug-1, my-slug-2), führt zum Problem der doppelten Links, das eingangs beschrieben wurde. Das korrekte Retry-Verhalten wird im Abschnitt zur Idempotenz beschrieben.
Einen Link lesen#
GET /v1/links/{id} gibt den vollständigen Link-Datensatz zurück, einschließlich der aktuellen Klickanzahl, des Zeitstempels des letzten Klicks und der gesamten Konfiguration. Die Link-ID ist der kanonische Identifikator – Slugs können sich ändern (Pro+ unterstützt Slug-Umbenennungen), IDs nicht.
GET /v1/links?domain_id=…&tag=…&limit=… listet Links im Workspace mit Filtern auf. Die Paginierung ist Cursor-basiert; next_cursor in der Antwort ist opak und wird im nächsten Request als Query-Parameter cursor zurückgegeben.
Einen Link aktualisieren#
PATCH /v1/links/{id} akzeptiert dieselben Felder wie Create. Die häufigsten Updates sind: Ändern der Ziel-URL (nützlich für Kampagnen-Rotationen ohne Neudruck von QR-Codes), Ändern von Tags oder Verlängern von expires_at. Das Aktualisieren des Slugs erfolgt über einen separaten POST /v1/links/{id}/rename Endpunkt, der den 301-Redirect vom alten Slug für einen konfigurierbaren Zeitraum (Standard 30 Tage) verwaltet.
Einen Link löschen#
DELETE /v1/links/{id} führt ein Soft-Delete durch. Der Link gibt für die nächsten 90 Tage 410 Gone zurück und wird dann endgültig gelöscht. Die Papierkorb-Ansicht im Dashboard zeigt Soft-Delete-Links an; Sie können diese über das Dashboard oder über POST /v1/links/{id}/restore innerhalb des 90-Tage-Fensters wiederherstellen.
Idempotenz-Keys#
Jeder mutierende Request – POST, PATCH, DELETE – akzeptiert einen Idempotency-Key-Header. Der Header-Wert ist ein opaker String mit bis zu 255 Zeichen; der Server speichert den Response-Body und den Statuscode für 24 Stunden unter dem Key (workspace_id, idempotency_key) und gibt die gespeicherte Antwort zurück, wenn derselbe Key erneut gesendet wird.
Die offiziellen SDKs generieren Idempotenz-Keys automatisch, falls diese nicht angegeben werden. Sie können dies überschreiben:
const link = await elido.links.create(
{ destinationUrl: "https://shop.example.com/spring-sale" },
{ idempotencyKey: "order-12345-link" },
);
Der Anwendungsfall ist eine Retry-Schleife. Wenn Ihr Job einen Link als Teil der Verarbeitung eines Upstream-Auftrags erstellt, generieren Sie den Idempotenz-Key aus der Auftrags-ID. Ein erneuter Versuch desselben Jobs verwendet denselben Key, trifft auf den Idempotenz-Cache und gibt den ursprünglich erstellten Link zurück, anstatt einen zweiten zu erzeugen.
Die Tücke: Der Idempotenz-Cache bleibt nur 24 Stunden bestehen, nicht ewig. Ein Retry am dritten Tag eines hängengebliebenen Jobs wird einen neuen Link erstellen. Wenn die Integration über mehrtägige Batches läuft, speichern Sie die vom ersten erfolgreichen Create zurückgegebene Link-ID und prüfen Sie diese vor einer erneuten Erstellung.
Eine zweite Tücke: Idempotenz gilt pro Workspace. Derselbe Key in zwei Workspaces erstellt zwei Links. Dies ist die richtige Semantik für eine Multi-Workspace-API, kann aber Teams überraschen, die davon ausgehen, dass der Key global eindeutig ist.
Fehlerbehandlung#
Die API gibt Standard-HTTP-Statuscodes sowie einen strukturierten Fehler-Body zurück:
{
"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
}
}
Die Codes, die Sie am häufigsten sehen werden:
400 invalid_request– Validierungsfehler des Payloads. Das Feldmessagelistet die spezifischen Felder auf. Nicht erneut versuchen; Payload korrigieren.401 unauthorized– Token fehlt oder ist ungültig. Nicht ohne Token-Rotation erneut versuchen.403 forbidden– Token hat nicht den erforderlichen Scope. Prüfen Sie die Scope-Liste des Tokens unter/settings/api.404 not_found– Die Ressource existiert nicht oder das Token hat keinen Zugriff darauf (wir geben 404 statt 403 zurück, um die Existenz von Ressourcen vor unbefugten Aufrufern nicht preiszugeben).409 conflict– Slug bereits in Benutzung oder gleichzeitige Bearbeitung erkannt (PATCH auf eine veraltete Version). Erneut abrufen und versuchen.429 rate_limit_exceeded– Backoff gemäß dem Wert vonretry_after.500 internal_server_error– Serverseitiger Fehler. Sicherer Retry mit demselben Idempotenz-Key möglich.502 bad_gateway,503 service_unavailable,504 gateway_timeout– Vorübergehende Infrastrukturprobleme. Backoff und Retry.
Die offiziellen SDKs implementieren einen exponentiellen Backoff mit Jitter für 429, 500, 502, 503 und 504. Sie führen keinen Retry für 400, 401, 403, 404 oder 409 durch – dabei handelt es sich um Programmierfehler oder Konflikte in der Geschäftslogik, nicht um vorübergehende Fehler. Eigene HTTP-Clients sollten demselben Muster folgen; ein erneuter Versuch eines 400-Fehlers mit demselben Payload wird kein anderes Ergebnis liefern.
Die request_id im Fehler-Body ist das Feld, das in Support-Tickets angegeben werden sollte. Wir können jeden Request anhand dieser ID durch das Audit-Log, das App-Log und die Plattform-Metriken zurückverfolgen – ohne diese ID ist uns das nicht möglich.
Rate-Limits#
Die veröffentlichten Rate-Limits betragen 100 Anfragen pro Sekunde pro Workspace bei Pro, 500 bei Business und ein individuell vereinbartes Limit bei Enterprise. Der Free-Tarif liegt bei 10 req/s.
Der Status des Rate-Limits wird in jedem API-Response über drei Header offengelegt:
X-RateLimit-Limit– Das aktuelle Limit pro Sekunde.X-RateLimit-Remaining– Verbleibende Anfragen in der aktuellen Sekunde.X-RateLimit-Reset– Unix-Zeitstempel, wann das Bucket zurückgesetzt wird.
Das Limit von 100/s ist eine Token-Bucket-Implementierung mit einer Burst-Kapazität von 200 – das bedeutet, Sie können 200 Anfragen auf einmal senden, wenn das Bucket voll ist, und sich dann auf die dauerhafte Rate von 100/s einpendeln. Die meisten Jobs zur Erstellung von Kurzlinks passen bequem in den Burst; Analytics-intensive Integrationen, die historische Klick-Events durchblättern, profitieren vom Spielraum des Pro-Tarifs.
Für Bulk-Operationen ab Business+ akzeptiert der POST /v1/links/bulk Endpunkt bis zu 1000 Links pro Anfrage und zählt als eine Rate-Limit-Einheit. Dies ist der richtige Endpunkt für jeden Job, der mehr als hundert Links gleichzeitig erstellt.
Was die SDKs leisten, was einfaches HTTP nicht tut#
Die offiziellen SDKs liefern vier Funktionen mit, die sich schnell bezahlt machen:
- Automatischer Retry mit Backoff für die wiederholbaren Statuscodes.
- Generierung von Idempotenz-Keys, wenn diese nicht explizit angegeben werden.
- Typisierte Fehler, sodass Sie
catch (err) { if (err instanceof ElidoRateLimitError) { … } }nutzen können, anstatt JSON in Catch-Blöcken zu parsen. - Paginierungs-Iteratoren, sodass Listen-Endpunkte Async-Iteratoren oder Generatoren bereitstellen, anstatt ein manuelles Cursor-Handling zu erfordern.
Das Go SDK legt zusätzlich den zugrunde liegenden HTTP-Client für Instrumentierung offen – nützlich, wenn Sie ihn in Ihr bestehendes Tracing-Setup einbinden möchten. Die API + SDKs Feature-Seite im Repo deckt den gesamten Funktionsumfang ab; die API-Referenz ist unter /docs/api-reference veröffentlicht.
Zugriff auf Analytics#
Die Analytics-Endpunkte sind schreibgeschützt und befinden sich unter /v1/workspaces/{id}/analytics/. Die häufigsten Abfragen sind:
GET .../links/{id}/clicks?from=…&to=…– Rohe Klick-Events mit Paginierung. Nützlich für Export-Pipelines.GET .../timeseries?from=…&to=…&bucket=day– Gruppierte Klickzahlen für einen Zeitraum.GET .../breakdown/country?from=…&to=…– Geografische Aufschlüsselung.GET .../breakdown/referrer?from=…&to=…– Aufschlüsselung nach Referrer.
Der Feed für rohe Klick-Events ist am umfangreichsten. Ein Workspace mit 10 Mio. Klicks pro Monat produziert etwa 600 MB JSON pro Monat an rohen Event-Daten. Für Exporte in dieser Größenordnung beschreibt der ClickHouse-Export-Guide den Bulk-Export-Mechanismus, der den JSON-Umschlag umgeht und direkt aus dem Analytics-Warehouse streamt.
Webhooks für Klick-Events#
Webhooks sind das Gegenteil von Polling – anstatt die API nach neuen Klicks zu fragen, liefert die API diese an Ihren Endpunkt. Die Konfiguration erfolgt unter /settings/webhooks:
await elido.webhooks.create({
url: "https://your-app.example/webhooks/elido",
events: ["link.click", "link.created", "link.expired"],
secret: process.env.WEBHOOK_SIGNING_SECRET,
});
Jede Zustellung enthält einen Elido-Signature-Header, der einen HMAC-SHA256 des Request-Bodys mit Ihrem gemeinsamen Secret enthält. Verifizieren Sie die Signatur vor der Verarbeitung – ohne diese kann jeder Aufrufer Daten an Ihren Webhook-Endpunkt senden und sich als Elido ausgeben.
Die Zustellungssemantik ist At-Least-Once mit exponentiellem Backoff bis zu einer maximalen Vorhaltezeit von 72 Stunden. Für detaillierte Informationen zum Format und Retry-Verhalten vergleicht der Beitrag Webhooks vs. Polling für Klick-Tracking die beiden Integrationsmuster.
Ein Praxisbeispiel: Kampagnen-Automatisierung#
Die Integration, die die meisten zur Nutzung der API bewegt, sieht so aus: Ihre Marketing-Automatisierung erstellt eine Kampagne in Customer.io oder HubSpot. Ein Hook wird ausgelöst, wenn die Kampagne veröffentlicht wird. Ihr Handler erstellt den Kurzlink, hängt ihn an den Kampagnen-Datensatz an und sendet ihn an das Kampagnen-Management-Tool zurück, um ihn in das E-Mail-Template einzufügen.
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}`, campaign.channel],
utm: {
source: campaign.channel,
medium: "email",
campaign: campaign.slug,
},
metadata: { campaign_id: campaign.id, batch: campaign.batchId },
},
{
idempotencyKey: `campaign-${campaign.id}-link`,
},
);
await campaignStore.update(campaign.id, { shortUrl: link.shortUrl });
return link;
}
Der Idempotenz-Key wird aus der Kampagnen-ID abgeleitet. Wenn der Hook für die veröffentlichte Kampagne zweimal ausgelöst wird (was vorkommt – Webhook-Zustellungen sind At-Least-Once), gibt der zweite Aufruf denselben Link zurück, ohne ein Duplikat zu erstellen. Das Feld metadata enthält Ihre eigenen Join-Keys, sodass Sie die Klick-Events von Elido wieder mit der Kampagne korrelieren können, ohne Tags parsen zu müssen.
Für eine End-to-End-Kampagnen-Attribution mit UTM-Templates und Conversion-Weiterleitung führt der UTM-Tracking-Leitfaden durch die gesamte Pipeline.
Was noch nicht in der API enthalten ist#
Zwei Dinge, die häufig angefragt werden, aber derzeit nicht verfügbar sind:
- Ein einzelner Analytics-GET für Links, der alle Aufschlüsselungen in einem Aufruf zurückgibt. Das aktuelle Modell erfordert separate Aufrufe für Klicks, Land, Referrer, Gerät und Zeitreihen. Die Aggregation steht auf der Roadmap; derzeit parallelisieren die SDKs die Anfragen mit einer einzigen Hilfsmethode.
- Webhook-Replay über die API. Das Dashboard zeigt den Verlauf der Webhook-Zustellungen an und unterstützt Replays; die API bietet dies noch nicht an. Auch dies steht auf der Roadmap.
Wenn ein Feature in der OpenAPI-Spezifikation steht, wird es unterstützt. Wenn es in diesem Beitrag steht, aber nicht in der Spezifikation, betrachten Sie es als geplant, nicht als garantiert.
Weiterführende Informationen#
- Smart Links erklärt – Der Grundstein für das Features-Cluster; beschreibt, wie die Redirect-Engine einen Link an der Edge auflöst.
- Webhooks vs. Polling für Klick-Tracking – Wann welches Integrationsmuster verwendet werden sollte.
- Serverseitiges Conversion-Tracking über Kurzlinks – Erweiterung der API in den Conversion-Weiterleitungsfluss.
- Kampagnen-Bulk-Import aus Google Sheets – Ein Praxisbeispiel für den Bulk-Endpunkt.
- Operationaler Walkthrough: Der MCP-Server-Guide zur Verbindung der Elido API-Oberfläche mit Claude, Cursor und anderen MCP-fähigen Clients.
- Produktübersicht:
/features/api-sdksund/solutions/developers.