Developers

Smart Link API

Create smart links that open the native app, manage them, and pull click analytics into your own tools. The API is a JSON REST API included with Pro.

Quickstart

  1. Open Dashboard → API and create a key. It is shown once, so store it somewhere safe.
  2. Send it as a Bearer token with every request.
curl https://smartlink.sh/api/v1/links \
  -H "Authorization: Bearer $SMARTLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"originalUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'

The response wraps the new link in a data object:

201 Created
{
  "data": {
    "id": "cm1x2y3z4000008l1abcd1234",
    "shortCode": "aB3dE9",
    "shortUrl": "https://smartlink.sh/l/aB3dE9",
    "originalUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "platform": "YOUTUBE",
    "title": "YouTube Video",
    "isActive": true,
    "isPasswordProtected": false,
    "expiresAt": null,
    "clickCount": 0,
    "source": "API",
    "createdAt": "2026-09-29T12:00:00.000Z",
    "updatedAt": "2026-09-29T12:00:00.000Z"
  }
}

Base URL

Base URL
https://smartlink.sh/api/v1

All requests use HTTPS. Request bodies are JSON with Content-Type: application/json. Dates are ISO 8601 strings in UTC.

Authentication

Every request needs an API key in the Authorization header:

Header
Authorization: Bearer sl_live_…

Keys belong to your account and can do everything you can do in the dashboard. You can have up to 5 active keys, and you can revoke any of them from the dashboard. Revoked keys stop working immediately.

The API is for server-to-server use. It doesn’t send CORS headers, so browsers block direct calls. Never put a key in website, browser extension, or mobile app code. Call the API from your backend, a serverless function, or an automation tool instead.

Keys only work while your Pro subscription is active. If it lapses, requests return 403 SUBSCRIPTION_REQUIRED. Your keys start working again when you renew.

Responses and errors

Successful responses return { "data": … }. List endpoints add pagination. Errors use the HTTP status code and a stable machine-readable code:

400 Bad Request
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "customCode: Short code may only contain letters, numbers, \"-\" and \"_\""
  }
}
Error codes
NameTypeDescription
UNAUTHORIZED401The Authorization header is missing, malformed, or the key was revoked.
SUBSCRIPTION_REQUIRED403The key’s account has no active Pro subscription. Keys start working again when the subscription is renewed.
VALIDATION_ERROR400A parameter or body field is invalid. The message names the field.
NOT_FOUND404No such link in your account. Links in other accounts also return 404.
CONFLICT409The custom short code is already taken.
RATE_LIMITED429Too many requests. Wait for the number of seconds in Retry-After.
INTERNAL500Something went wrong on our side. Retry with backoff and quote X-Request-Id to support.

Every response includes an X-Request-Id header. Include it when you contact support.

Rate limits

  • 60 requests per minute per API key. This limit covers REST and MCP requests together.
  • 1,000 new links per day per account, shared across all of your keys.

Every authenticated response includes these headers:

Rate limit headers
NameTypeDescription
X-RateLimit-LimitintegerRequests allowed in the current window.
X-RateLimit-RemainingintegerRequests left in the current window.
X-RateLimit-ResetintegerUnix time (seconds) when the window resets.
Retry-AfterintegerOn 429 only: seconds to wait before retrying.

Pagination

List endpoints take page (starting at 1) and limit (default 20, max 100). They return a pagination object with page, limit, total, and pages.

Versioning

The version is in the path (/api/v1). Within v1 we only make additive changes, such as new endpoints, optional parameters, and response fields. Your client should ignore fields it doesn’t recognize. Breaking changes will ship as /api/v2, with advance notice.

Reference