API Documentation

Complete reference for the LinkShort REST API. All endpoints, parameters, and examples.

Introduction

The LinkShort API lets you programmatically create and manage short links, track analytics, and receive real-time webhook notifications. All responses are JSON.

Base URL

Text
https://api.tooldit.com/api/v1

All requests must be made over HTTPS. HTTP requests will be rejected.

Authentication

The API supports two authentication methods. API Keys are recommended for server-to-server integrations.

Method 1 — API Key (Recommended)

Generate an API key from your dashboard and pass it in the Authorization header:

Bash
curl https://api.tooldit.com/api/v1/links \
  -H "Authorization: sk_your_api_key_here"

Method 2 — JWT Token

For dashboard integrations, use a JWT obtained from the login endpoint:

Bash
curl https://api.tooldit.com/api/v1/links \
  -H "Authorization: Bearer your_jwt_token"

Get your API key from your API Keys dashboard.

Rate Limits

Rate limits are applied per API key and reset every minute.

PlanRequests / minute
Free30
Pro200
Business1,000

Rate limit info is returned in response headers:

Text
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 25
X-RateLimit-Reset: 1234567890

When exceeded you will receive a 429 response:

JSON
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests"
  }
}

Error Handling

All errors follow a consistent format:

JSON
{
  "success": false,
  "data": null,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable message"
  },
  "timestamp": "2026-04-29T12:00:00Z"
}
Error CodeHTTPDescription
LINK_NOT_FOUND404Link does not exist
LINK_EXPIRED410Link has expired
SLUG_ALREADY_EXISTS409Custom slug is already taken
INVALID_URL400URL format is invalid
PLAN_LIMIT_EXCEEDED402Monthly link or click limit reached
API_KEY_INVALID401Invalid or revoked API key
RATE_LIMIT_EXCEEDED429Too many requests per minute
UNAUTHORIZED401Missing or invalid authentication

Link Expiry Format

The expiresIn field accepts duration strings:

ValueDescription
"30m"30 minutes
"1h"1 hour
"12h"12 hours
"1d"1 day
"7d"7 days
"30d"30 days
"3mo"3 months
"1y"1 year
"10y"10 years
"never"Never expires (Pro/Business only)

Free plan: maximum expiry is 7 days. Values exceeding this are clamped.

Bulk Create Links

POST/api/v1/links/bulk

Creates multiple links in a single request. Plan limits: Free — 10, Pro — 100, Business — 1,000.

Request body

JSON
{
  "links": [
    {
      "originalUrl": "https://example.com/1",
      "customSlug": "link-1"
    },
    {
      "originalUrl": "https://example.com/2"
    }
  ]
}

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "created": [
      {
        "shortCode": "link-1",
        "shortUrl": "https://go.tooldit.com/link-1",
        "originalUrl": "https://example.com/1"
      }
    ],
    "failed": [
      {
        "index": 2,
        "error": "Slug already exists"
      }
    ],
    "totalCreated": 9,
    "totalFailed": 1
  }
}

Bulk Action

POST/api/v1/links/bulk-action

Perform an action on multiple links at once.

Request body

ParameterTypeRequiredDescription
shortCodesstring[]RequiredArray of short codes to act on
actionstringRequiredAction: DELETE, DISABLE, ENABLE

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "processed": 5,
    "failed": 0
  }
}

Overview Analytics

GET/api/v1/analytics/overview

Returns aggregated analytics across all your links.

Query parameters

ParameterTypeRequiredDescription
rangestringDefault: 7dTime range: 7d, 30d, 90d, all

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "summary": {
      "totalClicks": 1240,
      "uniqueClicks": 980,
      "totalLinks": 45,
      "activeLinks": 38
    },
    "clicksOverTime": [
      { "date": "2026-04-22", "clicks": 180 },
      { "date": "2026-04-23", "clicks": 210 }
    ],
    "topLinks": [
      {
        "shortCode": "my-video",
        "shortUrl": "https://go.tooldit.com/my-video",
        "clicks": 320
      }
    ],
    "topCountries": [
      { "name": "United States", "clicks": 450 }
    ],
    "topCities": [
      { "name": "New York", "clicks": 120 }
    ],
    "topDevices": [
      { "name": "Mobile", "clicks": 680 }
    ],
    "topBrowsers": [
      { "name": "Chrome", "clicks": 590 }
    ],
    "topReferrers": [
      { "name": "twitter.com", "clicks": 230 }
    ]
  }
}

Generate Key

POST/api/v1/keys

Generates a new API key. The raw key value is only returned once.

Request body

ParameterTypeRequiredDescription
namestringRequiredA human-readable label for the key

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "name": "Production key",
    "key": "sk_live_abc123...",
    "createdAt": "2026-04-29T12:00:00Z"
  }
}

List Keys

GET/api/v1/keys

Returns all API keys for the authenticated user. Key values are masked.

Response — 200 OK

JSON
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Production key",
      "keyPreview": "sk_live_abc1...xyz9",
      "lastUsedAt": "2026-04-28T10:00:00Z",
      "createdAt": "2026-04-29T12:00:00Z"
    }
  ]
}

Delete Key

DELETE/api/v1/keys/{id}

Permanently revokes and deletes an API key. All requests using it will fail immediately.

Response — 200 OK

JSON
{
  "success": true,
  "data": null
}

Regenerate Key

PUT/api/v1/keys/{id}/regenerate

Issues a new secret value for an existing key. The old value is immediately invalidated. The new key is returned only once.

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "name": "Production key",
    "key": "sk_live_newvalue...",
    "createdAt": "2026-04-29T12:00:00Z"
  }
}

Add Domain

POST/api/v1/domains

Registers a custom domain for use with your short links.

Request body

ParameterTypeRequiredDescription
hostnamestringRequiredThe domain hostname (e.g. go.yourapp.com)

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "hostname": "go.yourapp.com",
    "isVerified": false,
    "verificationMethod": "DNS_TXT",
    "verificationToken": "linkshort-verify=abc123",
    "createdAt": "2026-04-29T12:00:00Z"
  }
}

List Domains

GET/api/v1/domains

Returns all custom domains for the authenticated user.

Response — 200 OK

JSON
{
  "success": true,
  "data": [
    {
      "id": 1,
      "hostname": "go.yourapp.com",
      "isVerified": true,
      "sslStatus": "ACTIVE",
      "createdAt": "2026-04-29T12:00:00Z"
    }
  ]
}

Delete Domain

DELETE/api/v1/domains/{id}

Removes a custom domain. Links using it will fall back to the default domain.

Response — 200 OK

JSON
{
  "success": true,
  "data": null
}

Verify Domain

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

Triggers a DNS verification check. Add the TXT record to your DNS before calling this endpoint.

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "hostname": "go.yourapp.com",
    "isVerified": true,
    "verifiedAt": "2026-04-29T12:30:00Z"
  }
}

Register Endpoint

POST/api/v1/webhooks

Registers a new webhook endpoint to receive event notifications.

Request body

ParameterTypeRequiredDescription
urlstringRequiredHTTPS URL that will receive events
descriptionstringOptionalHuman-readable label
eventsstring[]RequiredArray of event types to subscribe to
isActivebooleanDefault: trueEnable or disable the endpoint

Request example

JSON
{
  "url": "https://yourapp.com/webhooks/linkshort",
  "description": "Production webhook",
  "events": ["link.clicked", "link.created"],
  "isActive": true
}

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "url": "https://yourapp.com/webhooks/linkshort",
    "description": "Production webhook",
    "secret": "whsec_abc123...",
    "events": ["link.clicked", "link.created"],
    "isActive": true,
    "failureCount": 0,
    "createdAt": "2026-04-29T12:00:00Z"
  }
}
Store the secret securely — it is only returned at creation time and used to verify webhook signatures.

List Endpoints

GET/api/v1/webhooks

Returns all webhook endpoints for the authenticated user.

Response — 200 OK

JSON
{
  "success": true,
  "data": [
    {
      "id": 1,
      "url": "https://yourapp.com/webhooks/linkshort",
      "description": "Production webhook",
      "events": ["link.clicked", "link.created"],
      "isActive": true,
      "failureCount": 0,
      "createdAt": "2026-04-29T12:00:00Z"
    }
  ]
}

Update Endpoint

PUT/api/v1/webhooks/{id}

Updates an existing webhook endpoint configuration.

Request body

ParameterTypeRequiredDescription
urlstringOptionalNew destination URL
descriptionstringOptionalNew description
eventsstring[]OptionalUpdated list of subscribed events
isActivebooleanOptionalEnable or disable the endpoint

Response — 200 OK

JSON
{
  "success": true,
  "data": { ...updated endpoint object }
}

Delete Endpoint

DELETE/api/v1/webhooks/{id}

Permanently removes a webhook endpoint and stops all future deliveries.

Response — 200 OK

JSON
{
  "success": true,
  "data": null
}

Rotate Secret

POST/api/v1/webhooks/{id}/rotate-secret

Generates a new signing secret. Update your verification logic immediately — the old secret is invalidated.

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "secret": "whsec_newvalue123..."
  }
}

View Deliveries

GET/api/v1/webhooks/{id}/deliveries

Returns the delivery history for a webhook endpoint.

Query parameters

ParameterTypeRequiredDescription
pagenumberDefault: 0Page number
sizenumberDefault: 20Items per page
statusstringOptionalFilter: SUCCESS, FAILED, PENDING

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "content": [
      {
        "id": 1,
        "eventType": "link.clicked",
        "status": "SUCCESS",
        "httpStatus": 200,
        "attemptCount": 1,
        "createdAt": "2026-04-29T12:00:00Z",
        "deliveredAt": "2026-04-29T12:00:01Z"
      }
    ],
    "page": 0,
    "total": 45
  }
}

Retry Delivery

POST/api/v1/webhooks/{id}/deliveries/{deliveryId}/retry

Manually retries a failed or pending webhook delivery.

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "id": 1,
    "status": "SUCCESS",
    "httpStatus": 200,
    "attemptCount": 2
  }
}

Test Endpoint

POST/api/v1/webhooks/{id}/test

Sends a test event to verify your endpoint is reachable and your signature verification works.

Response — 200 OK

JSON
{
  "success": true,
  "data": {
    "httpStatus": 200,
    "responseTime": 124,
    "message": "Test delivery successful"
  }
}

plan.limit_reached

Fired when a usage limit (links or clicks) is 100% reached for the billing period.

JSON
{
  "id": "evt_01abc123def462",
  "event": "plan.limit_reached",
  "timestamp": "2026-04-29T12:00:00Z",
  "data": {
    "plan": "FREE",
    "limitType": "links",
    "limit": 100,
    "used": 100,
    "resetAt": "2026-05-01T00:00:00Z"
  }
}

plan.limit_warning

Fired when usage reaches 90% of a plan limit, giving time to upgrade or pause campaigns.

JSON
{
  "id": "evt_01abc123def463",
  "event": "plan.limit_warning",
  "timestamp": "2026-04-29T11:00:00Z",
  "data": {
    "plan": "FREE",
    "limitType": "clicks",
    "limit": 1000,
    "used": 900,
    "percentUsed": 90,
    "resetAt": "2026-05-01T00:00:00Z"
  }
}

Verifying Webhook Signatures

Every webhook request includes a signature header so you can confirm it originated from LinkShort:

Text
X-LinkShort-Signature: t=1234567890,v1=abc123def456...

Verification steps:

  1. Extract t (timestamp) and v1 (signature) from the header
  2. Build the signed string: timestamp + "." + raw_request_body
  3. Compute HMAC-SHA256 of the signed string using your webhook secret
  4. Compare with v1 using a constant-time comparison
const crypto = require('crypto')

function verifyWebhook(rawBody, header, secret) {
  const parts = header.split(',')
  const timestamp = parts[0].split('=')[1]
  const signature = parts[1].split('=')[1]

  const signed = timestamp + '.' + rawBody
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signed)
    .digest('hex')

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  )
}

Postman Collection

Download the official Postman collection to test every API endpoint instantly. All 33 endpoints are pre-configured with variable placeholders.

Download Postman Collection

Setup instructions

  1. Download the collection and import it into Postman
  2. Create a Postman environment with these variables:
    Text
    base_url = https://api.tooldit.com
    api_key  = sk_your_key_here
  3. Select your environment and run any request immediately

What's included

  • Links — 7 endpoints (create, list, get, update, delete, bulk create, bulk action)
  • Analytics — 3 endpoints (overview, link analytics, account stats)
  • API Keys — 5 endpoints (generate, list, delete, regenerate, usage)
  • Domains — 4 endpoints (add, list, delete, verify)
  • Webhooks — 9 endpoints (register, list, get, update, delete, rotate, deliveries, retry, test)
  • Auth — 5 endpoints (login, register, verify email, forgot password, reset password)

View the full API reference on this page .