Eine URL-Shortener-API ist eine der kleineren Integrationen im Backlog eines typischen Engineering-Teams. Drei Endpunkte, ein Auth-Header, ein JSON-Payload. Die Doku verspricht den ersten Aufruf in fünf Minuten. Dann trifft Produktionstraffic ein, die Retry-Logik erzeugt doppelte Links, das Dashboard füllt sich mit /foo-1, /foo-2, /foo-3-Varianten desselben Ziels, und jemand legt ein Ticket an.
Dieser Beitrag geht die tatsächliche Integration durch: Auth, den ersten Aufruf, die vier Endpunkte, die die meisten Anwendungsfälle abdecken, Idempotenz, Fehlerbehandlung, Rate Limits und die Produktions-Fallstricke, die der Fünf-Minuten-Schnelleinstieg auslässt. 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
Melde dich im Dashboard an, navigiere zu /dashboard/api-keys und erstelle einen API-Schlüssel (er beginnt mit elido_). Tokens sind workspace-gebunden - ein in Workspace A ausgestelltes Token kann in Workspace B keine Links erstellen. Machine-User-Tokens (für CI-Systeme, interne Tools, Machine-to-Machine-Integrationen) werden unter /dashboard/machine-users erstellt und rotieren unabhängig von persönlichen Schlüsseln. Beide Arten tragen eine feste Workspace-Rolle (viewer, editor oder admin) statt Scopes pro Endpunkt - gib einem CI-Job also editor, wenn er nur Links erstellt. Der Leitfaden zu Berechtigungen für API-Schlüssel für Link-Tools zeigt, welche Zugriffe jede Rolle ermöglicht, einschließlich der Erklärung, warum Änderungen an Webhooks admin erfordern.
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. Deine Short Links lösen über die Redirect-Domain auf; die API dient dem Erstellen, Ändern und Lesen dieser Links.
Die OpenAPI-Spezifikation ist unter https://elido.app/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; du kannst auch deinen eigenen Client in jeder OpenAPI-unterstützten Sprache generieren.
Der erste Aufruf
Erstelle einen Short Link 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 - mit 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 dasselbe Ergebnis. Der Response-Body enthält die Short URL, die kanonische Link-ID, die Workspace-ID und den Erstellungszeitstempel. Der Slug - abc123 im Beispiel oben - wird vom Server generiert, sofern du nicht slug in der Anfrage übergibst. Das Slug-Alphabet ist base62 ([0-9A-Za-z]); die Standardlänge beträgt sechs Zeichen.
Die vier Endpunkte, die du tatsächlich brauchst
Die API hat mehr als vier Endpunkte, aber die meisten Integrationen kommen mit diesem Set aus.
Einen Link erstellen
POST /v1/links akzeptiert die Ziel-URL plus optionale Felder:
slug- ein selbst gewählter Slug (muss auf der Domain eindeutig sein).domain_id- für Links mit eigener Domain; bei/v1/linkswird die Standard-Short-Domain deines Tarifs verwendet, falls weggelassen. Der Workspace-spezifische Pfad/v1/workspaces/{workspace_id}/linkserfordert das Feld.title- eine im Dashboard angezeigte Bezeichnung.tags- ein Array von Freitext-Strings zur Organisation.expires_at- RFC-3339-Zeitstempel, nach dem der Link 410 Gone zurückgibt.redirect_status-301,302(der Standardwert) oder307.password- beim Erstellen noch nicht akzeptiert; setze es direkt danach mit einemPATCH. Der Redirect liefert dann eine Passwortseite aus, bevor weitergeleitet wird.utmundmetadata- geplant. Füge UTM-Parameter heute direkt indestination_urlein und verwalte eigene Join-Keys intags.
Der Custom Slug ist das Feld, das Teams in der Produktion beißt. Übergibst du einen Slug, der bereits von einem anderen Link auf derselben Domain verwendet wird, liefert die API 409 Conflict. Der naive Retry-Handler, der einen Zähler anhängt (my-slug-1, my-slug-2), erzeugt genau das Duplikat-Problem aus der Einleitung. Das korrekte Retry-Verhalten wird im Abschnitt zur Idempotenz weiter unten beschrieben.
Einen Link lesen
GET /v1/links/{id} liefert den vollständigen Link-Datensatz, einschließlich short_url und der gesamten Konfiguration. Klickzahlen stehen nicht im Link-Datensatz, sondern kommen von den unten genannten Analytics-Endpunkten. Die Link-ID ist der kanonische Identifikator - Slugs können sich ändern, IDs nicht.
GET /v1/links?host=…&tags=…&limit=… listet Links im Workspace mit Filtern auf. Die Paginierung ist cursor-basiert; next_cursor in der Antwort ist opak und geht als cursor-Query-Parameter in die nächste Anfrage ein.
Einen Link aktualisieren
PATCH /v1/links/{id} akzeptiert dieselben Felder wie beim Erstellen. Die häufigsten Änderungen: die Ziel-URL ändern (nützlich für Kampagnenrotation ohne QR-Codes neu zu drucken), Tags ändern, expires_at verlängern. Der Slug wird über denselben PATCH geändert, indem du einen neuen slug sendest. Der alte Slug löst sofort nicht mehr auf; ein eigener Rename-Endpunkt, der für eine Aufbewahrungsfrist einen 301-Redirect vom alten Slug beibehält, ist geplant, aber noch nicht implementiert.
Einen Link löschen
DELETE /v1/links/{id} löscht den Link weich und gibt 204 No Content zurück. Der Link leitet nicht mehr weiter und fällt aus Listen- und Leseaufrufen heraus. Eine Papierkorb-Ansicht mit Restore-Endpunkt und einem 90-Tage-Fenster bis zur endgültigen Löschung ist geplant; heute gibt es keinen API-Aufruf, der einen gelöschten Link zurückbringt.
Idempotenzschlüssel
Jede verändernde Anfrage - POST, PATCH, DELETE - akzeptiert einen Idempotency-Key-Header. Der Header-Wert ist ein opaker String von bis zu 255 Zeichen; der Server speichert den Response-Body und den Statuscode für 24 Stunden, indiziert nach (workspace_id, idempotency_key), und liefert die gespeicherte Antwort zurück, wenn derselbe Schlüssel erneut übergeben wird.
Die offiziellen SDKs generieren Idempotenzschlüssel automatisch, wenn keiner angegeben wird. Du kannst das überschreiben:
const link = await elido.links.create(
{ destinationUrl: "https://shop.example.com/spring-sale" },
{ idempotencyKey: "order-12345-link" },
);
Der Anwendungsfall ist eine Retry-Schleife. Erstellt dein Job als Teil der Verarbeitung einer vorgelagerten Bestellung einen Link, generiere den Idempotenzschlüssel aus der Bestell-ID. Ein Retry desselben Jobs sieht denselben Schlüssel, trifft auf den Idempotenz-Cache und liefert den ursprünglich erstellten Link zurück, statt einen zweiten zu erzeugen.
Der zentrale Fallstrick: Der Idempotenz-Cache lebt 24 Stunden, nicht für immer. Ein Retry am dritten Tag eines hängengebliebenen Jobs erzeugt einen neuen Link. Läuft die Integration über mehrtägige Batches, speichere die vom ersten erfolgreichen Create zurückgegebene Link-ID und schlage sie nach, bevor du erneut erstellst.
Ein zweiter Fallstrick: Idempotenz gilt pro Workspace. Derselbe Schlüssel in zwei Workspaces erzeugt zwei Links. Das ist die richtige Semantik für eine Multi-Workspace-API, kann aber Teams überraschen, die davon ausgehen, dass der Schlüssel global eindeutig ist.
Fehlerbehandlung
Die API liefert Standard-HTTP-Statuscodes plus einen strukturierten Fehler-Body:
{
"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 du am häufigsten sehen wirst:
400 invalid_request- Validierungsfehler im Payload. Das Feldmessagelistet die betroffenen Felder auf. Nicht erneut versuchen; den Payload korrigieren.401 unauthorized- Token fehlt oder ist ungültig. Nicht erneut versuchen, ohne das Token zu rotieren.403 forbidden- die Rolle des Tokens erlaubt die Aktion nicht (einviewer-Schlüssel kann keine Links erstellen). Rolle des Schlüssels unter/dashboard/api-keysprüfen.404 not_found- die Ressource existiert nicht, oder das Token hat keinen Zugriff darauf (wir liefern 404 statt 403, um nicht offenzulegen, ob eine Ressource existiert, gegenüber nicht autorisierten Aufrufern).409 conflict- Slug bereits vergeben, oder gleichzeitige Bearbeitung erkannt (PATCH auf einer veralteten Version). Erneut abrufen und erneut versuchen.429 rate_limit_exceeded- gemäß dem Wert vonretry_afterzurückstufen.500 internal_server_error- serverseitiger Fehler. Sicher, mit demselben Idempotenzschlüssel erneut zu versuchen.502 bad_gateway,503 service_unavailable,504 gateway_timeout- vorübergehende Infrastrukturprobleme. Zurückstufen und erneut versuchen.
Die offiziellen SDKs implementieren exponentielles Backoff mit Jitter für 429, 500, 502, 503 und 504. Sie versuchen 400, 401, 403, 404 oder 409 nicht erneut - das sind Programmierfehler oder Business-Logic-Konflikte, keine vorübergehenden Fehler. Eigene HTTP-Clients sollten demselben Muster folgen; ein 400 mit demselben Payload erneut zu versuchen, liefert kein anderes Ergebnis.
Die request_id im Fehler-Body ist das Feld, das in Support-Tickets gehört. Wir können jede Anfrage anhand dieser ID durch das Audit-Log, das Anwendungslog und die Plattform-Metriken zurückverfolgen - und ohne sie können wir eine Anfrage nicht zurückverfolgen.
Rate Limits
Die veröffentlichten Rate Limits liegen bei 100 Anfragen pro Sekunde pro Workspace auf Pro, 500 auf Business und einem verhandelten Limit auf Enterprise. Der Free-Tarif liegt bei 10 req/s.
Der Rate-Limit-Status ist in drei Response-Headern auf jeder API-Antwort sichtbar:
X-RateLimit-Limit- das aktuelle Limit pro Sekunde.X-RateLimit-Remaining- verbleibende Anfragen in der aktuellen Sekunde.X-RateLimit-Reset- Unix-Zeitstempel, wann der Bucket zurückgesetzt wird.
Das Limit von 100/s ist eine Token-Bucket-Implementierung mit einer Burst-Kapazität von 200 - das heißt, du kannst 200 Anfragen auf einmal senden, wenn der Bucket voll ist, und pendelst dich dann auf die dauerhafte Rate von 100/s ein. Die meisten Jobs zum Erstellen von Short Links passen bequem in den Burst; analytiklastige Integrationen, die sich durch historische Klickereignisse blättern, profitieren vom zusätzlichen Spielraum des Pro-Tarifs.
Für Massenoperationen akzeptiert der Endpunkt POST /v1/links/bulk bis zu 100 Links pro Anfrage und zählt als eine Rate-Limit-Einheit. Das ist der richtige Endpunkt für jeden Job, der auf einmal mehr als hundert Links erstellt. Für eine tiefere Behandlung des Tempos gegenüber dem Token-Bucket, der Auswahl, welche Statuscodes erneut versucht werden sollten, und wie Idempotenzschlüssel verhindern, dass Retries Links duplizieren, siehe Rate Limits, Retries und Idempotenz in der Produktion.
Was die SDKs bieten, was reines HTTP nicht bietet
Die offiziellen SDKs liefern vier Dinge, die sich schnell auszahlen:
- Automatischer Retry mit Backoff für die wiederholbaren Statuscodes.
- Generierung von Idempotenzschlüsseln, wenn keiner explizit angegeben wird.
- Typisierte Fehler, sodass du
catch (err) { if (err instanceof ElidoRateLimitError) { … } }schreiben kannst, statt JSON in Catch-Blöcken zu parsen. - Paginierungs-Iteratoren, sodass List-Endpunkte asynchrone Iteratoren oder Generatoren bereitstellen, statt manuelle Cursor-Handhabung zu erfordern.
Das Go-SDK stellt zusätzlich den zugrunde liegenden HTTP-Client für Instrumentierung bereit - nützlich, wenn du ihn in dein bestehendes Tracing-Setup einbinden möchtest. Die Feature-Seite zu API + SDKs deckt die gesamte Oberfläche ab; die API-Referenz ist unter /docs/api-reference veröffentlicht.
Zugriff auf Analytics
Die Analytics-Endpunkte sind schreibgeschützt und liegen unter /v1/workspaces/{id}/analytics/; der Leitfaden zur Link-Analytics-API listet alle Reports, ihre Parameter und ihre Antwortstruktur auf. Die häufigsten Abfragen:
GET .../clicks/recent?from=…&to=…- einzelne Klicks, neueste zuerst, mitnext_cursorpaginiert. Nützlich für Export-Pipelines.GET .../timeseries?from=…&to=…&interval=day- gebündelte Klickzahlen für einen Zeitraum;intervalisthouroderday, undtzlegt die Zeitzone der Buckets fest.GET .../breakdown/country?from=…&to=…- geografische Aufschlüsselung.GET .../breakdown/referrer?from=…&to=…- Aufschlüsselung nach Referrer.
Die übrigen Reports sind summary, links/top, die verbleibenden Aufschlüsselungen (host, device, browser, destination) und die Top-Listen (top-countries, top-regions, top-cities, top-referrers, top-destinations). from und to sind Datumsangaben im Format YYYY-MM-DD, wobei to exklusiv ist; füge link_id hinzu, um jeden Report auf einen Link einzugrenzen, und limit, um die Größe von Aufschlüsselungen und Top-Listen festzulegen.
Der Feed roher Klickereignisse ist der größte. Ein Workspace mit 10 Mio. Klicks pro Monat erzeugt etwa 600 MB rohe Ereignisdaten als JSON pro Monat. Für Exports in dieser Größenordnung deckt der Analytics-Export-Leitfaden den Bulk-Export-Mechanismus ab, der das JSON-Envelope umgeht und direkt aus dem Analytics-Warehouse streamt.
Webhooks für Link-Ereignisse
Webhooks sind das Gegenstück zum Polling - statt dass du die API fragst, was sich geändert hat, liefert die API Link- und Domain-Ereignisse an deinen Endpunkt. Konfiguration unter /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,
});
Ein click.created-Ereignis pro Klick ist geplant, aber noch nicht verfügbar - Klickdaten kommen daher heute aus den Analytics-Endpunkten. Jede Zustellung enthält einen X-Elido-Signature-Header (auch als X-Webhook-Signature gesendet) mit dem Wert v1=<hex>: ein HMAC-SHA256, mit deinem Endpunkt-Secret als Schlüssel, über den Wert von X-Webhook-Timestamp, einen Punkt und den rohen Request-Body. Überprüfe die Signatur, bevor du verarbeitest - ohne sie kann jeder Aufrufer an deinen Webhook-Endpunkt posten und sich als Elido ausgeben.
Die Zustellsemantik ist at-least-once: Eine fehlgeschlagene Zustellung wird mit einem Backoff von Minuten erneut versucht, standardmäßig mit insgesamt drei Versuchen. Für die genaue Form und das Retry-Verhalten vergleicht der Beitrag Webhooks vs. Polling die beiden Integrationsmuster.
Ein durchgerechnetes Beispiel: Kampagnenautomatisierung
Die Integration, die die meiste API-Adoption motiviert, sieht so aus. Deine Marketing-Automatisierung erstellt eine Kampagne in Customer.io oder HubSpot. Ein Hook feuert, wenn die Kampagne veröffentlicht wird. Dein Handler erstellt den Short Link, hängt ihn an den Kampagnendatensatz und sendet ihn zurück an das Kampagnen-Management-Tool, um ihn in die E-Mail-Vorlage einzusetzen.
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;
}
Der Idempotenzschlüssel wird aus der Kampagnen-ID abgeleitet. Feuert der Hook für veröffentlichte Kampagnen zweimal (das passiert - Webhook-Zustellungen sind at-least-once), liefert der zweite Aufruf denselben Link zurück, ohne ein Duplikat zu erzeugen. Die Tags campaign: und batch: enthalten deine eigenen Join-Keys, sodass du Elidos Klickereignisse mit der Kampagne korrelieren kannst; ein eigenes metadata-Feld dafür ist geplant. UTM-Parameter gehören in campaign.destinationUrl selbst, bis das Feld utm verfügbar ist.
Für durchgängige Kampagnenattribution mit UTM-Vorlagen und Conversion-Weiterleitung führt der UTM-Tracking-Cornerstone durch die gesamte Pipeline.
Was noch nicht in der API steckt
Zwei häufig nachgefragte Dinge, die derzeit nicht verfügbar sind:
- Ein einzelner Analytics-GET für einen Link, der alle Aufschlüsselungen in einem Aufruf liefert. Das aktuelle Modell erfordert separate Aufrufe für Klicks, Land, Referrer, Gerät und Zeitreihe. Die Aggregation ist geplant; führe die Anfragen bis dahin in deinem eigenen Code parallel aus.
- Webhook-Replay über die API. Das Dashboard zeigt den Zustellverlauf von Webhooks an und unterstützt Replay; die API noch nicht. Auch das ist geplant.
Steht ein Feature in der OpenAPI-Spec, wird es unterstützt. Steht es in diesem Beitrag, aber nicht in der Spec, behandle es als geplant, nicht als garantiert.
Weiterführende Lektüre
- Smart Links erklärt - der Cornerstone für das Features-Cluster; behandelt, wie die Redirect-Engine einen Link am Edge auflöst.
- Webhooks vs. Polling für Click-Tracking - wann welches Integrationsmuster passt.
- Serverseitiges Conversion-Tracking über Short Links - die Erweiterung der API in den Conversion-Weiterleitungs-Flow.
- Bulk-Import von Kampagnen aus Google Sheets - ein durchgerechnetes Beispiel für den Bulk-Endpunkt.
- URL-Shortener-API: Rate Limits, Retries, Idempotenz - die Integration für Produktionstraffic härten.
- Berechtigungen für API-Schlüssel für Link-Tools - workspace-gebundene Schlüssel, Rollenlimits und Rotation.
- Kostenlose URL-Shortener-API: Codebeispiele, die laufen - der Create-Aufruf in curl, JavaScript, Python und Go, und was Free-Tarife einschränken.
- Link-Analytics-API: Klickstatistiken mit einem API-Schlüssel abrufen - jeder Report, seine Abfrageparameter und ein tägliches Slack-Skript.
- Operativer Leitfaden: der MCP-Server-Guide zur Anbindung von Elidos API-Oberfläche an Claude, Cursor und andere MCP-fähige Clients.
- Produktoberfläche:
/features/api-sdksund/solutions/developers.
Elido testen
URL einfügen, kurzer Link in Sekunden
Kein Konto nötig. Link bleibt 30 Tage aktiv. Konto erstellen, um ihn dauerhaft zu behalten.
Kostenlos, keine Anmeldung erforderlich · 2 pro Tag