API Reference

Use the shorter.sh API to create short links and track clicks programmatically. Authenticate with an API key and start shortening URLs in seconds.

Base URL

https://shorter.sh/api/v1

All requests and responses use JSON. Include Content-Type: application/json in your request headers.


Authentication

API requests are authenticated using API keys. You can create and manage keys from your dashboard.

1

Sign in with Google or GitHub at /auth

2

Go to your dashboard and open the API Keys tab

3

Create a new key. Copy it immediately — it’s only shown once.

Your key looks like this:

sk_a1b2c3d4e5f6...  (sk_ prefix + 64 hex characters)

Include it in the Authorization header on every request:

Header
Authorization: Bearer sk_your_api_key_here
!

Keep your API key secret. Don’t commit it to source control or share it publicly. If compromised, revoke it from your dashboard and create a new one.


Quick Start

Shorten your first URL with a single curl command:

cURL
curl -X POST https://shorter.sh/api/v1/shorten \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk_your_api_key_here" \
  -d '{"url": "https://example.com/very/long/url"}'
Response · 201 Created
{
  "success": true,
  "shortCode": "xK9mP2",
  "shortUrl": "https://shorter.sh/xK9mP2",
  "originalUrl": "https://example.com/very/long/url"
}

Endpoints

POST /api/v1/shorten Create a short URL

Request Body

ParameterTypeDescription
url required string The URL to shorten. Must start with http:// or https://. Max 2048 characters.

Response Fields

FieldTypeDescription
success boolean Always true on success
shortCode string The generated 6-character code
shortUrl string Full shortened URL ready to share
originalUrl string The original URL you submitted

Example

JavaScript (fetch)
const response = await fetch("https://shorter.sh/api/v1/shorten", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer sk_your_api_key_here",
  },
  body: JSON.stringify({ url: "https://example.com" }),
});

const data = await response.json();
console.log(data.shortUrl); // https://shorter.sh/xK9mP2
Python (requests)
import requests

response = requests.post(
    "https://shorter.sh/api/v1/shorten",
    headers={"Authorization": "Bearer sk_your_api_key_here"},
    json={"url": "https://example.com"},
)

data = response.json()
print(data["shortUrl"])  # https://shorter.sh/xK9mP2
GET /api/v1/urls List your shortened URLs

Authentication

Requires API key. Returns URLs owned by the API key holder, sorted by newest first.

Query Parameters

ParameterTypeDefaultDescription
page number 1 Page number for pagination
limit number 50 Results per page (max 100)

Example

cURL
curl "https://shorter.sh/api/v1/urls?page=1&limit=10" \
  -H "Authorization: Bearer sk_your_api_key_here"
Response · 200 OK
{
  "success": true,
  "data": [
    {
      "id": 42,
      "short_code": "xK9mP2",
      "original_url": "https://example.com/very/long/url",
      "click_count": 127,
      "created_at": "2026-01-15T10:30:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 25,
    "totalPages": 3
  },
  "totalClicks": 1580
}

DELETE /api/v1/urls/:shortCode Delete a shortened URL

Authentication

Requires API key. You can only delete URLs you own. Deleted links return 410 Gone when visited.

URL Parameters

ParameterTypeDescription
shortCode required string The 6-character short code

Example

cURL
curl -X DELETE "https://shorter.sh/api/v1/urls/xK9mP2" \
  -H "Authorization: Bearer sk_your_api_key_here"
Response · 200 OK
{
  "success": true,
  "message": "URL deleted"
}

GET /api/v1/analytics/:shortCode Get full analytics for a short URL you own

Authentication

Requires API key. You can only access analytics for URLs you created.

URL Parameters

ParameterTypeDescription
shortCode required string The 6-character short code (e.g. xK9mP2)

Query Parameters

ParameterTypeDefaultDescription
start string|number 30 days ago Start of date range (ISO date or ms timestamp)
end string|number Now End of date range (ISO date or ms timestamp)
dimension string Optional breakdown: country, device_type, browser, os, referrer_domain, language
limit number 10 Max breakdown items (max 50)

Example

cURL
curl "https://shorter.sh/api/v1/analytics/xK9mP2?dimension=country" \
  -H "Authorization: Bearer sk_your_api_key_here"
Response · 200 OK
{
  "success": true,
  "summary": {
    "totalClicks": 1423,
    "uniqueVisitors": 892,
    "prevPeriodClicks": 1100,
    "prevPeriodUnique": 720,
    "topCountry": "US",
    "topReferrer": "google.com",
    "topDevice": "desktop",
    "topBrowser": "Chrome"
  },
  "timeseries": {
    "granularity": "daily",
    "data": [
      { "period": 1709164800000, "clicks": 45, "unique_visitors": 30 }
    ]
  },
  "breakdown": {
    "dimension": "country",
    "total": 1423,
    "data": [
      { "value": "US", "clicks": 580, "percentage": 40.8 }
    ]
  }
}
i

The breakdown field is only included when you pass the dimension query parameter. Auto-granularity adjusts based on the date range (hourly for <48h, daily for <90d, weekly for <1y, monthly otherwise).


GET /api/v1/analytics/overview Get aggregate analytics across all your URLs

Authentication

Requires API key. Returns analytics aggregated across all URLs owned by the API key holder.

Query Parameters

ParameterTypeDefaultDescription
start string|number 30 days ago Start of date range (ISO date or ms timestamp)
end string|number Now End of date range (ISO date or ms timestamp)

Example

cURL
curl "https://shorter.sh/api/v1/analytics/overview?start=2025-01-01" \
  -H "Authorization: Bearer sk_your_api_key_here"
Response · 200 OK
{
  "success": true,
  "totalClicks": 5420,
  "uniqueVisitors": 3100,
  "prevPeriodClicks": 4800,
  "prevPeriodUnique": 2700,
  "timeseries": { "granularity": "daily", "data": [...] },
  "topUrls": [
    { "short_code": "xK9mP2", "original_url": "...", "clicks": 580 }
  ],
  "countryBreakdown": [
    { "value": "US", "clicks": 2100, "percentage": 38.7 }
  ],
  "deviceBreakdown": [
    { "value": "desktop", "clicks": 3200, "percentage": 59.0 }
  ]
}

Rate Limits

API key requests have the following default limits. These can be adjusted by the admin.

EndpointLimitWindow
POST /api/v1/shorten 30 requests Per minute
POST /api/v1/shorten 500 requests Per day
/api/v1/urls* 60 requests Per minute
/api/v1/urls* 300 requests Per hour
/api/v1/analytics/* 60 requests Per minute
/api/v1/analytics/* 300 requests Per hour

When you hit a rate limit, you’ll get a 429 response with a RATE_LIMITED code and a message telling you how many seconds to wait.

429 Too Many Requests
{
  "success": false,
  "message": "Rate limit exceeded. Try again in 42 seconds.",
  "code": "RATE_LIMITED"
}

Error Codes

All errors return a JSON object with success: false, a human-readable message, and a machine-readable code.

Error response format
{
  "success": false,
  "message": "Description of what went wrong",
  "code": "ERROR_CODE"
}
CodeHTTPDescription
INVALID_API_KEY 401 API key is missing, malformed, or not found
ACCOUNT_SUSPENDED 403 Your account has been suspended
URL_REQUIRED 400 No URL was provided in the request body
INVALID_URL 400 URL format is invalid (must be http:// or https://)
URL_UNSAFE 400 URL was flagged as potentially malicious
RATE_LIMITED 429 Too many requests — wait and retry
AUTH_REQUIRED 401 Analytics endpoint requires API key authentication
FORBIDDEN 403 You don’t own this URL
INVALID_ID 400 URL ID is missing or not a valid number
NOT_FOUND 404 URL or resource not found (or not owned by you)
CREATION_FAILED 500 Server error while creating the short URL
STATS_FAILED 500 Server error while fetching stats