API Reference · v1

Build with the LinkShort API.

Programmatically create short links, track clicks, manage custom domains, and receive real-time webhook events. Every endpoint, parameter, and response — documented.

Base URLhttps://api.tooldit.com/api/v1

33 endpoints

REST · JSON

8 webhook events

HMAC-signed

Global CDN

< 50ms latency

Bulk operations

1,000 per request

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 .