Elido
Pick the angle that fits your team
For developers

The shortener you can read the source of.

You measure latency, error rates, and time-to-MTTR. Elido is the shortener you can read the source of — REST + gRPC, SDKs in six languages, OpenTelemetry spans on every redirect, and an Apache 2.0 self-host path the day you decide SaaS is the wrong shape.

  • REST + gRPC: pick the surface your service mesh prefers
  • OpenTelemetry spans on every redirect, every API call
  • Six SDKs: TypeScript, Go, Python, Ruby, PHP, .NET
  • Apache 2.0 self-host with a one-command Helm chart
POST /v1/links
201 Created · 38 ms
Request
curl -X POST https://api.elido.app/v1/links
  -H "Authorization: Bearer $ELIDO_API_KEY"
  -H "Idempotency-Key: ci-2026-05-08-build-4419"
  -d '{
    "destination_url": "https://shop.example.com/launch",
    "slug": "q2-launch",
    "workspace_id": "ws_8f3c"
  }'
Response
{
  "id": "link_01HQ3X...",
  "short_url": "https://b.elido.me/q2-launch",
  "click_tracker": "https://api.elido.app/v1/links/link_01HQ3X/clicks",
  "expires_at": "2026-08-08T00:00:00Z",
  "created_at": "2026-05-08T11:24:01Z"
}
Idempotent · safe to retry Live spec
OpenAPI 3.1
Spec format
3
First-party SDKs
5 ms
p50 redirect (cache HIT)
Apache 2.0
Self-host license

Observability — built in, not bolted on

Every redirect emits an OpenTelemetry span. Every span lands in your collector.

The edge service is instrumented end-to-end with OTel. Point your OTLP collector at the redirect tier and you get the full waterfall — cache lookup, rule evaluation, response, and the async click-event publish — without writing a single instrumentation line yourself.

Trace · 7f3a91 · GET / → 302
5 spans · 5.2 ms wall
edge.redirect
fasthttp · server
4.8 ms
cache.lookup (L1 → L2)
in-process LRU + Redis
0.6 ms
rule.evaluate
smart-link first-match
0.3 ms
response.write
302 + click_id header
1.0 ms
click.publish (async)
Redpanda · fire-and-forget
0.4 ms
Wall time
5.2 ms
Cache
L1 hit
Exporter
OTLP/gRPC

SDKs

Same canonical call. Six languages. All generated from one spec.

Every SDK ships from the same OpenAPI 3.1 spec. New endpoint added on the server? Run the generator, ship the SDKs, done. No hand-maintained client that drifts from the API. Idempotency keys, retries with exponential backoff, and typed error responses are surfaced consistently across all six languages.

  • OpenAPI 3.1 source of truth
    Spec checked in. SDKs regenerated on every release.
  • Typed error responses
    Rate-limit, validation, conflict — all typed, never stringly-caught.
  • Idempotency keys
    Header-based on every write endpoint, replayed on retry.
  • Built-in retries
    Exponential backoff with Retry-After honoured per language.
All six SDKs →
Canonical create — same call, three SDKs
generated from spec
TypeScriptcreate-link.ts
1import { Elido } from
2 "@elido/sdk";
3 
4const elido = new Elido({
5 apiKey: process.env.ELIDO_API_KEY!,
6});
7 
8const link = await elido.links.create({
9 destinationUrl: dest,
10 slug: "q2-launch",
11});
Gocreate-link.go
1import "github.com/elido/sdk-go"
2 
3client := elido.NewClient(
4 elido.WithAPIKey(key),
5)
6 
7link, err := client.Links.Create(ctx,
8 &elido.CreateLinkRequest{
9 DestinationURL: dest,
10 Slug: "q2-launch",
11 })
Pythoncreate_link.py
1from elido import Elido
2 
3elido = Elido(
4 api_key=os.environ["ELIDO_API_KEY"],
5)
6 
7link = elido.links.create(
8 destination_url=dest,
9 slug="q2-launch",
10 idempotency_key=build_id,
11)
sdk-ts@2.4 · sdk-go@2.4 · sdk-py@2.4 in sync

gRPC contract

Same surface in protobuf — for service-mesh natives.

The api-core service serves both REST and gRPC from the same handlers. If your platform speaks proto natively (Envoy, Istio, Linkerd, Connect-Go), skip the JSON layer. The .proto files are published; generate clients in any language buf or protoc supports.

link_service.proto
buf · v1
1syntax = "proto3";
2 
3package elido.api.v1;
4 
5option go_package = "github.com/elido/proto/api/v1;apiv1";
6 
7service LinkService {
8 rpc Create(CreateLinkRequest) returns (Link);
9 rpc Resolve(ResolveLinkRequest) returns (ResolveLinkResponse);
10 rpc List(ListLinksRequest) returns (ListLinksResponse);
11 rpc Delete(DeleteLinkRequest) returns (google.protobuf.Empty);
12}
13 
14message CreateLinkRequest {
15 string workspace_id = 1;
16 string destination_url = 2;
17 optional string slug = 3;
18 optional google.protobuf.Timestamp expires_at = 4;
19 repeated KeyValue tags = 5;
20}
21 
22message Link {
23 string id = 1;
24 string short_url = 2;
25 string destination_url = 3;
26 google.protobuf.Timestamp created_at = 4;
27}
served from api-core:9090 stable
mTLSservice-mesh native

Authenticate with workload identity via SPIFFE/SPIRE or your mesh's built-in mTLS. API keys still work for non-mesh callers.

Same handlersREST and gRPC

One implementation in api-core. Connect-Go transcoding means the REST surface is generated, not separately maintained.

Streamingserver-side events

ResolveLinkResponse streams click events for hot links — useful for internal dashboards without webhook plumbing.

What you get out of the box

  • REST + gRPC: pick the surface your service mesh prefers
  • OpenTelemetry spans on every redirect, every API call
  • Six SDKs: TypeScript, Go, Python, Ruby, PHP, .NET
  • Apache 2.0 self-host with a one-command Helm chart
  • Webhook firehose with HMAC-SHA256 signing
  • Prometheus /metrics endpoint on every service

What the Elido API actually ships

An OpenAPI spec and a Bearer token are table stakes. The features below are what separates a shortener you can build on from one you'll fight at 2 AM.

Predictable REST
01

OpenAPI 3.1 with 44 documented endpoints — no undocumented surface

Every endpoint in production is described in the OpenAPI 3.1 spec. No shadow routes, no undocumented params the docs team forgot. The spec is checked into the repo and versioned alongside the API; breaking changes follow SemVer and get a deprecation window of at least 90 days. The spec renders interactively with Scalar in the docs — paste your API key and try calls without leaving the browser. Three auto-generated SDKs (TypeScript, Python, Go) are generated from the same spec on every release, so they can't drift from what the server actually accepts. The SDK methods accept typed request objects and return typed response objects; errors are typed, not stringly-caught. Idempotency keys are supported on write endpoints — pass an `Idempotency-Key` header and the response is replayed on retry without a duplicate create.

Programmatic slug control
02

Deterministic slugs, bulk create, and idempotency for CI pipelines

POST /v1/workspaces/{ws}/links accepts a slug field — you get the slug you asked for, or a conflict error with the existing link's ID so your pipeline can decide what to do. Bulk create (POST .../links/bulk) accepts up to 100 link specs per call; the response includes one result per input row with either a created link or an error, so partial failures don't hide. Both endpoints accept idempotency keys: re-submit the same request with the same key and you get the same response, no duplicate rows. This is the pattern for CI/CD pipelines that mint short links on deploy — deterministic, safe to retry, consistent across environments. Slug namespacing is per-custom-domain: the same slug on two different domains is two different links, not a conflict.

Webhooks and firehose
03

HMAC-signed webhooks with automatic retry and a dead-letter queue

Every workspace event (link created, link clicked, link deleted, audit entry, conversion attributed) is available as a webhook. Payloads are signed with HMAC-SHA256 using a rotatable secret; the signing key is separate from your API key so rotating one doesn't invalidate the other. Delivery semantics: at-least-once, with exponential backoff (1s, 5s, 30s, 5m, 30m) and a configurable retry window (default 24h). Events that exhaust retries land in a dead-letter queue visible in the dashboard; you can replay from there. For high-volume event pipelines, the Kafka/Redpanda firehose bypasses HTTP delivery entirely — consume click events and audit logs directly from the stream. The firehose is a Business feature; webhook delivery is available on Pro and above.

MCP protocol
04

Model Context Protocol server: Elido tools in any MCP client

The open-source Elido MCP server (MIT license) exposes link, QR, and analytics endpoints as typed MCP tools. Install is 30 seconds: add the server block to your Claude Desktop or Cursor config, set ELIDO_API_KEY, restart. The tool catalogue is auto-discovered from the server — no hand-written tool definitions that drift. Read-only is the default scope; write operations require explicit grant in workspace settings. Every tool call appears in the workspace audit log with the calling key and arguments, so agent-driven mutations are traceable. The server speaks stdio and SSE; it passes through the same rate limits and error codes as the REST API, including Retry-After on 429 so your agent can back off cleanly. Source is on GitHub; common forks add workspace-specific tools or metadata enrichment without needing Elido to merge upstream.

Self-host
05

Helm chart (Apache 2.0): run the redirect tier in your own VPC

The redirect tier (edge-redirect service) is the only component on the hot path of every redirect. It's a single Go binary — no runtime dependencies beyond Redis for the L2 cache. The Helm chart ships with sane defaults for Kubernetes horizontal pod autoscaling; it scales on CPU and request rate. Configuration is environment variables; the chart includes a values.yaml with sane defaults and a documented list of every variable. The rest of the stack (api-core, dashboard) can remain on Elido-managed SaaS — you don't have to self-host everything. The common split is: redirect tier self-hosted in your VPC (lower latency to your users, no egress billing), dashboard and analytics on Elido's cloud. Bring your own KMS for at-rest encryption of the local Redis cache if your security posture requires it. Compared to Bitly (no self-host option) and building a custom shortener, the Helm chart option gives you the redirect performance and managed API surface without starting from scratch.

Stack you'll touch

  • TypeScript SDK
  • Python SDK
  • Go SDK
  • Webhook firehose
  • OpenAPI 3.1 spec
  • Self-host Helm chart

What you'll measure

p50 redirect latency
5 ms cache HIT
API uptime SLA
99.95% on Business
Self-host RTO
<1 hour

Engineering teams building on this

Names are placeholders for now — real customer names land here as case studies are published.

We self-host the redirect tier in our own Kubernetes cluster and use the managed API for everything else. p50 redirect latency dropped from 45ms to 6ms after moving the edge service into the same region as our users. The Helm chart was readable enough that we shipped without consulting support.

P
Platform engineering team, mid-market SaaS, Vilnius
Staff Engineer

The MCP server was the deciding factor. Our team works in Cursor all day; being able to create tagged short links for release notes from inside the IDE without leaving the workflow is the kind of DX win that actually sticks.

D
DevRel team, developer tools company, Berlin
Head of Developer Relations

Idempotency keys on bulk create let us mint short links in CI without paranoia about retries creating duplicates. The typed Go SDK means our pipeline code compiles or fails — no silent bad requests at runtime.

B
Backend platform team, fintech, Amsterdam
Senior Backend Engineer

Elido API vs Bitly API vs building your own shortener

Two external options and the build-it-yourself alternative. Honest about where Bitly's API is more mature and where a custom shortener wins on control.

CapabilityElidoBitly APICustom shortener
API spec formatOpenAPI 3.1, checked into repoCustom v4 docs (not OpenAPI)Whatever you write
First-party SDKsTypeScript, Python, Go — generated from specJavaScript, Python, Ruby, JavaYou build them
Idempotency keys on writesYes — header-based, all write endpointsNot documentedYou implement it
Bulk create100 per call, partial-failure per rowNo native bulk endpoint documentedYour schema, your rules
Webhook deliveryAt-least-once, HMAC-SHA256, DLQAvailable on EnterpriseYou build it
MCP serverMIT open-source, 30s installNot availableYou build it
Self-host redirect tierApache 2.0 Helm chartNot availableFull control, full cost
p50 redirect latency5 ms cache HITComparable (edge-served)Depends on your infra

Developer questions

Where is the OpenAPI spec?

At /docs/api-reference — Scalar renders it interactively. The raw YAML is at /openapi.yaml. It's the same spec the SDKs are generated from, not a separately maintained doc.

How do I get a deterministic slug in CI?

Pass `slug` in the request body. If the slug is already taken by a different link, the API returns 409 with the ID of the conflicting link. If it's taken by the same destination URL (idempotent re-create), it returns the existing link. Use the Idempotency-Key header to make retries safe.

What does the self-host Helm chart include?

The edge-redirect service (Go binary), Redis config, HPA settings, and a values.yaml with all config variables documented. It does not include api-core or the dashboard — those can stay on Elido's SaaS. Apache 2.0 license; no CLA required for forks.

How do I consume click events without polling?

Two options: webhooks (HTTPS, HMAC-signed, at-least-once) or the Kafka/Redpanda firehose (direct consumer, Business tier). Webhooks are fine for audit and alerting; the firehose is the right path for high-volume event pipelines where per-event HTTP delivery overhead matters.

What's the rate limit?

100 req/sec sustained, 200 burst per API key, with a 429 and Retry-After header. Write endpoints count separately from reads. The MCP server passes 429 through as a tool error; the SDKs expose the Retry-After value as a typed field in the rate-limit error.

Can I use the MCP server in production automation, not just interactively?

Yes — the MCP server is a standard stdio or SSE process. You can invoke it from a script, a CI step, or an agent pipeline. Read-only by default; write scope requires explicit workspace setting. Every call is audited.

What breaking-change policy do you use?

SemVer on the API version prefix (/v1/, /v2/). Breaking changes get a 90-day deprecation window with both versions live simultaneously. Non-breaking additions (new fields, new endpoints) happen without a version bump. The changelog at /changelog documents every change with the affected endpoint.

Is there a local dev mode without hitting the real API?

The TypeScript and Python SDKs accept a baseUrl override pointing at your own instance — useful for self-hosters. There's no official mock server yet; for local testing the pattern is a test workspace with a separate API key, not a mock. It's on the roadmap.

Not sure which angle fits?

Most teams start as one and grow into all four. Our sales team can walk through your specific stack in 20 minutes.

For developers — Plain REST. Three SDKs. A self-host Helm chart. · Elido