Build anything
on top of your links
A predictable REST API over links, QR codes, analytics and bio pages. Standard verbs, JSON everywhere, and error codes that mean what they say.
API access is included on Pro and Business.
# POST /api/v1/workspaces/{workspace}/links — shorten a URL curl -X POST {{APP_URL}}/api/v1/workspaces/1/links \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{ "original_url": "https://example.com/very/long/url", "custom_alias": "my-campaign", "expires_at": "2026-12-31 23:59:59", "tags": ["marketing", "q4"] }' # 201 Created { "data": { "id": 4821, "short_url": "{{APP_URL}}/my-campaign", "clicks": 0, "created_at": "2026-04-20T10:32:00Z" } }
const res = await fetch(`{{APP_URL}}/api/v1/workspaces/${workspaceId}/links`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.SHORTLINK_API_TOKEN}`, 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ original_url: 'https://example.com/very/long/url', custom_alias: 'my-campaign', expires_at: '2026-12-31 23:59:59', tags: ['marketing', 'q4'], }), }) const { data } = await res.json() console.log(data.short_url) // {{APP_URL}}/my-campaign
import os, requests res = requests.post( f"{{APP_URL}}/api/v1/workspaces/{workspace_id}/links", headers={ "Authorization": f"Bearer {os.environ['SHORTLINK_API_TOKEN']}", "Accept": "application/json", }, json={ "original_url": "https://example.com/very/long/url", "custom_alias": "my-campaign", "expires_at": "2026-12-31 23:59:59", "tags": ["marketing", "q4"], }, ) print(res.json()["data"]["short_url"]) # {{APP_URL}}/my-campaign
use Illuminate\Support\Facades\Http; $response = Http::withToken(env('SHORTLINK_API_TOKEN')) ->acceptJson() ->post("{{APP_URL}}/api/v1/workspaces/{$workspaceId}/links", [ 'original_url' => 'https://example.com/very/long/url', 'custom_alias' => 'my-campaign', 'expires_at' => '2026-12-31 23:59:59', 'tags' => ['marketing', 'q4'], ]); echo $response->json('data.short_url'); // {{APP_URL}}/my-campaign
Everything you need in an API
Consistent JSON responses, standard HTTP verbs, and errors that tell you what to fix.
-
RESTful design
GET, POST, PATCH and DELETE against resource-oriented URLs, with JSON in and JSON out. Nothing to learn beyond HTTP.
-
Scoped API tokens
Named tokens with read, write or admin scope. Revoke one without disturbing the others, and see when each was last used.
-
Rate limiting
Limits by plan, with X-RateLimit headers on every response so you can back off before you are told to.
-
Signed webhooks
HTTP POST on clicks, expiry and limit events, each payload signed with HMAC-SHA256 so you can verify it came from us.
-
Full resource coverage
Links, QR codes, bio pages, tags, domains, workspaces and analytics — if the dashboard can do it, the API can too.
-
OpenAPI 3.1 spec
Import into Postman or Insomnia, or generate a typed client in TypeScript, Python, Go or anything else that reads the spec.
Core endpoints
Paths below are relative to /api/v1 and authenticated with a bearer token. Resources are scoped to a workspace, so {ws} is the id you get back from the first call in the list.
-
GET
/workspaces -
POST
/workspaces/{ws}/links -
GET
/workspaces/{ws}/links -
GET
/workspaces/{ws}/links/{id} -
PUT
/workspaces/{ws}/links/{id} -
DELETE
/workspaces/{ws}/links/{id} -
POST
/workspaces/{ws}/links/bulk -
GET
/workspaces/{ws}/analytics/overview -
GET
/workspaces/{ws}/analytics/links/{id} -
GET
/workspaces/{ws}/analytics/export -
POST
/workspaces/{ws}/qr
Rate limits by plan
Every response carries its own limit headers, so you never have to guess where you stand or discover it from a 429.
| Plan | Requests / min | Requests / day | Webhooks |
|---|---|---|---|
| Free | — | — | Not included |
| Pro | 1,000 | 100,000 | 5 |
| Business | 10,000 | Unlimited | Unlimited |
Questions about the API
Anything not covered here? Ask us directly.
How do I authenticate?
A bearer token in the Authorization header on every request. Tokens are created in the dashboard, scoped to read, write or admin, and can be revoked individually.
Which plans include API access?
Pro and Business. The free plan can create links in the dashboard but not through the API — the redirect endpoints themselves are open to everyone regardless of plan.
What happens when I hit a rate limit?
You get a 429 with a Retry-After header. Because every earlier response also carried X-RateLimit-Remaining, a well-behaved client can slow down before reaching that point.
Can I generate QR codes through the API?
Yes. POST to /api/v1/workspaces/{ws}/qr with a link id and the styling you want, then download the result as PNG, SVG or PDF from the download endpoint.
How do webhooks work?
You register a URL and we POST to it on clicks, expiry and limit events. Each payload is signed with HMAC-SHA256 using your webhook secret, so you can reject anything that does not verify.
Can I use it for marketing automation?
That is the common case. Create a tracked link per recipient or per campaign at send time, then read the analytics endpoint to attribute the response — no manual tagging in between.
How do I integrate it with a CRM?
Create the link when the record is created and store the returned id on the record. Polling the analytics endpoint for those ids, or receiving a webhook on click, then keeps engagement data next to the contact.
Is the analytics data real time?
Clicks are queued at redirect time and processed within about a second, so the API returns what the dashboard shows. It is not a nightly export.
Start building today
Create a token from the dashboard and make your first request. API access is included on Pro and Business.