API and integrations

A small REST API with personal keys. It's the same one the Mac and iPhone apps use.

Keys

Create a key under Apps & API and send it with every request:

Authorization: Bearer shr_your_key

Every endpoint lives under https://shared.do/api/v1 and answers in JSON. Apps can also exchange an email and password for a key of their own:

POST/api/v1/auth/login
{"email": "[email protected]", "password": "…", "device": "Jason's MacBook", "code": "123456"}
→ {"key": "shr_…", "user": {"plan": {…}, "features": {…}, "limits": {…}, "domains": […]}}

Leave out code unless the account uses two-factor sign-in; you'll get totp_required if it's needed. GET /api/v1/me returns the same user object.

Quick shorten

GET/api/v1/shorten?url=…&format=text
curl -H "Authorization: Bearer $KEY" "https://shared.do/api/v1/shorten?format=text&url=https://example.com"
https://shared.do/k7pm2q
POST/api/v1/links
{
  "url": "https://example.com/spring",
  "slug": "spring",                       // optional
  "domain": "go.yourbrand.com",           // optional: host or id
  "title": "Spring sale", "tags": ["campaign"], "notes": "…",
  "utm": {"source": "instagram", "medium": "social", "campaign": "spring"},
  "og_title": "…", "og_description": "…", "og_image": "https://…",
  "ios_url": "https://apps.apple.com/…", "android_url": "https://play.google.com/…",
  "geo": [{"country": "DE", "url": "https://example.de"}],
  "password": "…", "expires_at": "2026-12-31T23:59:00Z", "max_clicks": 1000, "expired_url": "https://…"
}

Answers 201 with the link: id, short_url, clicks, qr_svg and every field above.

GET/api/v1/links?q=&tag=&sort=new|clicks|recent|old&page=1&per_page=50
GET/api/v1/links/{id}
PATCH/api/v1/links/{id}

Send only what changes. archived and disabled are true/false.

DELETE/api/v1/links/{id}
GET/api/v1/tags
GET/api/v1/meta?url=…

Reads a page's title, description and preview image.

Stats

GET/api/v1/links/{id}/stats?days=7|30|90|365
GET/api/v1/stats?days=30
{"total": 1204, "unique": 911, "previous": 830, "qr": 140,
 "series": [{"day": "2026-10-01", "clicks": 40, "unique": 31}, …],
 "countries": [{"key": "US", "label": "United States", "clicks": 602}, …],
 "cities": […], "devices": […], "os": […], "browsers": […], "referrers": […], "sources": […]}

QR codes

GET/api/v1/links/{id}/qr.svg?fg=1d1c1a&bg=ffffff
GET/api/v1/links/{id}/qr.png?s=16

Domains

GET/api/v1/domains
POST/api/v1/domains
POST/api/v1/domains/{id}/verify
DELETE/api/v1/domains/{id}

Errors and limits

{"error": {"code": "upgrade_required", "message": "Branded domains is part of the Pro plan."}}

unauthorized 401, upgrade_required 402, not_found 404, conflict 409 (back-half taken), invalid 422, rate_limited 429. Each key can make 120 requests a minute.

Zapier, Make and n8n

Add a Webhooks by Zapier step (Make: HTTP, n8n: HTTP Request): POST https://shared.do/api/v1/links, header Authorization: Bearer shr_…, JSON body with url. Use short_url from the response in the next step.

Shortcuts, Raycast and Alfred

Anything that can open a URL works. In Apple Shortcuts: Get Contents of URL with https://shared.do/api/v1/shorten?format=text&url= plus the input and an Authorization header, then Copy to Clipboard.